diff --git a/.github/workflows/BuildAndTestMain.yml b/.github/workflows/BuildAndTestMain.yml deleted file mode 100644 index 509c2ed..0000000 --- a/.github/workflows/BuildAndTestMain.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: .NET Core - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 3.1.301 - - name: Install dependencies - run: dotnet restore - - name: Build - run: dotnet build --configuration Release --no-restore - - name: Test - run: dotnet test --no-restore --verbosity normal diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj index 86bbe3a..35b215e 100644 --- a/src/Application/Application.csproj +++ b/src/Application/Application.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 CodeClinic.Application CodeClinic.Application @@ -12,7 +12,7 @@ - + diff --git a/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommand.cs b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommand.cs new file mode 100644 index 0000000..2dd2bcd --- /dev/null +++ b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommand.cs @@ -0,0 +1,15 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Categories.Commands.CreateCategory +{ + public class CreateCategoryCommand : IRequest + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + + } +} diff --git a/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandHandler.cs b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandHandler.cs new file mode 100644 index 0000000..239a734 --- /dev/null +++ b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandHandler.cs @@ -0,0 +1,33 @@ +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Commands.CreateCategory +{ + public class CreateCategoryCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public CreateCategoryCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(CreateCategoryCommand request, CancellationToken cancellationToken) + { + var category = new Category + { + Name = request.Name, + Description = request.Description, + + }; + + _context.Categories.Add(category); + + await _context.SaveChangesAsync(cancellationToken); + + return category.Id; + } + } +} diff --git a/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandValidator.cs b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandValidator.cs new file mode 100644 index 0000000..5fbb00c --- /dev/null +++ b/src/Application/Categories/Commands/CreateCategory/CreateCategoryCommandValidator.cs @@ -0,0 +1,35 @@ +using CodeClinic.Application.Common.Interfaces; +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Commands.CreateCategory +{ + public class CreateCategoryCommandValidator : AbstractValidator + { + private readonly IApplicationDbContext _context; + + public CreateCategoryCommandValidator(IApplicationDbContext context) + { + RuleFor(n => n.Name) + .MaximumLength(50) + .WithMessage("Name should not be greater than 50 characters") + .NotNull().NotEmpty().WithMessage("Name is required") + .MustAsync(BeUnique).WithMessage("Category must be Unique"); + + RuleFor(d => d.Description) + .MaximumLength(500).WithMessage("Description should be short") ; + _context = context; + } + + public async Task BeUnique(CreateCategoryCommand request,string name,CancellationToken cancellationToken) + { + return await _context + .Categories + .Where(n => n.Id != request.Id) + .AllAsync(n => n.Name != request.Name); + } + } +} diff --git a/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommand.cs b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommand.cs new file mode 100644 index 0000000..221eaac --- /dev/null +++ b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommand.cs @@ -0,0 +1,13 @@ +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Text; + +namespace CodeClinic.Application.Categories.Commands.DeleteCategory +{ + public class DeleteCategoryCommand :IRequest + { + public int Id { get; set; } + } +} diff --git a/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandHandler.cs b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandHandler.cs new file mode 100644 index 0000000..d45a9e5 --- /dev/null +++ b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandHandler.cs @@ -0,0 +1,35 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Commands.DeleteCategory +{ + public class DeleteCategoryCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public DeleteCategoryCommandHandler(IApplicationDbContext context) + { + _context = context; + + } + + public async Task Handle(DeleteCategoryCommand request, CancellationToken cancellationToken) + { + + var entity = await _context.Categories.FindAsync(request.Id); + + if (entity == null) throw new NotFoundException(nameof(Category), request.Id); + + _context.Categories.Remove(entity); + + await _context.SaveChangesAsync(cancellationToken); + + return Unit.Value; + } + } +} diff --git a/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandValidator.cs b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandValidator.cs new file mode 100644 index 0000000..3a67751 --- /dev/null +++ b/src/Application/Categories/Commands/DeleteCategory/DeleteCategoryCommandValidator.cs @@ -0,0 +1,16 @@ +using FluentValidation; + +namespace CodeClinic.Application.Categories.Commands.DeleteCategory +{ + public class DeleteCategoryCommandValidator : AbstractValidator + { + public DeleteCategoryCommandValidator() + { + + + RuleFor(c => c.Id).NotNull() + .NotEmpty().WithMessage("Id Cannot be null"); + } + + } +} diff --git a/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommand.cs b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommand.cs new file mode 100644 index 0000000..41256c9 --- /dev/null +++ b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommand.cs @@ -0,0 +1,14 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Categories.Commands.UpdateCategory +{ + public class UpdateCategoryCommand : IRequest + { + public int Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + } +} diff --git a/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandHandler.cs b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandHandler.cs new file mode 100644 index 0000000..7cc9389 --- /dev/null +++ b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandHandler.cs @@ -0,0 +1,35 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Commands.UpdateCategory +{ + public partial class UpdateCategoryCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public UpdateCategoryCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(UpdateCategoryCommand request, CancellationToken cancellationToken) + { + var categoryUpdate = await _context.Categories.FindAsync(request.Id); + if (categoryUpdate == null) + throw new NotFoundException(nameof(Category), request.Id); + + + categoryUpdate.Name = request.Name; + categoryUpdate.Description = request.Description; + + _context.Categories.Update(categoryUpdate); + + await _context.SaveChangesAsync(cancellationToken); + + return Unit.Value; + } + } +} diff --git a/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandValidator.cs b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandValidator.cs new file mode 100644 index 0000000..b3d3a56 --- /dev/null +++ b/src/Application/Categories/Commands/UpdateCategory/UpdateCategoryCommandValidator.cs @@ -0,0 +1,35 @@ +using CodeClinic.Application.Common.Interfaces; +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Commands.UpdateCategory +{ + + public partial class UpdateCategoryCommandHandler + { + public class UpdateCategoryCommandValidator : AbstractValidator + { + private readonly IApplicationDbContext _context; + + public UpdateCategoryCommandValidator(IApplicationDbContext context) + { + RuleFor(n => n.Name) + .MaximumLength(50) + .WithMessage("Name should not be greater than 50 characters") + .NotNull().NotEmpty().WithMessage("Name is required") + .MustAsync(BeUniqueName).WithMessage("Category must be Unique"); + + _context = context; + } + public async Task BeUniqueName(UpdateCategoryCommand model, string name, CancellationToken cancellationToken) + { + return await _context.Categories + .Where(l => l.Id != model.Id) + .AllAsync(l => l.Name != name); + } + } + } +} diff --git a/src/Application/Categories/Queries/GetCategoryDetail/CategoryDetailVm.cs b/src/Application/Categories/Queries/GetCategoryDetail/CategoryDetailVm.cs new file mode 100644 index 0000000..fe0fe45 --- /dev/null +++ b/src/Application/Categories/Queries/GetCategoryDetail/CategoryDetailVm.cs @@ -0,0 +1,34 @@ +using AutoMapper; +using CodeClinic.Application.Categories.Queries.GetCategoryList; +using CodeClinic.Application.Common.Mappings; +using CodeClinic.Application.Issues.Queries.GetIssueList; +using CodeClinic.Domain.Entities; +using System; +using System.Collections.Generic; + +namespace CodeClinic.Application.Categories.Queries.GetCategory +{ + public class CategoryDetailVm : IMapFrom + { + public int CategoryId { get; set; } + public string CategoryName { get; set; } + public string CategoryDescription { get; set; } + + public DateTime DateCreated { get; set; } + + public string LastModifiedBy { get; set; } + + public DateTime? LastModified { get; set; } + public IList IssuesTickets { get; set; } = new List(); + + + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(d => d.CategoryId, opt => opt.MapFrom(s => s.Id)) + .ForMember(c=> c.CategoryName , cd=> cd.MapFrom(c=> c.Name)) + .ForMember(c=> c.CategoryDescription,op=> op.MapFrom(d=> d.Description)); + } + } +} \ No newline at end of file diff --git a/src/Application/Categories/Queries/GetCategoryDetail/GetCategoryDetailQuery.cs b/src/Application/Categories/Queries/GetCategoryDetail/GetCategoryDetailQuery.cs new file mode 100644 index 0000000..d5fa55f --- /dev/null +++ b/src/Application/Categories/Queries/GetCategoryDetail/GetCategoryDetailQuery.cs @@ -0,0 +1,50 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Issues.Queries.GetIssueList; +using CodeClinic.Domain.Entities; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Queries.GetCategory +{ + public class GetCategoryDetailQuery:IRequest + { + public int Id { get; set; } + } + + public class GetCategoryDetailQueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetCategoryDetailQueryHandler(IApplicationDbContext context,IMapper mapper) + { + _context = context; + _mapper = mapper; + } + public async Task Handle(GetCategoryDetailQuery request, CancellationToken cancellationToken) + { + var viewModel = await _context.Categories + .ProjectTo(_mapper.ConfigurationProvider) + .FirstOrDefaultAsync(p => p.CategoryId == request.Id, cancellationToken); + + if (viewModel == null) throw new NotFoundException(nameof(Category), request.Id); + + var issueTicketList = await _context.IssueTickets.ProjectTo(_mapper.ConfigurationProvider) + .Where(c => c.CategoryId == request.Id).ToListAsync(); + + + viewModel.IssuesTickets = issueTicketList; + return viewModel; + } + } + +} diff --git a/src/Application/Categories/Queries/GetCategoryList/CategoryDto.cs b/src/Application/Categories/Queries/GetCategoryList/CategoryDto.cs new file mode 100644 index 0000000..6d5409e --- /dev/null +++ b/src/Application/Categories/Queries/GetCategoryList/CategoryDto.cs @@ -0,0 +1,21 @@ +using AutoMapper; +using CodeClinic.Application.Common.Mappings; +using CodeClinic.Application.Issues.Queries.GetIssueList; +using CodeClinic.Domain.Entities; +using System.Collections.Generic; + +namespace CodeClinic.Application.Categories.Queries.GetCategoryList +{ + public class CategoryDto : IMapFrom + { + public int CategoryId { get; set; } + public string Name { get; set; } + public string Description { get; set; } + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(i => i.CategoryId, op => op.MapFrom(s => s.Id)); + } + } +} \ No newline at end of file diff --git a/src/Application/Categories/Queries/GetCategoryList/CategoryListVm.cs b/src/Application/Categories/Queries/GetCategoryList/CategoryListVm.cs new file mode 100644 index 0000000..6731191 --- /dev/null +++ b/src/Application/Categories/Queries/GetCategoryList/CategoryListVm.cs @@ -0,0 +1,10 @@ +using CodeClinic.Domain.Entities; +using System.Collections.Generic; + +namespace CodeClinic.Application.Categories.Queries.GetCategoryList +{ + public class CategoryListVm + { + public List Categories { get; internal set; } + } +} \ No newline at end of file diff --git a/src/Application/Categories/Queries/GetCategoryList/GetCategoryListQuery.cs b/src/Application/Categories/Queries/GetCategoryList/GetCategoryListQuery.cs new file mode 100644 index 0000000..6fe4804 --- /dev/null +++ b/src/Application/Categories/Queries/GetCategoryList/GetCategoryListQuery.cs @@ -0,0 +1,45 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CodeClinic.Application.Common.Interfaces; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Categories.Queries.GetCategoryList +{ + public class GetCategoryListQuery : IRequest + { + } + + public class GetCategoryListQueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetCategoryListQueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(GetCategoryListQuery request, CancellationToken cancellationToken) + { + var categories = await _context.Categories + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); + + + var viewModel = new CategoryListVm + { + Categories = categories + }; + + return viewModel; + } + } +} diff --git a/src/Application/Comments/Commands/CommentCommandBaseHandler.cs b/src/Application/Comments/Commands/CommentCommandBaseHandler.cs new file mode 100644 index 0000000..e2b7a26 --- /dev/null +++ b/src/Application/Comments/Commands/CommentCommandBaseHandler.cs @@ -0,0 +1,21 @@ +using CodeClinic.Application.Common.Interfaces; +using FluentValidation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Comments.Commands +{ + public class CommentCommandBaseHandler + { + protected readonly IApplicationDbContext _context; + + public CommentCommandBaseHandler(IApplicationDbContext context) + { + _context = context; + } + + + } + +} diff --git a/src/Application/Comments/Commands/CreateComment/CommentCreatedEvent.cs b/src/Application/Comments/Commands/CreateComment/CommentCreatedEvent.cs new file mode 100644 index 0000000..a002f4a --- /dev/null +++ b/src/Application/Comments/Commands/CreateComment/CommentCreatedEvent.cs @@ -0,0 +1,26 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Commands.CreateComment +{ + public class CommentCreatedEvent : INotification + { + public int Id { get; set; } + + public class CommentCreatedEventHandler : INotificationHandler + { + public Task Handle(CommentCreatedEvent notification, CancellationToken cancellationToken) + { + //DO something + + throw new NotImplementedException(); + } + } + } + +} diff --git a/src/Application/Comments/Commands/CreateComment/CreateCommentCommand.cs b/src/Application/Comments/Commands/CreateComment/CreateCommentCommand.cs new file mode 100644 index 0000000..7c46140 --- /dev/null +++ b/src/Application/Comments/Commands/CreateComment/CreateCommentCommand.cs @@ -0,0 +1,49 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Commands.CreateComment +{ + public class CreateCommentCommand : IRequest + { + public int IssueTicketId { get; set; } + public string Title { get; set; } + public string Description { get; set; } + + } + + + public class CreateCommentCommandHandler : CommentCommandBaseHandler, IRequestHandler + { + public CreateCommentCommandHandler(IApplicationDbContext context) : base(context) { } + + public async Task Handle(CreateCommentCommand request, CancellationToken cancellationToken) + { + var issueTicket = await _context.IssueTickets.FindAsync(request.IssueTicketId); + + if (issueTicket == null) + throw + new PostException(nameof(Comment), + new NotFoundException($"The Depend Entity '{nameof(IssueTicket)}'" + + $" with Id {request.IssueTicketId} was not found")); + + var entity = new Comment + { + IssueTicketId = request.IssueTicketId, + Title = request.Title, + Description = request.Description + }; + + _context.Comments.Add(entity); + + await _context.SaveChangesAsync(cancellationToken); + return entity.Id; + } + } +} diff --git a/src/Application/Comments/Commands/CreateComment/CreateCommentCommandValidator.cs b/src/Application/Comments/Commands/CreateComment/CreateCommentCommandValidator.cs new file mode 100644 index 0000000..1a918d5 --- /dev/null +++ b/src/Application/Comments/Commands/CreateComment/CreateCommentCommandValidator.cs @@ -0,0 +1,23 @@ +using CodeClinic.Application.Common.Models; +using FluentValidation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Comments.Commands.CreateComment +{ + class CreateCommentCommandValidator: AbstractValidator + { + public CreateCommentCommandValidator() + { + RuleFor(t => t.IssueTicketId) + .NotEmpty().NotNull() + .WithErrorCode( ErrorCode.BadRequest) + .WithMessage("Issue Ticket Id is Required"); + + RuleFor(t => t.Title) + .NotEmpty().WithErrorCode(ErrorCode.BadRequest) + .WithMessage("The title is required"); + } + } +} diff --git a/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommand.cs b/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommand.cs new file mode 100644 index 0000000..6d07f05 --- /dev/null +++ b/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommand.cs @@ -0,0 +1,38 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Commands.DeleteComment +{ + public class DeleteCommentCommand : IRequest + { + public int IssueTicketId { get; set; } + + public int Id { get; set; } + } + + public class DeleteCommentCommandHandler : CommentCommandBaseHandler, IRequestHandler + { + public DeleteCommentCommandHandler(IApplicationDbContext context) : base(context) { } + + + public async Task Handle(DeleteCommentCommand request, CancellationToken cancellationToken) + { + var entity = await _context.Comments.FindAsync(request.Id); + + if (entity == null) throw new NotFoundException(nameof(Comment), request.Id); + + _context.Comments.Remove(entity); + + await _context.SaveChangesAsync(cancellationToken); + + return Unit.Value; + } + } +} diff --git a/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommandValidator.cs b/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommandValidator.cs new file mode 100644 index 0000000..60ed3da --- /dev/null +++ b/src/Application/Comments/Commands/DeleteComment/DeleteCommentCommandValidator.cs @@ -0,0 +1,37 @@ +using CodeClinic.Application.Common.Interfaces; +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Commands.DeleteComment +{ + class DeleteCommentCommandValidator :AbstractValidator + { + private readonly IApplicationDbContext _context; + + public DeleteCommentCommandValidator(IApplicationDbContext context) + { + _context = context; + } + public DeleteCommentCommandValidator() + { + RuleFor(i => i.Id) + .NotEmpty().NotNull().WithMessage("Comment Id is Required!"); + + RuleFor(i => i.IssueTicketId).NotEmpty() + .MustAsync(MustBeInTheIssueTicket) + .WithMessage("Ticket does not contain Comment with given Id!"); + } + + public async Task MustBeInTheIssueTicket(DeleteCommentCommand request, int issueTickeId, CancellationToken cancellationToken) + { + var ticket = await _context.IssueTickets.FirstOrDefaultAsync(i => i.Id == request.IssueTicketId && i.Comments.FirstOrDefault(r => r.IssueTicketId == issueTickeId ) != null); + return ticket != null; + } + } +} diff --git a/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommand.cs b/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommand.cs new file mode 100644 index 0000000..0a6f855 --- /dev/null +++ b/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommand.cs @@ -0,0 +1,37 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Commands.UpdateComment +{ + public class UpdateCommentCommand : IRequest + { + public int IssueTicketId { get; set; } + public int CommentId { get; set; } + public string Title { get; set; } + public string Description { get; set; } + } + public class UpdateCommentCommandHandler : CommentCommandBaseHandler, IRequestHandler + { + public UpdateCommentCommandHandler(IApplicationDbContext context) : base(context) { } + + public async Task Handle(UpdateCommentCommand request, CancellationToken cancellationToken) + { + Comment entity = await _context.Comments.FindAsync(request.CommentId, cancellationToken); + + if (entity == null) throw new NotFoundException(nameof(Comment), request.CommentId); + + entity.Title = request.Title; + entity.Description = request.Description; + + _context.Comments.Update(entity); + await _context.SaveChangesAsync(cancellationToken); + + return Unit.Value; + } + + } +} diff --git a/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommandValidator.cs b/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommandValidator.cs new file mode 100644 index 0000000..a5bdb18 --- /dev/null +++ b/src/Application/Comments/Commands/UpdateComment/UpdateCommentCommandValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Comments.Commands.UpdateComment +{ + class UpdateCommentCommandValidator : AbstractValidator + { + public UpdateCommentCommandValidator() + { + RuleFor(i => i.CommentId).NotEmpty() + .NotNull(); + + RuleFor(t => t.IssueTicketId) + .NotEmpty() + .NotNull() + .WithErrorCode("400").WithMessage("Issue Ticket Id is Required"); + + RuleFor(t => t.Title) + .NotEmpty() + .WithMessage("The title is required"); + } + } +} diff --git a/src/Application/Comments/Query/GetCommentDetails/GetCommentDetailsQuery.cs b/src/Application/Comments/Query/GetCommentDetails/GetCommentDetailsQuery.cs new file mode 100644 index 0000000..2fe49c1 --- /dev/null +++ b/src/Application/Comments/Query/GetCommentDetails/GetCommentDetailsQuery.cs @@ -0,0 +1,46 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Comments.Query.GetCommentList; +using CodeClinic.Domain.Entities; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Query.GetCommentDetails +{ + public class GetCommentDetailsQuery : IRequest + { + public int IssueTicketId { get; set; } + public int CommentId { get; set; } + } + + public class GetCommentDetailsQueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetCommentDetailsQueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + public async Task Handle(GetCommentDetailsQuery request, CancellationToken cancellationToken) + { + var diagnosis = await _context.Comments + .ProjectTo(_mapper.ConfigurationProvider) + .SingleOrDefaultAsync(i => i.CommentId == request.CommentId, cancellationToken); + + if (diagnosis == null) throw new NotFoundException(nameof(Comment), request.CommentId); + if (diagnosis.IssueTicketId != request.IssueTicketId) + throw new NotFoundException($"Comment of id {request.CommentId} in Ticket {request.IssueTicketId} was not found"); + + return diagnosis; + } + } +} diff --git a/src/Application/Comments/Query/GetCommentList/CommentDto.cs b/src/Application/Comments/Query/GetCommentList/CommentDto.cs new file mode 100644 index 0000000..0099c8d --- /dev/null +++ b/src/Application/Comments/Query/GetCommentList/CommentDto.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using CodeClinic.Application.Common.Mappings; +using CodeClinic.Domain.Entities; + +namespace CodeClinic.Application.Comments.Query.GetCommentList +{ + public class CommentDto : IMapFrom + { + public int CommentId { get; set; } + public int IssueTicketId { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(i => i.CommentId, opt => opt.MapFrom(d => d.Id)); + } + + } +} diff --git a/src/Application/Comments/Query/GetCommentList/CommentListVm.cs b/src/Application/Comments/Query/GetCommentList/CommentListVm.cs new file mode 100644 index 0000000..06b7731 --- /dev/null +++ b/src/Application/Comments/Query/GetCommentList/CommentListVm.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace CodeClinic.Application.Comments.Query.GetCommentList +{ + public class CommentListVm + { + public List Items { get; set; } + } +} \ No newline at end of file diff --git a/src/Application/Comments/Query/GetCommentList/GetCommentListQuery.cs b/src/Application/Comments/Query/GetCommentList/GetCommentListQuery.cs new file mode 100644 index 0000000..c3da451 --- /dev/null +++ b/src/Application/Comments/Query/GetCommentList/GetCommentListQuery.cs @@ -0,0 +1,55 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Comments.Query.GetCommentList +{ + public class GetCommentListQuery : IRequest + { + public GetCommentListQuery(int issueTicketId) + { + IssueTicketId = issueTicketId; + } + public int IssueTicketId { get; private set; } + } + + public class GetCommentsListQueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetCommentsListQueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + + public async Task Handle(GetCommentListQuery request, CancellationToken cancellationToken) + { + var comments = await _context.Comments + .Where(it => it.IssueTicketId == request.IssueTicketId) + .Include(u=> u.Likes) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(cancellationToken); + + if (comments == null) + throw new NotFoundException(nameof(Comment), request.IssueTicketId); + + CommentListVm vm = new CommentListVm { Items = comments }; + + if (comments != null) return vm; + + return new CommentListVm(); + } + } +} diff --git a/src/Application/Common/Exceptions/NotFoundException.cs b/src/Application/Common/Exceptions/NotFoundException.cs index 9718df9..696bea8 100644 --- a/src/Application/Common/Exceptions/NotFoundException.cs +++ b/src/Application/Common/Exceptions/NotFoundException.cs @@ -2,25 +2,30 @@ namespace CodeClinic.Application.Common.Exceptions { - public class NotFoundException : Exception + public class PostException : Exception { - public NotFoundException() + public PostException() : base() { + + } - public NotFoundException(string message) + public PostException(string message) : base(message) { + + } - public NotFoundException(string message, Exception innerException) - : base(message, innerException) + + public PostException(string name, Exception innerException) + : base(name?? $"Failed to create entity \"{name}\" " , innerException) { } - public NotFoundException(string name, object key) - : base($"Entity \"{name}\" ({key}) was not found.") + public PostException(string name, string reason) + : base($"Failed to create entity \"{name}\" because {reason}") { } } diff --git a/src/Application/Common/Exceptions/PostException.cs b/src/Application/Common/Exceptions/PostException.cs new file mode 100644 index 0000000..7ffba5a --- /dev/null +++ b/src/Application/Common/Exceptions/PostException.cs @@ -0,0 +1,32 @@ +using System; + +namespace CodeClinic.Application.Common.Exceptions +{ + public class NotFoundException : Exception + { + public NotFoundException() + : base() + { + + + } + + public NotFoundException(string message) + : base(message) + { + + + } + + + public NotFoundException(string message, Exception innerException) + : base(message, innerException) + { + } + + public NotFoundException(string name, object key) + : base($"Entity \"{name}\" ({key}) was not found.") + { + } + } +} diff --git a/src/Application/Common/Interfaces/IApplicationDbContext.cs b/src/Application/Common/Interfaces/IApplicationDbContext.cs index 95ffce5..cab086c 100644 --- a/src/Application/Common/Interfaces/IApplicationDbContext.cs +++ b/src/Application/Common/Interfaces/IApplicationDbContext.cs @@ -8,8 +8,10 @@ namespace CodeClinic.Application.Common.Interfaces public interface IApplicationDbContext { - DbSet Issues {get;set;} - + DbSet IssueTickets {get;set;} + DbSet Categories { get; set; } + DbSet Comments { get; set; } + DbSet Likes { get; set; } Task SaveChangesAsync(CancellationToken cancellationToken); } } diff --git a/src/Application/Common/Models/StatusCode.cs b/src/Application/Common/Models/StatusCode.cs new file mode 100644 index 0000000..b82d70f --- /dev/null +++ b/src/Application/Common/Models/StatusCode.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.Common.Models +{ + public static class ErrorCode + { + public const string BadRequest = "400"; + public const string NotFound = "404"; + public const string InternalError= "500"; + } +} diff --git a/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommand.cs b/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommand.cs new file mode 100644 index 0000000..5989c32 --- /dev/null +++ b/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommand.cs @@ -0,0 +1,49 @@ +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace Application.Issues.Commands.CreateIssue +{ + public class CreateIssueTicketCommand : IRequest + { + public int Id { get; set; } + + public string Title { get; set; } + + public int CategoryId { get; set; } + public string Body { get; set; } + + public class CreateIssueTicketCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + public CreateIssueTicketCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + + public async Task Handle(CreateIssueTicketCommand request, CancellationToken cancellationToken) + { + var entity = new IssueTicket + { + Title = request.Title, + CategoryId = request.CategoryId, + Body = request.Body, + }; + + _context.IssueTickets.Add(entity); + + + await _context.SaveChangesAsync(cancellationToken); + return entity.Id; + } + + + } + + } + + +} \ No newline at end of file diff --git a/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommandValidator.cs b/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommandValidator.cs new file mode 100644 index 0000000..376274b --- /dev/null +++ b/src/Application/IssueTickets/Commands/CreateIssueTicket/CreateIssueTicketCommandValidator.cs @@ -0,0 +1,36 @@ +using Application.Issues.Commands.CreateIssue; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Common.Models; +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.TodoItems.Commands.UpdateTodoItem +{ + public class CreateIssueTicketCommandValidator : AbstractValidator + { + private readonly IApplicationDbContext _context; + + public CreateIssueTicketCommandValidator(IApplicationDbContext context) + { + + RuleFor(v => v.Title) + .MaximumLength(200) + .NotEmpty().WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Title cannot be longer than 200 characters"); + + RuleFor(c => c.CategoryId) + .NotNull() + .GreaterThan(0) + .MustAsync(HaveAnExistingCategory).WithErrorCode(ErrorCode.NotFound) + .WithMessage("Choose a Category that exists in the system"); + _context = context; + } + + public async Task HaveAnExistingCategory(CreateIssueTicketCommand request, int CategoryId, CancellationToken cancellationToken) + { + return await _context.Categories.AnyAsync(c => c.Id == CategoryId); + } + } +} diff --git a/src/Application/IssueTickets/Commands/CreateIssueTicket/IssueTicketCreatedEvent.cs b/src/Application/IssueTickets/Commands/CreateIssueTicket/IssueTicketCreatedEvent.cs new file mode 100644 index 0000000..8113b56 --- /dev/null +++ b/src/Application/IssueTickets/Commands/CreateIssueTicket/IssueTicketCreatedEvent.cs @@ -0,0 +1,24 @@ +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.IssueTickets.Commands.CreateIssueTicket +{ + class IssueTicketCreatedEvent : INotification + { + public int IssueTicketId { get; set; } + + public class IssueTicketCreatedEventHandler : INotificationHandler + { + public Task Handle(IssueTicketCreatedEvent notification, CancellationToken cancellationToken) + { + // do something + throw new NotImplementedException(); + } + } + } +} diff --git a/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommand.cs b/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommand.cs new file mode 100644 index 0000000..eb258b0 --- /dev/null +++ b/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommand.cs @@ -0,0 +1,14 @@ +using System; +using System.Text; +using MediatR; + + +namespace CodeClinic.Application.Issues.Commands.DeleteIssue +{ + public class DeleteIssueTicketCommand :IRequest + { + public int Id { get; set; } + } + + +} diff --git a/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommandHandler.cs b/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommandHandler.cs new file mode 100644 index 0000000..9e9d9f3 --- /dev/null +++ b/src/Application/IssueTickets/Commands/DeleteIssueTicket/DeleteIssueTicketCommandHandler.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; + + +namespace CodeClinic.Application.Issues.Commands.DeleteIssue +{ + public class DeleteIssueTicketCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public DeleteIssueTicketCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(DeleteIssueTicketCommand request, CancellationToken cancellationToken) + { + var entity = await _context.IssueTickets.FindAsync(request.Id); + + if (entity == null) + { + throw new NotFoundException(nameof(IssueTicket), request.Id); + } + + _context.IssueTickets.Remove(entity); + + await _context.SaveChangesAsync(cancellationToken); + + return Unit.Value; + } + } + + +} diff --git a/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommand.cs b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommand.cs new file mode 100644 index 0000000..33152fe --- /dev/null +++ b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommand.cs @@ -0,0 +1,16 @@ +using CodeClinic.Domain.Enums; +using MediatR; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.IssueTickets.Commands.UpdateIssueTicket +{ + public class UpdateIssueTicketCommand : IRequest + { + public int Id { get; set; } + public int CategoryId { get; set; } + public int Stars { get; set; } + public ProgressStatus Status { get; set; } + } +} diff --git a/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandHandler.cs b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandHandler.cs new file mode 100644 index 0000000..43b6815 --- /dev/null +++ b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandHandler.cs @@ -0,0 +1,34 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.IssueTickets.Commands.UpdateIssueTicket +{ + public partial class UpdateIssueTicketCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public UpdateIssueTicketCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(UpdateIssueTicketCommand request, CancellationToken cancellationToken) + { + var entity = await _context.IssueTickets.FindAsync(request.Id); + + if(entity == null) throw new NotFoundException(nameof(IssueTicket), request.Id); + + entity.Status = request.Status; + entity.Stars = request.Stars; + _context.IssueTickets.Update(entity); + + await _context.SaveChangesAsync(cancellationToken); + return Unit.Value; + } + } + + +} diff --git a/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandValidator.cs b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandValidator.cs new file mode 100644 index 0000000..64d5c13 --- /dev/null +++ b/src/Application/IssueTickets/Commands/UpdateIssueTicket/UpdateIssueTicketCommandValidator.cs @@ -0,0 +1,40 @@ +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Common.Models; +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.IssueTickets.Commands.UpdateIssueTicket +{ + + public partial class UpdateIssueTicketCommandHandler + { + public class UpdateIssueTicketCommandValidator : AbstractValidator + { + private readonly IApplicationDbContext _context; + + + public UpdateIssueTicketCommandValidator(IApplicationDbContext context) + { + RuleFor(s => s.Stars) + .GreaterThanOrEqualTo(0).NotNull().NotEmpty().WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Star Rating Cannot be less than Zero"); + + RuleFor(a => a.Status) + .NotNull().NotEmpty().WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Status cannot be null or empty"); + + RuleFor(c => c.CategoryId).NotNull().GreaterThan(0) + .MustAsync(HaveAnExistingCategory).WithErrorCode(ErrorCode.NotFound) + .WithMessage("Choose a Category that exists in the system"); + _context = context; + } + + public async Task HaveAnExistingCategory(UpdateIssueTicketCommand request, int CategoryId, CancellationToken cancellationToken) + { + return await _context.Categories.AnyAsync(c => c.Id == CategoryId); + } + } + } +} diff --git a/src/Application/Issues/Commands/UpdateIssue/UpdateIssueCommand.cs b/src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommand.cs similarity index 59% rename from src/Application/Issues/Commands/UpdateIssue/UpdateIssueCommand.cs rename to src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommand.cs index 7e7b9c3..7f7da2b 100644 --- a/src/Application/Issues/Commands/UpdateIssue/UpdateIssueCommand.cs +++ b/src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommand.cs @@ -11,33 +11,33 @@ namespace CodeClinic.Application.Issues.Commands.UpdateIssue { - public class UpdateIssueCommand : IRequest + public class UpdateIssueTicketDetailsCommand : IRequest { public int Id { get; set; } public string Title { get; set; } - public ProgressStatus Status { get; set; } + public int CategoryId { get; set; } public string Body { get; set; } - public class UpdateIssueCommandHandler : IRequestHandler + public class UpdateIssueDetailsCommandHandler : IRequestHandler { private readonly IApplicationDbContext _ctx; - public UpdateIssueCommandHandler(IApplicationDbContext ctx) + public UpdateIssueDetailsCommandHandler(IApplicationDbContext ctx) { _ctx = ctx; } - public async Task Handle(UpdateIssueCommand request, CancellationToken cancellationToken) + public async Task Handle(UpdateIssueTicketDetailsCommand request, CancellationToken cancellationToken) { - var entity = await _ctx.Issues.FindAsync(request.Id); + var entity = await _ctx.IssueTickets.FindAsync(request.Id); - if (entity == null) throw new NotFoundException(nameof(Issue), request.Id); + if (entity == null) throw new NotFoundException(nameof(IssueTicket), request.Id); entity.Title = request.Title; entity.Body = request.Body; - entity.Status = request.Status; + entity.CategoryId = request.CategoryId; - _ctx.Issues.Update(entity); + _ctx.IssueTickets.Update(entity); await _ctx.SaveChangesAsync(cancellationToken); diff --git a/src/Application/Issues/Commands/UpdateIssue/CreateIssueCommandValidator.cs b/src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommandValidator.cs similarity index 80% rename from src/Application/Issues/Commands/UpdateIssue/CreateIssueCommandValidator.cs rename to src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommandValidator.cs index 249fe03..6d41bdb 100644 --- a/src/Application/Issues/Commands/UpdateIssue/CreateIssueCommandValidator.cs +++ b/src/Application/IssueTickets/Commands/UpdateIssueTicketDetails/UpdateIssueTicketDetailsCommandValidator.cs @@ -10,10 +10,10 @@ namespace CodeClinic.Application.Issues.Commands.CreateIssue { - class UpdateIssueCommandValidator : AbstractValidator + class UpdateIssueTicketDetailsCommandValidator : AbstractValidator { - public UpdateIssueCommandValidator() + public UpdateIssueTicketDetailsCommandValidator() { RuleFor(v => v.Title) .MaximumLength(200) diff --git a/src/Application/IssueTickets/Queries/GetIssueDetail/GetIssueTicketDetailQuery.cs b/src/Application/IssueTickets/Queries/GetIssueDetail/GetIssueTicketDetailQuery.cs new file mode 100644 index 0000000..5639271 --- /dev/null +++ b/src/Application/IssueTickets/Queries/GetIssueDetail/GetIssueTicketDetailQuery.cs @@ -0,0 +1,49 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Issues.Queries.GetIssueList; +using CodeClinic.Application.IssueTickets.Queries.GetIssueDetail; +using CodeClinic.Application.Comments.Query.GetCommentList; +using CodeClinic.Domain.Entities; +using MediatR; +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.IssueItems.Queries.GetIssueDetail +{ + public class GetIssueTicketDetailQuery : IRequest< IssueTicketDetailVm> + { + public int Id { get; set; } + } + + public class GetIssueDetailQueryHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMapper _mapper; + + public GetIssueDetailQueryHandler(IApplicationDbContext context, IMapper mapper) + { + _context = context; + _mapper = mapper; + } + public async Task Handle(GetIssueTicketDetailQuery request, + CancellationToken cancellationToken) + { + var viewModel = await _context.IssueTickets + .ProjectTo(_mapper.ConfigurationProvider) + .FirstOrDefaultAsync(i => i.IssueTicketId == request.Id, cancellationToken); + + if(viewModel == null) throw new NotFoundException(nameof(IssueTicket), request.Id); + + var Comments = await _context.Comments + .ProjectTo(_mapper.ConfigurationProvider) + .Where(x => x.IssueTicketId == request.Id).ToListAsync(cancellationToken); + + viewModel.Comments = Comments; + return viewModel; + } + } +} diff --git a/src/Application/IssueTickets/Queries/GetIssueDetail/IssueTicketDetailVm.cs b/src/Application/IssueTickets/Queries/GetIssueDetail/IssueTicketDetailVm.cs new file mode 100644 index 0000000..bfa17dc --- /dev/null +++ b/src/Application/IssueTickets/Queries/GetIssueDetail/IssueTicketDetailVm.cs @@ -0,0 +1,33 @@ +using AutoMapper; +using CodeClinic.Application.Common.Mappings; +using CodeClinic.Application.Comments.Query.GetCommentList; +using CodeClinic.Domain.Entities; +using CodeClinic.Domain.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Application.IssueTickets.Queries.GetIssueDetail +{ + public class IssueTicketDetailVm:IMapFrom + { + public int CategoryId { get; set; } + public int IssueTicketId { get; set; } + public string Title { get; set; } + public int Stars { get; set; } + public string Body { get; set; } + + public ProgressStatus Status { get; set; } + public string CategoryName { get; set; } + + public IList Comments { get; set; } = new List(); + + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(c => c.CategoryName, o => o.MapFrom(c => c.Category.Name)) + .ForMember(i => i.IssueTicketId, o => o.MapFrom(c => c.Id)); + } + } +} diff --git a/src/Application/Issues/Queries/GetIssueList/GetIssueListQuery.cs b/src/Application/IssueTickets/Queries/GetIssueList/GetIssueTicketListQuery.cs similarity index 64% rename from src/Application/Issues/Queries/GetIssueList/GetIssueListQuery.cs rename to src/Application/IssueTickets/Queries/GetIssueList/GetIssueTicketListQuery.cs index 64786c4..b350854 100644 --- a/src/Application/Issues/Queries/GetIssueList/GetIssueListQuery.cs +++ b/src/Application/IssueTickets/Queries/GetIssueList/GetIssueTicketListQuery.cs @@ -12,24 +12,25 @@ namespace CodeClinic.Application.Issues.Queries.GetIssueList { - public class GetIssueListQuery : IRequest + public class GetIssueTicketListQuery : IRequest { } - public class GetIssueQueryHandler : IRequestHandler + public class GetIssueTicketQueryHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IMapper _mapper; - public GetIssueQueryHandler(IApplicationDbContext context, IMapper mapper) + public GetIssueTicketQueryHandler(IApplicationDbContext context, IMapper mapper) { _context = context; _mapper = mapper; } - public async Task Handle(GetIssueListQuery request, CancellationToken cancellationToken) + public async Task Handle(GetIssueTicketListQuery request, + CancellationToken cancellationToken) { - var issues = await _context.Issues - .ProjectTo(_mapper.ConfigurationProvider) + var issues = await _context.IssueTickets + .ProjectTo(_mapper.ConfigurationProvider) .OrderBy(i => i.Title).ToListAsync(cancellationToken); var progressStatuses = Enum.GetValues(typeof(ProgressStatus)) @@ -37,7 +38,7 @@ public async Task Handle(GetIssueListQuery request, CancellationTok .Select(p => new ProgressStatusDto { Value = (int)p, Name = p.ToString() }) .ToList(); - var viewModel = new IssueListVm + var viewModel = new IssueTicketListVm { Issues = issues, ProgressStatuses = progressStatuses diff --git a/src/Application/IssueTickets/Queries/GetIssueList/IssueTicketDto.cs b/src/Application/IssueTickets/Queries/GetIssueList/IssueTicketDto.cs new file mode 100644 index 0000000..9c93116 --- /dev/null +++ b/src/Application/IssueTickets/Queries/GetIssueList/IssueTicketDto.cs @@ -0,0 +1,38 @@ +using AutoMapper; +using CodeClinic.Application.Common.Mappings; +using CodeClinic.Domain.Entities; +using CodeClinic.Domain.Enums; +using System; + +namespace CodeClinic.Application.Issues.Queries.GetIssueList +{ + public class IssueTicketDto :IMapFrom + { + public int IssueTicketId { get; set; } + public int CategoryId { get; set; } + public string CategoryName { get; set; } + public string Title { get; set; } + public int Stars { get; set; } + public int Status { get; set; } + public string Body { get; set; } + + public string CreatedBy { get; set; } + + public DateTime DateCreated { get; set; } + + public string LastModifiedBy { get; set; } + + public DateTime? LastModified { get; set; } + + + public void Mapping(Profile profile) + { + profile.CreateMap() + .ForMember(i=> i.IssueTicketId, opt=> opt.MapFrom(i=> i.Id)) + .ForMember(s => s.Status, op => op.MapFrom(s => (int)s.Status)) + .ForMember(c => c.CategoryName, op => op.MapFrom(c => c.Category.Name)) + .ForMember(cb => cb.CreatedBy, cf => cf.MapFrom(c => c.CreatedBy ?? string.Empty)) + .ForMember(lm => lm.LastModifiedBy, opt => opt.MapFrom(c => c.LastModified != null ? c.LastModifiedBy : string.Empty)); + } + } +} diff --git a/src/Application/Issues/Queries/GetIssueList/IssueListVm.cs b/src/Application/IssueTickets/Queries/GetIssueList/IssueTicketListVm.cs similarity index 71% rename from src/Application/Issues/Queries/GetIssueList/IssueListVm.cs rename to src/Application/IssueTickets/Queries/GetIssueList/IssueTicketListVm.cs index 4a21886..2f962c9 100644 --- a/src/Application/Issues/Queries/GetIssueList/IssueListVm.cs +++ b/src/Application/IssueTickets/Queries/GetIssueList/IssueTicketListVm.cs @@ -3,10 +3,10 @@ namespace CodeClinic.Application.Issues.Queries.GetIssueList { - public class IssueListVm + public class IssueTicketListVm { public IList ProgressStatuses{ get; set; } - public IList Issues { get; set; } + public IList Issues { get; set; } } } diff --git a/src/Application/Issues/Queries/GetIssueList/ProgressStatusDto.cs b/src/Application/IssueTickets/Queries/GetIssueList/ProgressStatusDto.cs similarity index 100% rename from src/Application/Issues/Queries/GetIssueList/ProgressStatusDto.cs rename to src/Application/IssueTickets/Queries/GetIssueList/ProgressStatusDto.cs diff --git a/src/Application/Issues/Commands/CreateIssue/CreateIssueCommand.cs b/src/Application/Issues/Commands/CreateIssue/CreateIssueCommand.cs deleted file mode 100644 index c9b09b3..0000000 --- a/src/Application/Issues/Commands/CreateIssue/CreateIssueCommand.cs +++ /dev/null @@ -1,39 +0,0 @@ -using CodeClinic.Application.Common.Interfaces; -using CodeClinic.Domain.Entities; -using MediatR; -using System.Threading; -using System.Threading.Tasks; - -namespace Application.Issues.Commands.CreateIssue -{ - public class CreateIssueCommand : IRequest - { - public string Title { get; set; } - - public string Body { get; set; } - - } - public class CreateIssueItemCommandHandler : IRequestHandler - { - private readonly IApplicationDbContext _context; - public CreateIssueItemCommandHandler(IApplicationDbContext context) - { - _context = context; - } - public async Task Handle(CreateIssueCommand request, CancellationToken cancellationToken) - { - var entity = new Issue - { - Title = request.Title, - Body = request.Body, - }; - - _context.Issues.Add(entity); - - await _context.SaveChangesAsync(cancellationToken); - return entity.Id; - } - } - - -} \ No newline at end of file diff --git a/src/Application/Issues/Commands/CreateIssue/CreateIssueCommandValidator.cs b/src/Application/Issues/Commands/CreateIssue/CreateIssueCommandValidator.cs deleted file mode 100644 index d5b023c..0000000 --- a/src/Application/Issues/Commands/CreateIssue/CreateIssueCommandValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Application.Issues.Commands.CreateIssue; -using FluentValidation; - -namespace CodeClinic.Application.TodoItems.Commands.UpdateTodoItem -{ - public class CreateIssueCommandValidator : AbstractValidator - { - public CreateIssueCommandValidator() - { - - RuleFor(v => v.Title) - .MaximumLength(200) - .NotEmpty(); - } - } -} diff --git a/src/Application/Issues/Commands/DeleteIssue/DeleteIssueCommand.cs b/src/Application/Issues/Commands/DeleteIssue/DeleteIssueCommand.cs deleted file mode 100644 index 25112f6..0000000 --- a/src/Application/Issues/Commands/DeleteIssue/DeleteIssueCommand.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using CodeClinic.Application.Common.Exceptions; -using CodeClinic.Application.Common.Interfaces; -using CodeClinic.Domain.Entities; -using MediatR; - - -namespace CodeClinic.Application.Issues.Commands.DeleteIssue -{ - public class DeleteIssueCommand :IRequest - { - public int Id { get; set; } - } - - public class DeleteIssueCommandHandler : IRequestHandler - { - private readonly IApplicationDbContext _context; - - public DeleteIssueCommandHandler(IApplicationDbContext context) - { - _context = context; - } - public async Task Handle(DeleteIssueCommand request, CancellationToken cancellationToken) - { - var entity = await _context.Issues.FindAsync(request.Id); - - if (entity == null) - { - throw new NotFoundException(nameof(Issue), request.Id); - } - - _context.Issues.Remove(entity); - - await _context.SaveChangesAsync(cancellationToken); - - return Unit.Value; - } - } - - -} diff --git a/src/Application/Issues/Queries/GetIssueDetail/GetIssueDetailQuery.cs b/src/Application/Issues/Queries/GetIssueDetail/GetIssueDetailQuery.cs deleted file mode 100644 index 4e09139..0000000 --- a/src/Application/Issues/Queries/GetIssueDetail/GetIssueDetailQuery.cs +++ /dev/null @@ -1,44 +0,0 @@ -using AutoMapper; -using AutoMapper.QueryableExtensions; -using CodeClinic.Application.Common.Exceptions; -using CodeClinic.Application.Common.Interfaces; -using CodeClinic.Domain.Entities; -using MediatR; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace CodeClinic.Application.IssueItems.Queries.GetIssueDetail -{ - public class GetIssueDetailQuery : IRequest - { - public int Id { get; set; } - - } - - public class GetIssueDetailQueryHandler : IRequestHandler - { - private readonly IApplicationDbContext _context; - private readonly IMapper _mapper; - - public GetIssueDetailQueryHandler(IApplicationDbContext context, IMapper mapper) - { - _context = context; - _mapper = mapper; - } - public async Task Handle(GetIssueDetailQuery request, CancellationToken cancellationToken) - { - var viewModel = await _context.Issues - .ProjectTo(_mapper.ConfigurationProvider) - .FirstOrDefaultAsync(i => i.IssueId == request.Id, cancellationToken); - - if(viewModel == null) throw new NotFoundException(nameof(Issue), request.Id); - - return viewModel; - } - } -} diff --git a/src/Application/Issues/Queries/GetIssueDetail/IssueDetailVm.cs b/src/Application/Issues/Queries/GetIssueDetail/IssueDetailVm.cs deleted file mode 100644 index 66fff1b..0000000 --- a/src/Application/Issues/Queries/GetIssueDetail/IssueDetailVm.cs +++ /dev/null @@ -1,27 +0,0 @@ -using AutoMapper; -using CodeClinic.Domain.Entities; -using CodeClinic.Domain.Enums; -using System; -using System.Collections.Generic; -using System.Text; - -namespace CodeClinic.Application.IssueItems.Queries.GetIssueDetail -{ - public class IssueDetailVm - { - public int IssueId { get; set; } - public int WardId { get; set; } - - public string Title { get; set; } - public int Stars { get; set; } - - public int Status { get; set; } - public string Body { get; set; } - - public void Mapping(Profile profile) - { - profile.CreateMap() - .ForMember(s => s.Status, op => op.MapFrom(s => (int)s.Status)); - } - } -} diff --git a/src/Application/Issues/Queries/GetIssueList/IssueDto.cs b/src/Application/Issues/Queries/GetIssueList/IssueDto.cs deleted file mode 100644 index 9fd51c1..0000000 --- a/src/Application/Issues/Queries/GetIssueList/IssueDto.cs +++ /dev/null @@ -1,24 +0,0 @@ -using AutoMapper; -using CodeClinic.Application.Common.Mappings; -using CodeClinic.Domain.Entities; -using CodeClinic.Domain.Enums; - -namespace CodeClinic.Application.Issues.Queries.GetIssueList -{ - public class IssueDto :IMapFrom - { - public int Id { get; set; } - - public string Title { get; set; } - public int Stars { get; set; } - - public int Status { get; set; } - public string Body { get; set; } - - public void Mapping(Profile profile) - { - profile.CreateMap() - .ForMember(s => s.Status, op => op.MapFrom(s => (int)s.Status)); - } - } -} diff --git a/src/Application/Likes/Commands/CreateLike/CreateLikeCommand.cs b/src/Application/Likes/Commands/CreateLike/CreateLikeCommand.cs new file mode 100644 index 0000000..ac04260 --- /dev/null +++ b/src/Application/Likes/Commands/CreateLike/CreateLikeCommand.cs @@ -0,0 +1,43 @@ +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Likes.Commands +{ + public class CreateLikeCommand :IRequest + { + + public int CommentId { get; set; } + + public class CreateLikeCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public CreateLikeCommandHandler(IApplicationDbContext context) + { + _context = context; + } + + async Task IRequestHandler.Handle(CreateLikeCommand request, CancellationToken cancellationToken) + { + + if (request.CommentId == 0) + throw new Exception("Comment Id Cannot be empty"); + + var like = new Like { CommentId = request.CommentId , IsLiked = true }; + + _context.Likes.Add(like); + + await _context.SaveChangesAsync(cancellationToken); + + return like.Id; + } + } + } +} diff --git a/src/Application/Likes/Commands/CreateLike/CreateLikeCommandValidator.cs b/src/Application/Likes/Commands/CreateLike/CreateLikeCommandValidator.cs new file mode 100644 index 0000000..5e44abe --- /dev/null +++ b/src/Application/Likes/Commands/CreateLike/CreateLikeCommandValidator.cs @@ -0,0 +1,44 @@ +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Common.Models; +using FluentValidation; +using Microsoft.EntityFrameworkCore; + +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Likes.Commands +{ + class CreateLikeCommandValidator : AbstractValidator + { + private readonly IApplicationDbContext _context; + private readonly ICurrentUserService _currentUserService; + + public CreateLikeCommandValidator(IApplicationDbContext context,ICurrentUserService currentUserService) + { + _context = context; + _currentUserService = currentUserService; + } + public CreateLikeCommandValidator() + { + + RuleFor(c => c.CommentId) + .NotEmpty() + .WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Comment Id cannot be empty") + .MustAsync(NotExist) + .WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Comment already liked by user"); + } + + private async Task NotExist(int commentId, CancellationToken cancellationToken) + { + + var userId = _currentUserService.UserId; + + var like = await _context.Likes + .SingleOrDefaultAsync(x => x.CreatedBy == userId && x.CommentId == commentId); + + return like == null; + } + } +} diff --git a/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommand.cs b/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommand.cs new file mode 100644 index 0000000..7442d2e --- /dev/null +++ b/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommand.cs @@ -0,0 +1,36 @@ +using MediatR; +using System.Threading; +using System.Threading.Tasks; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Domain.Entities; + +namespace CodeClinic.Application.Likes.Commands.DeleteLike +{ + public class DeleteLikeCommand :IRequest + { + public int LikeId { get; set; } + + public class DeleteLikeCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public DeleteLikeCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(DeleteLikeCommand request, CancellationToken cancellationToken) + { + + var like = await _context.Likes.FindAsync(request.LikeId,cancellationToken); + + if (like == null) throw new NotFoundException(nameof(Like), request.LikeId); + + _context.Likes.Remove(like); + + return Unit.Value; + } + } + } + +} diff --git a/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommandValidator.cs b/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommandValidator.cs new file mode 100644 index 0000000..4f35a4c --- /dev/null +++ b/src/Application/Likes/Commands/DeleteLike/DeleteLikeCommandValidator.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentValidation; +using System.Threading.Tasks; +using CodeClinic.Application.Common.Models; + +namespace CodeClinic.Application.Likes.Commands.DeleteLike +{ + class DeleteLikeCommandValidator : AbstractValidator + { + + public DeleteLikeCommandValidator() + { + RuleFor(c => c.LikeId) + .NotEqual(0) + .WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Invalid Id"); + + + + } + } +} diff --git a/src/Application/Likes/Commands/UpdateLike/UpdateLikeCommand.cs b/src/Application/Likes/Commands/UpdateLike/UpdateLikeCommand.cs new file mode 100644 index 0000000..95b0d55 --- /dev/null +++ b/src/Application/Likes/Commands/UpdateLike/UpdateLikeCommand.cs @@ -0,0 +1,36 @@ +using CodeClinic.Application.Common.Exceptions; +using CodeClinic.Application.Common.Interfaces; +using CodeClinic.Domain.Entities; +using MediatR; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeClinic.Application.Likes.Commands.UpdateLike +{ + public class UpdateLikeCommand : IRequest + { + public int LikeId { get; set; } + + public class UpdateLikeCommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + + public UpdateLikeCommandHandler(IApplicationDbContext context) + { + _context = context; + } + public async Task Handle(UpdateLikeCommand request, CancellationToken cancellationToken) + { + + var like = await _context.Likes.FindAsync(request.LikeId, cancellationToken) ; + + if (like == null) + throw new NotFoundException(nameof(Like), request.LikeId); + + like.IsLiked = !like.IsLiked; + + return Unit.Value; + } + } + } +} diff --git a/src/Application/Likes/Commands/UpdateLike/UpdateLikeValidator.cs b/src/Application/Likes/Commands/UpdateLike/UpdateLikeValidator.cs new file mode 100644 index 0000000..5c6f674 --- /dev/null +++ b/src/Application/Likes/Commands/UpdateLike/UpdateLikeValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; +using CodeClinic.Application.Common.Models; + +namespace CodeClinic.Application.Likes.Commands.UpdateLike +{ + public class UpdateLikeValidator : AbstractValidator + { + + public UpdateLikeValidator() + { + RuleFor(i => i.LikeId) + .NotEqual(0) + .WithErrorCode(ErrorCode.BadRequest) + .WithMessage("Like Id cannot be equal to 0"); + } + } +} diff --git a/src/Domain/Common/AuditableEntity.cs b/src/Domain/Common/AuditableEntity.cs index bbf7bea..bed036b 100644 --- a/src/Domain/Common/AuditableEntity.cs +++ b/src/Domain/Common/AuditableEntity.cs @@ -4,6 +4,7 @@ namespace CodeClinic.Domain.Common { public abstract class AuditableEntity { + public string CreatedBy { get; set; } public DateTime Created { get; set; } diff --git a/src/Domain/Common/BaseEntity.cs b/src/Domain/Common/BaseEntity.cs new file mode 100644 index 0000000..eb258ec --- /dev/null +++ b/src/Domain/Common/BaseEntity.cs @@ -0,0 +1,14 @@ +using CodeClinic.Domain.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeClinic.Domain.Common +{ + public class BaseEntity : AuditableEntity + { + public int Id { get; set; } + } +} diff --git a/src/Domain/Domain.csproj b/src/Domain/Domain.csproj index 65629b5..f7bcc82 100644 --- a/src/Domain/Domain.csproj +++ b/src/Domain/Domain.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net5.0 CodeClinic.Domain CodeClinic.Domain diff --git a/src/Domain/Entities/Category.cs b/src/Domain/Entities/Category.cs new file mode 100644 index 0000000..8c4d989 --- /dev/null +++ b/src/Domain/Entities/Category.cs @@ -0,0 +1,19 @@ +using CodeClinic.Domain.Common; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; + +namespace CodeClinic.Domain.Entities +{ + public class Category : BaseEntity + { + public Category() + { + IssueTickets = new List(); + } + public string Name { get; set; } + public string Description { get; set; } + public IList IssueTickets { get; private set; } + } +} diff --git a/src/Domain/Entities/Comment.cs b/src/Domain/Entities/Comment.cs new file mode 100644 index 0000000..b53e029 --- /dev/null +++ b/src/Domain/Entities/Comment.cs @@ -0,0 +1,24 @@ +using CodeClinic.Domain.Common; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Domain.Entities +{ + public class Comment : BaseEntity + { + + public int IssueTicketId { get; set; } + + public int DisLikes { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } + + public IssueTicket IssueTicket { get;private set; } + + public List Likes { get; private set; } = new List(); + + } +} diff --git a/src/Domain/Entities/Issue.cs b/src/Domain/Entities/Issue.cs deleted file mode 100644 index de1a5cb..0000000 --- a/src/Domain/Entities/Issue.cs +++ /dev/null @@ -1,15 +0,0 @@ -using CodeClinic.Domain.Common; -using CodeClinic.Domain.Enums; - -namespace CodeClinic.Domain.Entities -{ - public class Issue : AuditableEntity - { - public int Id { get; set; } - public string Title { get; set; } - public int Stars { get; set; } - - public ProgressStatus Status { get; set; } - public string Body { get; set; } - } -} \ No newline at end of file diff --git a/src/Domain/Entities/IssueTicket.cs b/src/Domain/Entities/IssueTicket.cs new file mode 100644 index 0000000..a16d1f1 --- /dev/null +++ b/src/Domain/Entities/IssueTicket.cs @@ -0,0 +1,19 @@ +using CodeClinic.Domain.Common; +using CodeClinic.Domain.Enums; +using System.Collections.Generic; + +namespace CodeClinic.Domain.Entities +{ + public class IssueTicket : BaseEntity + { + public int CategoryId { get; set; } + public string Title { get; set; } + public int Stars { get; set; } + public string Body { get; set; } + public bool IsPublished { get; set; } + public ProgressStatus Status { get; set; } + public Category Category { get; private set; } + + public IList Comments { get; private set; } = new List(); + } +} \ No newline at end of file diff --git a/src/Domain/Entities/Like.cs b/src/Domain/Entities/Like.cs new file mode 100644 index 0000000..b66670c --- /dev/null +++ b/src/Domain/Entities/Like.cs @@ -0,0 +1,12 @@ + +using CodeClinic.Domain.Common; + +namespace CodeClinic.Domain.Entities +{ + public class Like : BaseEntity + { + public int CommentId { get; set; } + public Comment Comment { get; set; } + public bool IsLiked { get; set; } + } +} \ No newline at end of file diff --git a/src/Infrastructure/Identity/ApplicationUser.cs b/src/Infrastructure/Identity/ApplicationUser.cs index bab4bc5..27451a4 100644 --- a/src/Infrastructure/Identity/ApplicationUser.cs +++ b/src/Infrastructure/Identity/ApplicationUser.cs @@ -4,5 +4,11 @@ namespace CodeClinic.Infrastructure.Identity { public class ApplicationUser : IdentityUser { + public string CoverImage { get; set; } + public string AvatarImage { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Bio { get; set; } + } } diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj index 29ae36b..44f235f 100644 --- a/src/Infrastructure/Infrastructure.csproj +++ b/src/Infrastructure/Infrastructure.csproj @@ -1,17 +1,17 @@  - netcoreapp3.1 + net5.0 CodeClinic.Infrastructure CodeClinic.Infrastructure - - - - - + + + + + diff --git a/src/Infrastructure/Persistence/ApplicationDbContext.cs b/src/Infrastructure/Persistence/ApplicationDbContext.cs index a4527a7..52f21a0 100644 --- a/src/Infrastructure/Persistence/ApplicationDbContext.cs +++ b/src/Infrastructure/Persistence/ApplicationDbContext.cs @@ -30,7 +30,10 @@ public ApplicationDbContext( _dateTime = dateTime; } - public DbSet Issues { get ; set ; } + public DbSet IssueTickets { get ; set ; } + public DbSet Categories {get; set ; } + public DbSet Comments { get ; set; } + public DbSet Likes { get ; set ; } public override Task SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken()) { diff --git a/src/Infrastructure/Persistence/ApplicationDbContextSeed.cs b/src/Infrastructure/Persistence/ApplicationDbContextSeed.cs index 1e942f5..d7ac6a7 100644 --- a/src/Infrastructure/Persistence/ApplicationDbContextSeed.cs +++ b/src/Infrastructure/Persistence/ApplicationDbContextSeed.cs @@ -1,54 +1,130 @@ using CodeClinic.Domain.Entities; using CodeClinic.Infrastructure.Identity; using Microsoft.AspNetCore.Identity; +using System; using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; namespace CodeClinic.Infrastructure.Persistence { public static class ApplicationDbContextSeed { + private static ApplicationUser _defaultUser; + public static async Task SeedDefaultUserAsync(UserManager userManager) { - var defaultUser = new ApplicationUser { UserName = "admin@admin.com", Email = "admin@admin.com" }; + _defaultUser = new ApplicationUser { UserName = "admin@admin.com", Email = "admin@admin.com" }; - if (userManager.Users.All(u => u.UserName != defaultUser.UserName)) + if (userManager.Users.All(u => u.UserName != _defaultUser.UserName)) { - await userManager.CreateAsync(defaultUser, "P@ssw0rd"); + await userManager.CreateAsync(_defaultUser, "P@ssw0rd"); } } public static async Task SeedSampleDataAsync(ApplicationDbContext context) { // Seed, if necessary - if (!context.Issues.Any()) - { - context.Issues.AddRange( - new List - { - new Issue{ - Title = "😥 I broke my Clients Ecommece System Please Help", - Body = "I was Updating to the latest version of entity framework and everything went west of westeros", - }, - - new Issue{ - Title = "My Xamarin 📱 Application Has a Bug ,I cant Fix", - Body = "I cant seem to create a new page ", - }, - new Issue{ - Title = "😫 How do I integrate CICD on Web application", - Body = "Help hellp help ,I am frustrated", - }, - - new Issue{ - Title = "Fix me! it Says ,But ☹ I dont know How", - Body = "Help me pleae ,Anyone someone ", - }, - } - ); - await context.SaveChangesAsync(); - } + //if (!context.IssueTickets.Any()) + //{ + // var categories = new List + // { + // new Category{CreatedBy=_defaultUser.Id, Name = "Xamarin", Description ="Bug Issue Tickets related to Xamarin"}, + // new Category{CreatedBy=_defaultUser.Id, Name = "AspNet Core ", Description ="Issue Tickets related to AspNet Core"}, + // new Category{CreatedBy=_defaultUser.Id, Name = "Xamarin", Description ="Reported Bug issues for Blazor"}, + // new Category{CreatedBy=_defaultUser.Id, Name = "ML.Net", Description ="Issues Related ML.Net"}, + // new Category{CreatedBy=_defaultUser.Id, Name = "UWP", Description ="Bug Issue Tickets related to Universal Windows Platform"}, + // }; + + // context.Categories.AddRange(categories); + + // await context.SaveChangesAsync(); + + // context.IssueTickets.AddRange( + // new List + // { + // new IssueTicket{ + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title = "😥 I broke my Clients Ecommece System Please Help", + // CategoryId = 1, + // Status = Domain.Enums.ProgressStatus.InDiscussion, + // Body = "I was Updating to the latest version of entity framework and everything went west of westeros", + + // }, + + // new IssueTicket{ + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title = "My Xamarin 📱 Application Has a Bug ,I cant Fix", + // CategoryId = 2, + // Body = "I cant seem to create a new page ", + // }, + // new IssueTicket{ + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title = "😫 How do I integrate CICD on Web application", + // CategoryId = 3, + // Body = "Help hellp help ,I am frustrated", + // }, + + // new IssueTicket{ + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title = "Fix me! it Says ,But ☹ I dont know How", + // CategoryId = 4, + // Body = "Help me pleae ,Anyone someone ", + // }, + // } + // ); + + // var comments = new List + // { + // new Comment + // { + // IssueTicketId = 3, + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title = "Provide more details", + // Description="Can you describe the problem you facing " + + // }, + // new Comment + // { + // IssueTicketId = 2, + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title="Here is how you should debug your app", + // Description ="If you were updating to 6.4 which is the latest current version at the time this was posted ,you should be aware that certain implementations where changed you I will show you where to " + + // "change on your previous version else if this doesn help open the docs,should refer to the docs", + + // }, + // new Comment + // { + // IssueTicketId = 3, + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title="Here is how you should debug your app", + // Description ="If you were updating to 6.4 which is the latest current version at the time this was posted ,you should be aware that certain implementations where changed you I will show you where to " + + // "change on your previous version else if this doesn help open the docs,should refer to the docs", + + // }, + // new Comment + // { + // IssueTicketId =1, + // Created = DateTime.Now, + // CreatedBy = _defaultUser.Id, + // Title="Here is how you should debug your app", + // Description ="If you were updating to 6.4 which is the latest current version at the time this was posted ,you should be aware that certain implementations where changed you I will show you where to " + + // "change on your previous version else if this doesn help open the docs,should refer to the docs", + + // } + // }; + + // context.Comments.AddRange(comments); + // await context.SaveChangesAsync(); + //} } } } diff --git a/src/Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs b/src/Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs new file mode 100644 index 0000000..d4fbe39 --- /dev/null +++ b/src/Infrastructure/Persistence/Configurations/ApplicationUserConfiguration.cs @@ -0,0 +1,13 @@ +using CodeClinic.Infrastructure.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CodeClinic.Infrastructure.Persistence.Configurations +{ + class ApplicationUserConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + } + } +} diff --git a/src/Infrastructure/Persistence/Configurations/CategoryConfiguration.cs b/src/Infrastructure/Persistence/Configurations/CategoryConfiguration.cs new file mode 100644 index 0000000..a62eab4 --- /dev/null +++ b/src/Infrastructure/Persistence/Configurations/CategoryConfiguration.cs @@ -0,0 +1,23 @@ +using CodeClinic.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CodeClinic.Infrastructure.Persistence.Configurations +{ + class CategoryConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(n => n.Name) + .HasMaxLength(30) + .IsRequired(); + builder.Property(d => d.Description) + .HasMaxLength(500); + + + builder.HasMany(it => it.IssueTickets) + .WithOne(x => x.Category) + .OnDelete(DeleteBehavior.Cascade); + } + } +} diff --git a/src/Infrastructure/Persistence/Configurations/CommentConfiguration.cs b/src/Infrastructure/Persistence/Configurations/CommentConfiguration.cs new file mode 100644 index 0000000..4fbd0c8 --- /dev/null +++ b/src/Infrastructure/Persistence/Configurations/CommentConfiguration.cs @@ -0,0 +1,32 @@ +using CodeClinic.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Infrastructure.Persistence.Configurations +{ + class CommentConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + + builder.Property(t => t.Title); + builder + .Property(c => c.Description) + .IsRequired(); + + + builder.HasOne(x => x.IssueTicket) + .WithMany(d => d.Comments) + .OnDelete(DeleteBehavior.Cascade) + .HasForeignKey(k => k.IssueTicketId) + .IsRequired(); + + builder.HasMany(x => x.Likes) + .WithOne(d=> d.Comment).OnDelete(DeleteBehavior.Cascade); + + } + } +} diff --git a/src/Infrastructure/Persistence/Configurations/IssueConfiguration.cs b/src/Infrastructure/Persistence/Configurations/IssueConfiguration.cs deleted file mode 100644 index e880d22..0000000 --- a/src/Infrastructure/Persistence/Configurations/IssueConfiguration.cs +++ /dev/null @@ -1,19 +0,0 @@ -using CodeClinic.Domain.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using System; -using System.Collections.Generic; -using System.Text; - -namespace CodeClinic.Infrastructure.Persistence.Configurations -{ - public class IssueConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.Property(t => t.Title) - .HasMaxLength(200) - .IsRequired(); - } - } -} diff --git a/src/Infrastructure/Persistence/Configurations/IssueTicketConfiguration.cs b/src/Infrastructure/Persistence/Configurations/IssueTicketConfiguration.cs new file mode 100644 index 0000000..bc0cf25 --- /dev/null +++ b/src/Infrastructure/Persistence/Configurations/IssueTicketConfiguration.cs @@ -0,0 +1,27 @@ +using CodeClinic.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CodeClinic.Infrastructure.Persistence.Configurations +{ + public class IssueTicketConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.Property(t => t.Title) + .HasMaxLength(200) + .IsRequired(); + + builder.HasOne(c => c.Category) + .WithMany(it => it.IssueTickets) + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict); + + builder.HasMany(d => d.Comments) + .WithOne(it => it.IssueTicket); + } + } +} diff --git a/src/Infrastructure/Persistence/Configurations/LikeConfiguration.cs b/src/Infrastructure/Persistence/Configurations/LikeConfiguration.cs new file mode 100644 index 0000000..0f41041 --- /dev/null +++ b/src/Infrastructure/Persistence/Configurations/LikeConfiguration.cs @@ -0,0 +1,30 @@ +using CodeClinic.Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CodeClinic.Infrastructure.Persistence.Configurations +{ + public class LikeConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder + .Property(d => d.CommentId) + .IsRequired(); + + builder + .Property(d => d.CreatedBy) + .IsRequired(); + + builder.HasOne(c => c.Comment) + .WithMany(cm => cm.Likes).HasForeignKey(k => k.CommentId); + + } + } + +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.Designer.cs new file mode 100644 index 0000000..bc7a850 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.Designer.cs @@ -0,0 +1,397 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201116025644_RenameIssueTableToIssueTickets")] + partial class RenameIssueTableToIssueTickets + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.cs b/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.cs new file mode 100644 index 0000000..d1209e5 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116025644_RenameIssueTableToIssueTickets.cs @@ -0,0 +1,117 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class RenameIssueTableToIssueTickets : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Issues"); + + migrationBuilder.DropTable( + name: "TodoItems"); + + migrationBuilder.DropTable( + name: "TodoLists"); + + migrationBuilder.CreateTable( + name: "IssueTickets", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CreatedBy = table.Column(nullable: true), + Created = table.Column(nullable: false), + LastModifiedBy = table.Column(nullable: true), + LastModified = table.Column(nullable: true), + Title = table.Column(maxLength: 200, nullable: false), + Stars = table.Column(nullable: false), + Status = table.Column(nullable: false), + Body = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_IssueTickets", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "IssueTickets"); + + migrationBuilder.CreateTable( + name: "Issues", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Body = table.Column(type: "nvarchar(max)", nullable: true), + Created = table.Column(type: "datetime2", nullable: false), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModified = table.Column(type: "datetime2", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + Stars = table.Column(type: "int", nullable: false), + Status = table.Column(type: "int", nullable: false), + Title = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Issues", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TodoLists", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Colour = table.Column(type: "nvarchar(max)", nullable: true), + Created = table.Column(type: "datetime2", nullable: false), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModified = table.Column(type: "datetime2", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + Title = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TodoLists", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "TodoItems", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Created = table.Column(type: "datetime2", nullable: false), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + Done = table.Column(type: "bit", nullable: false), + LastModified = table.Column(type: "datetime2", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + ListId = table.Column(type: "int", nullable: false), + Note = table.Column(type: "nvarchar(max)", nullable: true), + Priority = table.Column(type: "int", nullable: false), + Reminder = table.Column(type: "datetime2", nullable: true), + Title = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TodoItems", x => x.Id); + table.ForeignKey( + name: "FK_TodoItems_TodoLists_ListId", + column: x => x.ListId, + principalTable: "TodoLists", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_TodoItems_ListId", + table: "TodoItems", + column: "ListId"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.Designer.cs new file mode 100644 index 0000000..d0aca52 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.Designer.cs @@ -0,0 +1,441 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201116050001_CreateCategoriesTable")] + partial class CreateCategoriesTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.cs b/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.cs new file mode 100644 index 0000000..380c503 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116050001_CreateCategoriesTable.cs @@ -0,0 +1,66 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class CreateCategoriesTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CategoryId", + table: "IssueTickets", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "Categories", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CreatedBy = table.Column(nullable: true), + Created = table.Column(nullable: false), + LastModifiedBy = table.Column(nullable: true), + LastModified = table.Column(nullable: true), + Name = table.Column(nullable: true), + Description = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Categories", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_IssueTickets_CategoryId", + table: "IssueTickets", + column: "CategoryId"); + + migrationBuilder.AddForeignKey( + name: "FK_IssueTickets_Categories_CategoryId", + table: "IssueTickets", + column: "CategoryId", + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_IssueTickets_Categories_CategoryId", + table: "IssueTickets"); + + migrationBuilder.DropTable( + name: "Categories"); + + migrationBuilder.DropIndex( + name: "IX_IssueTickets_CategoryId", + table: "IssueTickets"); + + migrationBuilder.DropColumn( + name: "CategoryId", + table: "IssueTickets"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.Designer.cs new file mode 100644 index 0000000..2c19ee3 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.Designer.cs @@ -0,0 +1,444 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201116050922_AddedRulestoCategoryTableColumns")] + partial class AddedRulestoCategoryTableColumns + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(500)") + .HasMaxLength(500); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(30)") + .HasMaxLength(30); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.cs b/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.cs new file mode 100644 index 0000000..5fc39da --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201116050922_AddedRulestoCategoryTableColumns.cs @@ -0,0 +1,48 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class AddedRulestoCategoryTableColumns : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "Categories", + maxLength: 30, + nullable: false, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "Description", + table: "Categories", + maxLength: 500, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(max)", + oldNullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "Categories", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 30); + + migrationBuilder.AlterColumn( + name: "Description", + table: "Categories", + type: "nvarchar(max)", + nullable: true, + oldClrType: typeof(string), + oldMaxLength: 500, + oldNullable: true); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.Designer.cs new file mode 100644 index 0000000..2130605 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.Designer.cs @@ -0,0 +1,490 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201118041232_CreateReviewTable")] + partial class CreateReviewTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(500)") + .HasMaxLength(500); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(30)") + .HasMaxLength(30); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Review", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Reviews"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Review", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Reviews") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.cs b/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.cs new file mode 100644 index 0000000..25007fc --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201118041232_CreateReviewTable.cs @@ -0,0 +1,71 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class CreateReviewTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_IssueTickets_Categories_CategoryId", + table: "IssueTickets"); + + migrationBuilder.CreateTable( + name: "Reviews", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CreatedBy = table.Column(nullable: true), + Created = table.Column(nullable: false), + LastModifiedBy = table.Column(nullable: true), + LastModified = table.Column(nullable: true), + IssueTicketId = table.Column(nullable: false), + Title = table.Column(nullable: true), + Description = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Reviews", x => x.Id); + table.ForeignKey( + name: "FK_Reviews_IssueTickets_IssueTicketId", + column: x => x.IssueTicketId, + principalTable: "IssueTickets", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Reviews_IssueTicketId", + table: "Reviews", + column: "IssueTicketId"); + + migrationBuilder.AddForeignKey( + name: "CategoryIssueTickets", + table: "IssueTickets", + column: "CategoryId", + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "CategoryIssueTickets", + table: "IssueTickets"); + + migrationBuilder.DropTable( + name: "Reviews"); + + migrationBuilder.AddForeignKey( + name: "FK_IssueTickets_Categories_CategoryId", + table: "IssueTickets", + column: "CategoryId", + principalTable: "Categories", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.Designer.cs new file mode 100644 index 0000000..c1c618a --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.Designer.cs @@ -0,0 +1,490 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201119120107_ChangedReviewToComment")] + partial class ChangedReviewToComment + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(500)") + .HasMaxLength(500); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(30)") + .HasMaxLength(30); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("DeviceCode") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("ClientId") + .IsRequired() + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasMaxLength(50000); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SubjectId") + .HasColumnType("nvarchar(200)") + .HasMaxLength(200); + + b.Property("Type") + .IsRequired() + .HasColumnType("nvarchar(50)") + .HasMaxLength(50); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.cs b/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.cs new file mode 100644 index 0000000..5738fdb --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201119120107_ChangedReviewToComment.cs @@ -0,0 +1,80 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class ChangedReviewToComment : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Reviews"); + + migrationBuilder.CreateTable( + name: "Comments", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CreatedBy = table.Column(nullable: true), + Created = table.Column(nullable: false), + LastModifiedBy = table.Column(nullable: true), + LastModified = table.Column(nullable: true), + IssueTicketId = table.Column(nullable: false), + Title = table.Column(nullable: true), + Description = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Comments", x => x.Id); + table.ForeignKey( + name: "FK_Comments_IssueTickets_IssueTicketId", + column: x => x.IssueTicketId, + principalTable: "IssueTickets", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Comments_IssueTicketId", + table: "Comments", + column: "IssueTicketId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Comments"); + + migrationBuilder.CreateTable( + name: "Reviews", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Created = table.Column(type: "datetime2", nullable: false), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + Description = table.Column(type: "nvarchar(max)", nullable: false), + IssueTicketId = table.Column(type: "int", nullable: false), + LastModified = table.Column(type: "datetime2", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + Title = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Reviews", x => x.Id); + table.ForeignKey( + name: "FK_Reviews_IssueTickets_IssueTicketId", + column: x => x.IssueTicketId, + principalTable: "IssueTickets", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Reviews_IssueTicketId", + table: "Reviews", + column: "IssueTicketId"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.Designer.cs new file mode 100644 index 0000000..30e375d --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.Designer.cs @@ -0,0 +1,525 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201120033215_UpdateIdentityTables")] + partial class UpdateIdentityTables + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.cs b/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.cs new file mode 100644 index 0000000..646b571 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201120033215_UpdateIdentityTables.cs @@ -0,0 +1,77 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class UpdateIdentityTables : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ConsumedTime", + table: "PersistedGrants", + type: "datetime2", + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "PersistedGrants", + type: "nvarchar(200)", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "PersistedGrants", + type: "nvarchar(100)", + maxLength: 100, + nullable: true); + + migrationBuilder.AddColumn( + name: "Description", + table: "DeviceCodes", + type: "nvarchar(200)", + maxLength: 200, + nullable: true); + + migrationBuilder.AddColumn( + name: "SessionId", + table: "DeviceCodes", + type: "nvarchar(100)", + maxLength: 100, + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants", + columns: new[] { "SubjectId", "SessionId", "Type" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PersistedGrants_SubjectId_SessionId_Type", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "ConsumedTime", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "PersistedGrants"); + + migrationBuilder.DropColumn( + name: "Description", + table: "DeviceCodes"); + + migrationBuilder.DropColumn( + name: "SessionId", + table: "DeviceCodes"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.Designer.cs new file mode 100644 index 0000000..811363c --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.Designer.cs @@ -0,0 +1,531 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201121155421_AddedLikeAndDislikeCOlumnToCommentTable")] + partial class AddedLikeAndDislikeCOlumnToCommentTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisLikes") + .HasColumnType("int"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Likes") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.cs b/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.cs new file mode 100644 index 0000000..b024981 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201121155421_AddedLikeAndDislikeCOlumnToCommentTable.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class AddedLikeAndDislikeCOlumnToCommentTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DisLikes", + table: "Comments", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "Likes", + table: "Comments", + type: "int", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DisLikes", + table: "Comments"); + + migrationBuilder.DropColumn( + name: "Likes", + table: "Comments"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.Designer.cs new file mode 100644 index 0000000..3ce62a9 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.Designer.cs @@ -0,0 +1,577 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201128134050_CreateLikeTable")] + partial class CreateLikeTable + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisLikes") + .HasColumnType("int"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("CommentId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.HasOne("CodeClinic.Domain.Entities.Comment", "Comment") + .WithMany("Likes") + .HasForeignKey("CommentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Comment"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Navigation("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.cs b/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.cs new file mode 100644 index 0000000..13f6f20 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128134050_CreateLikeTable.cs @@ -0,0 +1,67 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class CreateLikeTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Likes", + table: "Comments"); + + migrationBuilder.AddColumn( + name: "IsPublished", + table: "IssueTickets", + type: "bit", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateTable( + name: "Likes", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + CommentId = table.Column(type: "int", nullable: false), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: false), + Created = table.Column(type: "datetime2", nullable: false), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModified = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Likes", x => x.Id); + table.ForeignKey( + name: "FK_Likes_Comments_CommentId", + column: x => x.CommentId, + principalTable: "Comments", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Likes_CommentId", + table: "Likes", + column: "CommentId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Likes"); + + migrationBuilder.DropColumn( + name: "IsPublished", + table: "IssueTickets"); + + migrationBuilder.AddColumn( + name: "Likes", + table: "Comments", + type: "int", + nullable: false, + defaultValue: 0); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.Designer.cs new file mode 100644 index 0000000..2382292 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.Designer.cs @@ -0,0 +1,580 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201128140323_CreatedIsLikedColumn")] + partial class CreatedIsLikedColumn + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisLikes") + .HasColumnType("int"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("CommentId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsLiked") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.HasOne("CodeClinic.Domain.Entities.Comment", "Comment") + .WithMany("Likes") + .HasForeignKey("CommentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Comment"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Navigation("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.cs b/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.cs new file mode 100644 index 0000000..719f219 --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128140323_CreatedIsLikedColumn.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class CreatedIsLikedColumn : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsLiked", + table: "Likes", + type: "bit", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsLiked", + table: "Likes"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.Designer.cs b/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.Designer.cs new file mode 100644 index 0000000..84c85fa --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.Designer.cs @@ -0,0 +1,595 @@ +// +using System; +using CodeClinic.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20201128153350_AddProfileColumns")] + partial class AddProfileColumns + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisLikes") + .HasColumnType("int"); + + b.Property("IssueTicketId") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("IsPublished") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Stars") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("CommentId") + .HasColumnType("int"); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("IsLiked") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CommentId"); + + b.ToTable("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("AvatarImage") + .HasColumnType("nvarchar(max)"); + + b.Property("Bio") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CoverImage") + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => + { + b.Property("UserCode") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("DeviceCode") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .IsRequired() + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("UserCode"); + + b.HasIndex("DeviceCode") + .IsUnique(); + + b.HasIndex("Expiration"); + + b.ToTable("DeviceCodes"); + }); + + modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Key"); + + b.HasIndex("Expiration"); + + b.HasIndex("SubjectId", "ClientId", "Type"); + + b.HasIndex("SubjectId", "SessionId", "Type"); + + b.ToTable("PersistedGrants"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => + { + b.HasOne("CodeClinic.Domain.Entities.Comment", "Comment") + .WithMany("Likes") + .HasForeignKey("CommentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Comment"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("CodeClinic.Infrastructure.Identity.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Navigation("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.cs b/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.cs new file mode 100644 index 0000000..f60cadc --- /dev/null +++ b/src/Infrastructure/Persistence/Migrations/20201128153350_AddProfileColumns.cs @@ -0,0 +1,63 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace CodeClinic.Infrastructure.Persistence.Migrations +{ + public partial class AddProfileColumns : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AvatarImage", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "Bio", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "CoverImage", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "FirstName", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastName", + table: "AspNetUsers", + type: "nvarchar(max)", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AvatarImage", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "Bio", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "CoverImage", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "FirstName", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "LastName", + table: "AspNetUsers"); + } + } +} diff --git a/src/Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs index 633c2a5..96e1171 100644 --- a/src/Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs @@ -15,19 +15,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.0") + .UseIdentityColumns() .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasAnnotation("ProductVersion", "5.0.0"); - modelBuilder.Entity("CodeClinic.Domain.Entities.Issue", b => + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - - b.Property("Body") - .HasColumnType("nvarchar(max)"); + .UseIdentityColumn(); b.Property("Created") .HasColumnType("datetime2"); @@ -35,34 +32,77 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedBy") .HasColumnType("nvarchar(max)"); + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + b.Property("LastModified") .HasColumnType("datetime2"); b.Property("LastModifiedBy") .HasColumnType("nvarchar(max)"); - b.Property("Stars") + b.Property("Name") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.HasKey("Id"); + + b.ToTable("Categories"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .UseIdentityColumn(); + + b.Property("Created") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DisLikes") .HasColumnType("int"); - b.Property("Status") + b.Property("IssueTicketId") .HasColumnType("int"); + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + b.Property("Title") - .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); - b.ToTable("Issues"); + b.HasIndex("IssueTicketId"); + + b.ToTable("Comments"); }); - modelBuilder.Entity("CodeClinic.Domain.Entities.TodoItem", b => + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .UseIdentityColumn(); + + b.Property("Body") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); b.Property("Created") .HasColumnType("datetime2"); @@ -70,7 +110,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedBy") .HasColumnType("nvarchar(max)"); - b.Property("Done") + b.Property("IsPublished") .HasColumnType("bit"); b.Property("LastModified") @@ -79,60 +119,55 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("LastModifiedBy") .HasColumnType("nvarchar(max)"); - b.Property("ListId") + b.Property("Stars") .HasColumnType("int"); - b.Property("Note") - .HasColumnType("nvarchar(max)"); - - b.Property("Priority") + b.Property("Status") .HasColumnType("int"); - b.Property("Reminder") - .HasColumnType("datetime2"); - b.Property("Title") .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.HasKey("Id"); - b.HasIndex("ListId"); + b.HasIndex("CategoryId"); - b.ToTable("TodoItems"); + b.ToTable("IssueTickets"); }); - modelBuilder.Entity("CodeClinic.Domain.Entities.TodoList", b => + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .UseIdentityColumn(); - b.Property("Colour") - .HasColumnType("nvarchar(max)"); + b.Property("CommentId") + .HasColumnType("int"); b.Property("Created") .HasColumnType("datetime2"); b.Property("CreatedBy") + .IsRequired() .HasColumnType("nvarchar(max)"); + b.Property("IsLiked") + .HasColumnType("bit"); + b.Property("LastModified") .HasColumnType("datetime2"); b.Property("LastModifiedBy") .HasColumnType("nvarchar(max)"); - b.Property("Title") - .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); - b.HasKey("Id"); - b.ToTable("TodoLists"); + b.HasIndex("CommentId"); + + b.ToTable("Likes"); }); modelBuilder.Entity("CodeClinic.Infrastructure.Identity.ApplicationUser", b => @@ -143,17 +178,32 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AccessFailedCount") .HasColumnType("int"); + b.Property("AvatarImage") + .HasColumnType("nvarchar(max)"); + + b.Property("Bio") + .HasColumnType("nvarchar(max)"); + b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("nvarchar(max)"); + b.Property("CoverImage") + .HasColumnType("nvarchar(max)"); + b.Property("Email") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("EmailConfirmed") .HasColumnType("bit"); + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("LastName") + .HasColumnType("nvarchar(max)"); + b.Property("LockoutEnabled") .HasColumnType("bit"); @@ -161,12 +211,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("datetimeoffset"); b.Property("NormalizedEmail") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("NormalizedUserName") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("PasswordHash") .HasColumnType("nvarchar(max)"); @@ -184,17 +234,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("bit"); b.Property("UserName") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.HasKey("Id"); b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); + .HasDatabaseName("EmailIndex"); b.HasIndex("NormalizedUserName") .IsUnique() - .HasName("UserNameIndex") + .HasDatabaseName("UserNameIndex") .HasFilter("[NormalizedUserName] IS NOT NULL"); b.ToTable("AspNetUsers"); @@ -203,34 +253,42 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => { b.Property("UserCode") - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("ClientId") .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("CreationTime") .HasColumnType("datetime2"); b.Property("Data") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(50000); + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("DeviceCode") .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("Expiration") .IsRequired() .HasColumnType("datetime2"); + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + b.Property("SubjectId") - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.HasKey("UserCode"); @@ -245,33 +303,44 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => { b.Property("Key") - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("ClientId") .IsRequired() - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("ConsumedTime") + .HasColumnType("datetime2"); b.Property("CreationTime") .HasColumnType("datetime2"); b.Property("Data") .IsRequired() - .HasColumnType("nvarchar(max)") - .HasMaxLength(50000); + .HasMaxLength(50000) + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("Expiration") .HasColumnType("datetime2"); + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + b.Property("SubjectId") - .HasColumnType("nvarchar(200)") - .HasMaxLength(200); + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); b.Property("Type") .IsRequired() - .HasColumnType("nvarchar(50)") - .HasMaxLength(50); + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); b.HasKey("Key"); @@ -279,6 +348,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SubjectId", "ClientId", "Type"); + b.HasIndex("SubjectId", "SessionId", "Type"); + b.ToTable("PersistedGrants"); }); @@ -292,18 +363,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(max)"); b.Property("Name") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.Property("NormalizedName") - .HasColumnType("nvarchar(256)") - .HasMaxLength(256); + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); b.HasKey("Id"); b.HasIndex("NormalizedName") .IsUnique() - .HasName("RoleNameIndex") + .HasDatabaseName("RoleNameIndex") .HasFilter("[NormalizedName] IS NOT NULL"); b.ToTable("AspNetRoles"); @@ -314,7 +385,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .UseIdentityColumn(); b.Property("ClaimType") .HasColumnType("nvarchar(max)"); @@ -338,7 +409,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("int") - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .UseIdentityColumn(); b.Property("ClaimType") .HasColumnType("nvarchar(max)"); @@ -360,12 +431,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { b.Property("LoginProvider") - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); b.Property("ProviderKey") - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); b.Property("ProviderDisplayName") .HasColumnType("nvarchar(max)"); @@ -402,12 +473,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(450)"); b.Property("LoginProvider") - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); b.Property("Name") - .HasColumnType("nvarchar(128)") - .HasMaxLength(128); + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); b.Property("Value") .HasColumnType("nvarchar(max)"); @@ -417,13 +488,38 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetUserTokens"); }); - modelBuilder.Entity("CodeClinic.Domain.Entities.TodoItem", b => + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.HasOne("CodeClinic.Domain.Entities.IssueTicket", "IssueTicket") + .WithMany("Comments") + .HasForeignKey("IssueTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IssueTicket"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.HasOne("CodeClinic.Domain.Entities.Category", "Category") + .WithMany("IssueTickets") + .HasForeignKey("CategoryId") + .HasConstraintName("CategoryIssueTickets") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Like", b => { - b.HasOne("CodeClinic.Domain.Entities.TodoList", "List") - .WithMany("Items") - .HasForeignKey("ListId") + b.HasOne("CodeClinic.Domain.Entities.Comment", "Comment") + .WithMany("Likes") + .HasForeignKey("CommentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Comment"); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => @@ -476,6 +572,21 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Category", b => + { + b.Navigation("IssueTickets"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.Comment", b => + { + b.Navigation("Likes"); + }); + + modelBuilder.Entity("CodeClinic.Domain.Entities.IssueTicket", b => + { + b.Navigation("Comments"); + }); #pragma warning restore 612, 618 } } diff --git a/src/WebUI/ClientApp/angular.json b/src/WebUI/ClientApp/angular.json index fa03730..d73c2cd 100644 --- a/src/WebUI/ClientApp/angular.json +++ b/src/WebUI/ClientApp/angular.json @@ -25,11 +25,12 @@ "src/assets" ], "styles": [ - "./node_modules/bootstrap/dist/css/bootstrap.min.css", + "./node_modules/bootswatch/dist/materia/bootstrap.min.css", "./node_modules/ngx-bootstrap/datepicker/bs-datepicker.css", "src/styles.css" ], - "scripts": [] + "scripts": [ + ] }, "configurations": { "production": { @@ -156,4 +157,4 @@ } }, "defaultProject": "CodeClinic.WebUI" -} \ No newline at end of file +} diff --git a/src/WebUI/ClientApp/package-lock.json b/src/WebUI/ClientApp/package-lock.json index 3a7ba06..0f0f1cb 100644 --- a/src/WebUI/ClientApp/package-lock.json +++ b/src/WebUI/ClientApp/package-lock.json @@ -3751,6 +3751,11 @@ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==" }, + "bootswatch": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-4.5.3.tgz", + "integrity": "sha512-gaB3gBSAegmYbk97aVELKcSKVdPjWsSY4yCITkUt/SqbqjtMU/HtIUszb4O9vzdbrfuVXThc/qCXzjoJaAPgiQ==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5103,6 +5108,23 @@ "assert-plus": "^1.0.0" } }, + "datatables.net": { + "version": "1.10.22", + "resolved": "https://registry.npmjs.org/datatables.net/-/datatables.net-1.10.22.tgz", + "integrity": "sha512-ujn8GvkQIBYzYH54XY7OrI0Zb35TKRd9ABYfbnXgBfwTGIFT6UsmXrfHU5Yk+MSDoF0sDu2TB+31V6c+zUZ0Pw==", + "requires": { + "jquery": ">=1.7" + } + }, + "datatables.net-bs4": { + "version": "1.10.22", + "resolved": "https://registry.npmjs.org/datatables.net-bs4/-/datatables.net-bs4-1.10.22.tgz", + "integrity": "sha512-si0eOiaKmuURURpXhPRba7b3vCZsVfJK8pfrlM5WtaOaCEBa62DG/S9guMxUBmcAmvEC3FA2CKc/iKya3gb9qg==", + "requires": { + "datatables.net": "1.10.22", + "jquery": ">=1.7" + } + }, "date-format": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", diff --git a/src/WebUI/ClientApp/package.json b/src/WebUI/ClientApp/package.json index c31cf63..f1b1be0 100644 --- a/src/WebUI/ClientApp/package.json +++ b/src/WebUI/ClientApp/package.json @@ -27,7 +27,9 @@ "@nguniversal/module-map-ngfactory-loader": "8.0.0-rc.1", "aspnet-prerendering": "^3.0.1", "bootstrap": "^4.3.1", + "bootswatch": "^4.5.3", "core-js": "^2.6.5", + "datatables.net-bs4": "^1.10.22", "jquery": "3.5.0", "ngx-bootstrap": "^5.2.0", "oidc-client": "^1.9.0", diff --git a/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.css b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.html b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.html new file mode 100644 index 0000000..826c8d3 --- /dev/null +++ b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.html @@ -0,0 +1,28 @@ + +
+
+
+
+ +
+
+
+
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+
+
+ diff --git a/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.spec.ts b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.spec.ts new file mode 100644 index 0000000..c5f08d4 --- /dev/null +++ b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginFormComponent } from './login-form.component'; + +describe('LoginFormComponent', () => { + let component: LoginFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LoginFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.ts b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.ts new file mode 100644 index 0000000..a1a6ec8 --- /dev/null +++ b/src/WebUI/ClientApp/src/api-authorization/login-form/login-form.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'login-form', + templateUrl: './login-form.component.html', + styleUrls: ['./login-form.component.css'] +}) +export class LoginFormComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/WebUI/ClientApp/src/api-authorization/login-menu/login-menu.component.html b/src/WebUI/ClientApp/src/api-authorization/login-menu/login-menu.component.html index 30fa656..e20934d 100644 --- a/src/WebUI/ClientApp/src/api-authorization/login-menu/login-menu.component.html +++ b/src/WebUI/ClientApp/src/api-authorization/login-menu/login-menu.component.html @@ -1,16 +1,16 @@ + diff --git a/src/WebUI/ClientApp/src/api-authorization/login/login.component.html b/src/WebUI/ClientApp/src/api-authorization/login/login.component.html index 5b5e4e4..b064212 100644 --- a/src/WebUI/ClientApp/src/api-authorization/login/login.component.html +++ b/src/WebUI/ClientApp/src/api-authorization/login/login.component.html @@ -1 +1,10 @@ -

{{ message | async }}

\ No newline at end of file +

{{ message | async }}

+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/CodeClinic-api.ts b/src/WebUI/ClientApp/src/app/CodeClinic-api.ts index 8846428..4fe6ba6 100644 --- a/src/WebUI/ClientApp/src/app/CodeClinic-api.ts +++ b/src/WebUI/ClientApp/src/app/CodeClinic-api.ts @@ -1,8 +1,8 @@ -/* tslint:disable */ +/* tslint:disable */ /* eslint-disable */ //---------------------- // -// Generated using the NSwag toolchain v13.3.0.0 (NJsonSchema v10.1.11.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// Generated using the NSwag toolchain v13.9.4.0 (NJsonSchema v10.3.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) // //---------------------- // ReSharper disable InconsistentNaming @@ -14,33 +14,34 @@ import { HttpClient, HttpHeaders, HttpResponse, HttpResponseBase } from '@angula export const API_BASE_URL = new InjectionToken('API_BASE_URL'); -export interface IIssuesClient { - getAll(): Observable; - create(command: CreateIssueCommand): Observable; - update(id: number, command: UpdateIssueCommand): Observable; +export interface ICategoriesClient { + getAll(): Observable; + create(command: CreateCategoryCommand): Observable; + getCategoryById(id: number): Observable; + update(id: string, command: UpdateCategoryCommand): Observable; delete(id: number): Observable; } @Injectable({ providedIn: 'root' }) -export class IssuesClient implements IIssuesClient { +export class CategoriesClient implements ICategoriesClient { private http: HttpClient; private baseUrl: string; protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) { this.http = http; - this.baseUrl = baseUrl ? baseUrl : ""; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; } - getAll(): Observable { - let url_ = this.baseUrl + "/api/Issues"; + getAll(): Observable { + let url_ = this.baseUrl + "/api/Categories"; url_ = url_.replace(/[?&]$/, ""); let options_ : any = { observe: "response", - responseType: "blob", + responseType: "blob", headers: new HttpHeaders({ "Accept": "application/json" }) @@ -53,25 +54,25 @@ export class IssuesClient implements IIssuesClient { try { return this.processGetAll(response_); } catch (e) { - return >_observableThrow(e); + return >_observableThrow(e); } } else - return >_observableThrow(response_); + return >_observableThrow(response_); })); } - protected processGetAll(response: HttpResponseBase): Observable { + protected processGetAll(response: HttpResponseBase): Observable { const status = response.status; - const responseBlob = - response instanceof HttpResponse ? response.body : + const responseBlob = + response instanceof HttpResponse ? response.body : (response).error instanceof Blob ? (response).error : undefined; - let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} if (status === 200) { return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { let result200: any = null; let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); - result200 = IssueListVm.fromJS(resultData200); + result200 = CategoryListVm.fromJS(resultData200); return _observableOf(result200); })); } else if (status !== 200 && status !== 204) { @@ -79,11 +80,11 @@ export class IssuesClient implements IIssuesClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); })); } - return _observableOf(null); + return _observableOf(null); } - create(command: CreateIssueCommand): Observable { - let url_ = this.baseUrl + "/api/Issues"; + create(command: CreateCategoryCommand): Observable { + let url_ = this.baseUrl + "/api/Categories"; url_ = url_.replace(/[?&]$/, ""); const content_ = JSON.stringify(command); @@ -91,9 +92,9 @@ export class IssuesClient implements IIssuesClient { let options_ : any = { body: content_, observe: "response", - responseType: "blob", + responseType: "blob", headers: new HttpHeaders({ - "Content-Type": "application/json", + "Content-Type": "application/json", "Accept": "application/json" }) }; @@ -114,11 +115,11 @@ export class IssuesClient implements IIssuesClient { protected processCreate(response: HttpResponseBase): Observable { const status = response.status; - const responseBlob = - response instanceof HttpResponse ? response.body : + const responseBlob = + response instanceof HttpResponse ? response.body : (response).error instanceof Blob ? (response).error : undefined; - let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} if (status === 200) { return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { let result200: any = null; @@ -134,11 +135,347 @@ export class IssuesClient implements IIssuesClient { return _observableOf(null); } - update(id: number, command: UpdateIssueCommand): Observable { - let url_ = this.baseUrl + "/api/Issues/{id}"; + getCategoryById(id: number): Observable { + let url_ = this.baseUrl + "/api/Categories/{id}"; if (id === undefined || id === null) throw new Error("The parameter 'id' must be defined."); - url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetCategoryById(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetCategoryById(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetCategoryById(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = CategoryDetailVm.fromJS(resultData200); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + update(id: string, command: UpdateCategoryCommand): Observable { + let url_ = this.baseUrl + "/api/Categories/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("put", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processUpdate(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processUpdate(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processUpdate(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + delete(id: number): Observable { + let url_ = this.baseUrl + "/api/Categories/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("delete", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processDelete(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processDelete(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processDelete(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } +} + +export interface ICommentsClient { + getAll(issueTicketId: number): Observable; + create(issueTicketId: number, command: CreateCommentCommand): Observable; + getCommentById(issueTicketId: number, id: number): Observable; + update(id: number, issueTicketId: string, command: UpdateCommentCommand): Observable; + delete(issueTicketId: number, id: number): Observable; +} + +@Injectable({ + providedIn: 'root' +}) +export class CommentsClient implements ICommentsClient { + private http: HttpClient; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) { + this.http = http; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + + getAll(issueTicketId: number): Observable { + let url_ = this.baseUrl + "/api/issueTickets/{issueTicketId}/Comments"; + if (issueTicketId === undefined || issueTicketId === null) + throw new Error("The parameter 'issueTicketId' must be defined."); + url_ = url_.replace("{issueTicketId}", encodeURIComponent("" + issueTicketId)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetAll(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetAll(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetAll(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = CommentListVm.fromJS(resultData200); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + create(issueTicketId: number, command: CreateCommentCommand): Observable { + let url_ = this.baseUrl + "/api/issueTickets/{issueTicketId}/Comments"; + if (issueTicketId === undefined || issueTicketId === null) + throw new Error("The parameter 'issueTicketId' must be defined."); + url_ = url_.replace("{issueTicketId}", encodeURIComponent("" + issueTicketId)); + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processCreate(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processCreate(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processCreate(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + getCommentById(issueTicketId: number, id: number): Observable { + let url_ = this.baseUrl + "/api/issueTickets/{issueTicketId}/Comments/{id}"; + if (issueTicketId === undefined || issueTicketId === null) + throw new Error("The parameter 'issueTicketId' must be defined."); + url_ = url_.replace("{issueTicketId}", encodeURIComponent("" + issueTicketId)); + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetCommentById(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetCommentById(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetCommentById(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = CommentDto.fromJS(resultData200); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + update(id: number, issueTicketId: string, command: UpdateCommentCommand): Observable { + let url_ = this.baseUrl + "/api/issueTickets/{issueTicketId}/Comments/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + if (issueTicketId === undefined || issueTicketId === null) + throw new Error("The parameter 'issueTicketId' must be defined."); + url_ = url_.replace("{issueTicketId}", encodeURIComponent("" + issueTicketId)); url_ = url_.replace(/[?&]$/, ""); const content_ = JSON.stringify(command); @@ -146,9 +483,9 @@ export class IssuesClient implements IIssuesClient { let options_ : any = { body: content_, observe: "response", - responseType: "blob", + responseType: "blob", headers: new HttpHeaders({ - "Content-Type": "application/json", + "Content-Type": "application/json", "Accept": "application/octet-stream" }) }; @@ -167,81 +504,1101 @@ export class IssuesClient implements IIssuesClient { })); } - protected processUpdate(response: HttpResponseBase): Observable { - const status = response.status; - const responseBlob = - response instanceof HttpResponse ? response.body : - (response).error instanceof Blob ? (response).error : undefined; + protected processUpdate(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + delete(issueTicketId: number, id: number): Observable { + let url_ = this.baseUrl + "/api/issueTickets/{issueTicketId}/Comments/{id}"; + if (issueTicketId === undefined || issueTicketId === null) + throw new Error("The parameter 'issueTicketId' must be defined."); + url_ = url_.replace("{issueTicketId}", encodeURIComponent("" + issueTicketId)); + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("delete", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processDelete(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processDelete(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processDelete(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } +} + +export interface IIssueTicketsClient { + getAll(): Observable; + create(command: CreateIssueTicketCommand): Observable; + getIssueTicketById(id: number): Observable; + update(id: number, command: UpdateIssueTicketCommand): Observable; + delete(id: number): Observable; + updateDetails(id: number | undefined, command: UpdateIssueTicketDetailsCommand): Observable; +} + +@Injectable({ + providedIn: 'root' +}) +export class IssueTicketsClient implements IIssueTicketsClient { + private http: HttpClient; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) { + this.http = http; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + + getAll(): Observable { + let url_ = this.baseUrl + "/api/IssueTickets"; + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetAll(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetAll(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetAll(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = IssueTicketListVm.fromJS(resultData200); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + create(command: CreateIssueTicketCommand): Observable { + let url_ = this.baseUrl + "/api/IssueTickets"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/json" + }) + }; + + return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processCreate(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processCreate(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processCreate(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = resultData200 !== undefined ? resultData200 : null; + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + getIssueTicketById(id: number): Observable { + let url_ = this.baseUrl + "/api/IssueTickets/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/json" + }) + }; + + return this.http.request("get", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processGetIssueTicketById(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processGetIssueTicketById(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processGetIssueTicketById(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + let result200: any = null; + let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver); + result200 = IssueTicketDetailVm.fromJS(resultData200); + return _observableOf(result200); + })); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + update(id: number, command: UpdateIssueTicketCommand): Observable { + let url_ = this.baseUrl + "/api/IssueTickets/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("put", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processUpdate(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processUpdate(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processUpdate(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + delete(id: number): Observable { + let url_ = this.baseUrl + "/api/IssueTickets/{id}"; + if (id === undefined || id === null) + throw new Error("The parameter 'id' must be defined."); + url_ = url_.replace("{id}", encodeURIComponent("" + id)); + url_ = url_.replace(/[?&]$/, ""); + + let options_ : any = { + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("delete", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processDelete(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processDelete(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processDelete(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + updateDetails(id: number | undefined, command: UpdateIssueTicketDetailsCommand): Observable { + let url_ = this.baseUrl + "/api/IssueTickets/UpdateDetails?"; + if (id === null) + throw new Error("The parameter 'id' cannot be null."); + else if (id !== undefined) + url_ += "id=" + encodeURIComponent("" + id) + "&"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("put", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processUpdateDetails(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processUpdateDetails(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processUpdateDetails(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } +} + +export interface ILikesClient { + createLike(commentId: number, command: CreateLikeCommand): Observable; + updateLike(id: number | undefined, commentId: string, command: UpdateLikeCommand): Observable; + deleteLike(commentId: string, command: DeleteLikeCommand): Observable; +} + +@Injectable({ + providedIn: 'root' +}) +export class LikesClient implements ILikesClient { + private http: HttpClient; + private baseUrl: string; + protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined; + + constructor(@Inject(HttpClient) http: HttpClient, @Optional() @Inject(API_BASE_URL) baseUrl?: string) { + this.http = http; + this.baseUrl = baseUrl !== undefined && baseUrl !== null ? baseUrl : ""; + } + + createLike(commentId: number, command: CreateLikeCommand): Observable { + let url_ = this.baseUrl + "/api/likes/{CommentId}/Likes"; + if (commentId === undefined || commentId === null) + throw new Error("The parameter 'commentId' must be defined."); + url_ = url_.replace("{commentId}", encodeURIComponent("" + commentId)); + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("post", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processCreateLike(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processCreateLike(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processCreateLike(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + updateLike(id: number | undefined, commentId: string, command: UpdateLikeCommand): Observable { + let url_ = this.baseUrl + "/api/likes/{CommentId}/Likes?"; + if (commentId === undefined || commentId === null) + throw new Error("The parameter 'commentId' must be defined."); + url_ = url_.replace("{CommentId}", encodeURIComponent("" + commentId)); + if (id === null) + throw new Error("The parameter 'id' cannot be null."); + else if (id !== undefined) + url_ += "id=" + encodeURIComponent("" + id) + "&"; + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("put", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processUpdateLike(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processUpdateLike(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processUpdateLike(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } + + deleteLike(commentId: string, command: DeleteLikeCommand): Observable { + let url_ = this.baseUrl + "/api/likes/{CommentId}/Likes"; + if (commentId === undefined || commentId === null) + throw new Error("The parameter 'commentId' must be defined."); + url_ = url_.replace("{CommentId}", encodeURIComponent("" + commentId)); + url_ = url_.replace(/[?&]$/, ""); + + const content_ = JSON.stringify(command); + + let options_ : any = { + body: content_, + observe: "response", + responseType: "blob", + headers: new HttpHeaders({ + "Content-Type": "application/json", + "Accept": "application/octet-stream" + }) + }; + + return this.http.request("delete", url_, options_).pipe(_observableMergeMap((response_ : any) => { + return this.processDeleteLike(response_); + })).pipe(_observableCatch((response_: any) => { + if (response_ instanceof HttpResponseBase) { + try { + return this.processDeleteLike(response_); + } catch (e) { + return >_observableThrow(e); + } + } else + return >_observableThrow(response_); + })); + } + + protected processDeleteLike(response: HttpResponseBase): Observable { + const status = response.status; + const responseBlob = + response instanceof HttpResponse ? response.body : + (response).error instanceof Blob ? (response).error : undefined; + + let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }} + if (status === 200 || status === 206) { + const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; + const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; + const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; + return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); + } else if (status !== 200 && status !== 204) { + return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + })); + } + return _observableOf(null); + } +} + +export class CategoryListVm implements ICategoryListVm { + categories?: CategoryDto[] | undefined; + + constructor(data?: ICategoryListVm) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + if (Array.isArray(_data["categories"])) { + this.categories = [] as any; + for (let item of _data["categories"]) + this.categories!.push(CategoryDto.fromJS(item)); + } + } + } + + static fromJS(data: any): CategoryListVm { + data = typeof data === 'object' ? data : {}; + let result = new CategoryListVm(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (Array.isArray(this.categories)) { + data["categories"] = []; + for (let item of this.categories) + data["categories"].push(item.toJSON()); + } + return data; + } +} + +export interface ICategoryListVm { + categories?: CategoryDto[] | undefined; +} + +export class CategoryDto implements ICategoryDto { + categoryId?: number; + name?: string | undefined; + description?: string | undefined; + + constructor(data?: ICategoryDto) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.categoryId = _data["categoryId"]; + this.name = _data["name"]; + this.description = _data["description"]; + } + } + + static fromJS(data: any): CategoryDto { + data = typeof data === 'object' ? data : {}; + let result = new CategoryDto(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["categoryId"] = this.categoryId; + data["name"] = this.name; + data["description"] = this.description; + return data; + } +} + +export interface ICategoryDto { + categoryId?: number; + name?: string | undefined; + description?: string | undefined; +} + +export class CategoryDetailVm implements ICategoryDetailVm { + categoryId?: number; + categoryName?: string | undefined; + categoryDescription?: string | undefined; + dateCreated?: Date; + lastModifiedBy?: string | undefined; + lastModified?: Date | undefined; + issuesTickets?: IssueTicketDto[] | undefined; + + constructor(data?: ICategoryDetailVm) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.categoryId = _data["categoryId"]; + this.categoryName = _data["categoryName"]; + this.categoryDescription = _data["categoryDescription"]; + this.dateCreated = _data["dateCreated"] ? new Date(_data["dateCreated"].toString()) : undefined; + this.lastModifiedBy = _data["lastModifiedBy"]; + this.lastModified = _data["lastModified"] ? new Date(_data["lastModified"].toString()) : undefined; + if (Array.isArray(_data["issuesTickets"])) { + this.issuesTickets = [] as any; + for (let item of _data["issuesTickets"]) + this.issuesTickets!.push(IssueTicketDto.fromJS(item)); + } + } + } + + static fromJS(data: any): CategoryDetailVm { + data = typeof data === 'object' ? data : {}; + let result = new CategoryDetailVm(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["categoryId"] = this.categoryId; + data["categoryName"] = this.categoryName; + data["categoryDescription"] = this.categoryDescription; + data["dateCreated"] = this.dateCreated ? this.dateCreated.toISOString() : undefined; + data["lastModifiedBy"] = this.lastModifiedBy; + data["lastModified"] = this.lastModified ? this.lastModified.toISOString() : undefined; + if (Array.isArray(this.issuesTickets)) { + data["issuesTickets"] = []; + for (let item of this.issuesTickets) + data["issuesTickets"].push(item.toJSON()); + } + return data; + } +} + +export interface ICategoryDetailVm { + categoryId?: number; + categoryName?: string | undefined; + categoryDescription?: string | undefined; + dateCreated?: Date; + lastModifiedBy?: string | undefined; + lastModified?: Date | undefined; + issuesTickets?: IssueTicketDto[] | undefined; +} + +export class IssueTicketDto implements IIssueTicketDto { + issueTicketId?: number; + categoryId?: number; + categoryName?: string | undefined; + title?: string | undefined; + stars?: number; + status?: number; + body?: string | undefined; + createdBy?: string | undefined; + dateCreated?: Date; + lastModifiedBy?: string | undefined; + lastModified?: Date | undefined; + + constructor(data?: IIssueTicketDto) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.issueTicketId = _data["issueTicketId"]; + this.categoryId = _data["categoryId"]; + this.categoryName = _data["categoryName"]; + this.title = _data["title"]; + this.stars = _data["stars"]; + this.status = _data["status"]; + this.body = _data["body"]; + this.createdBy = _data["createdBy"]; + this.dateCreated = _data["dateCreated"] ? new Date(_data["dateCreated"].toString()) : undefined; + this.lastModifiedBy = _data["lastModifiedBy"]; + this.lastModified = _data["lastModified"] ? new Date(_data["lastModified"].toString()) : undefined; + } + } + + static fromJS(data: any): IssueTicketDto { + data = typeof data === 'object' ? data : {}; + let result = new IssueTicketDto(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["issueTicketId"] = this.issueTicketId; + data["categoryId"] = this.categoryId; + data["categoryName"] = this.categoryName; + data["title"] = this.title; + data["stars"] = this.stars; + data["status"] = this.status; + data["body"] = this.body; + data["createdBy"] = this.createdBy; + data["dateCreated"] = this.dateCreated ? this.dateCreated.toISOString() : undefined; + data["lastModifiedBy"] = this.lastModifiedBy; + data["lastModified"] = this.lastModified ? this.lastModified.toISOString() : undefined; + return data; + } +} + +export interface IIssueTicketDto { + issueTicketId?: number; + categoryId?: number; + categoryName?: string | undefined; + title?: string | undefined; + stars?: number; + status?: number; + body?: string | undefined; + createdBy?: string | undefined; + dateCreated?: Date; + lastModifiedBy?: string | undefined; + lastModified?: Date | undefined; +} + +export class CreateCategoryCommand implements ICreateCategoryCommand { + id?: number; + name?: string | undefined; + description?: string | undefined; + + constructor(data?: ICreateCategoryCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.name = _data["name"]; + this.description = _data["description"]; + } + } + + static fromJS(data: any): CreateCategoryCommand { + data = typeof data === 'object' ? data : {}; + let result = new CreateCategoryCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["name"] = this.name; + data["description"] = this.description; + return data; + } +} + +export interface ICreateCategoryCommand { + id?: number; + name?: string | undefined; + description?: string | undefined; +} + +export class UpdateCategoryCommand implements IUpdateCategoryCommand { + id?: number; + name?: string | undefined; + description?: string | undefined; + + constructor(data?: IUpdateCategoryCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.name = _data["name"]; + this.description = _data["description"]; + } + } + + static fromJS(data: any): UpdateCategoryCommand { + data = typeof data === 'object' ? data : {}; + let result = new UpdateCategoryCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["name"] = this.name; + data["description"] = this.description; + return data; + } +} + +export interface IUpdateCategoryCommand { + id?: number; + name?: string | undefined; + description?: string | undefined; +} + +export class CommentListVm implements ICommentListVm { + items?: CommentDto[] | undefined; + + constructor(data?: ICommentListVm) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + if (Array.isArray(_data["items"])) { + this.items = [] as any; + for (let item of _data["items"]) + this.items!.push(CommentDto.fromJS(item)); + } + } + } + + static fromJS(data: any): CommentListVm { + data = typeof data === 'object' ? data : {}; + let result = new CommentListVm(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + if (Array.isArray(this.items)) { + data["items"] = []; + for (let item of this.items) + data["items"].push(item.toJSON()); + } + return data; + } +} + +export interface ICommentListVm { + items?: CommentDto[] | undefined; +} + +export class CommentDto implements ICommentDto { + commentId?: number; + issueTicketId?: number; + title?: string | undefined; + description?: string | undefined; + + constructor(data?: ICommentDto) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.commentId = _data["commentId"]; + this.issueTicketId = _data["issueTicketId"]; + this.title = _data["title"]; + this.description = _data["description"]; + } + } + + static fromJS(data: any): CommentDto { + data = typeof data === 'object' ? data : {}; + let result = new CommentDto(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["commentId"] = this.commentId; + data["issueTicketId"] = this.issueTicketId; + data["title"] = this.title; + data["description"] = this.description; + return data; + } +} + +export interface ICommentDto { + commentId?: number; + issueTicketId?: number; + title?: string | undefined; + description?: string | undefined; +} - let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; - if (status === 200 || status === 206) { - const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; - const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; - const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; - return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); - } else if (status !== 200 && status !== 204) { - return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { - return throwException("An unexpected server error occurred.", status, _responseText, _headers); - })); +export class CreateCommentCommand implements ICreateCommentCommand { + issueTicketId?: number; + title?: string | undefined; + description?: string | undefined; + + constructor(data?: ICreateCommentCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } } - return _observableOf(null); } - delete(id: number): Observable { - let url_ = this.baseUrl + "/api/Issues/{id}"; - if (id === undefined || id === null) - throw new Error("The parameter 'id' must be defined."); - url_ = url_.replace("{id}", encodeURIComponent("" + id)); - url_ = url_.replace(/[?&]$/, ""); + init(_data?: any) { + if (_data) { + this.issueTicketId = _data["issueTicketId"]; + this.title = _data["title"]; + this.description = _data["description"]; + } + } - let options_ : any = { - observe: "response", - responseType: "blob", - headers: new HttpHeaders({ - "Accept": "application/octet-stream" - }) - }; + static fromJS(data: any): CreateCommentCommand { + data = typeof data === 'object' ? data : {}; + let result = new CreateCommentCommand(); + result.init(data); + return result; + } - return this.http.request("delete", url_, options_).pipe(_observableMergeMap((response_ : any) => { - return this.processDelete(response_); - })).pipe(_observableCatch((response_: any) => { - if (response_ instanceof HttpResponseBase) { - try { - return this.processDelete(response_); - } catch (e) { - return >_observableThrow(e); - } - } else - return >_observableThrow(response_); - })); + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["issueTicketId"] = this.issueTicketId; + data["title"] = this.title; + data["description"] = this.description; + return data; } +} - protected processDelete(response: HttpResponseBase): Observable { - const status = response.status; - const responseBlob = - response instanceof HttpResponse ? response.body : - (response).error instanceof Blob ? (response).error : undefined; +export interface ICreateCommentCommand { + issueTicketId?: number; + title?: string | undefined; + description?: string | undefined; +} - let _headers: any = {}; if (response.headers) { for (let key of response.headers.keys()) { _headers[key] = response.headers.get(key); }}; - if (status === 200 || status === 206) { - const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined; - const fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined; - const fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined; - return _observableOf({ fileName: fileName, data: responseBlob, status: status, headers: _headers }); - } else if (status !== 200 && status !== 204) { - return blobToText(responseBlob).pipe(_observableMergeMap(_responseText => { - return throwException("An unexpected server error occurred.", status, _responseText, _headers); - })); +export class UpdateCommentCommand implements IUpdateCommentCommand { + issueTicketId?: number; + commentId?: number; + title?: string | undefined; + description?: string | undefined; + + constructor(data?: IUpdateCommentCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } } - return _observableOf(null); } + + init(_data?: any) { + if (_data) { + this.issueTicketId = _data["issueTicketId"]; + this.commentId = _data["commentId"]; + this.title = _data["title"]; + this.description = _data["description"]; + } + } + + static fromJS(data: any): UpdateCommentCommand { + data = typeof data === 'object' ? data : {}; + let result = new UpdateCommentCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["issueTicketId"] = this.issueTicketId; + data["commentId"] = this.commentId; + data["title"] = this.title; + data["description"] = this.description; + return data; + } +} + +export interface IUpdateCommentCommand { + issueTicketId?: number; + commentId?: number; + title?: string | undefined; + description?: string | undefined; } -export class IssueListVm implements IIssueListVm { +export class IssueTicketListVm implements IIssueTicketListVm { progressStatuses?: ProgressStatusDto[] | undefined; - issues?: IssueDto[] | undefined; + issues?: IssueTicketDto[] | undefined; - constructor(data?: IIssueListVm) { + constructor(data?: IIssueTicketListVm) { if (data) { for (var property in data) { if (data.hasOwnProperty(property)) @@ -260,14 +1617,14 @@ export class IssueListVm implements IIssueListVm { if (Array.isArray(_data["issues"])) { this.issues = [] as any; for (let item of _data["issues"]) - this.issues!.push(IssueDto.fromJS(item)); + this.issues!.push(IssueTicketDto.fromJS(item)); } } } - static fromJS(data: any): IssueListVm { + static fromJS(data: any): IssueTicketListVm { data = typeof data === 'object' ? data : {}; - let result = new IssueListVm(); + let result = new IssueTicketListVm(); result.init(data); return result; } @@ -288,9 +1645,9 @@ export class IssueListVm implements IIssueListVm { } } -export interface IIssueListVm { +export interface IIssueTicketListVm { progressStatuses?: ProgressStatusDto[] | undefined; - issues?: IssueDto[] | undefined; + issues?: IssueTicketDto[] | undefined; } export class ProgressStatusDto implements IProgressStatusDto { @@ -333,14 +1690,17 @@ export interface IProgressStatusDto { name?: string | undefined; } -export class IssueDto implements IIssueDto { - id?: number; +export class IssueTicketDetailVm implements IIssueTicketDetailVm { + categoryId?: number; + issueTicketId?: number; title?: string | undefined; stars?: number; - status?: number; body?: string | undefined; + status?: ProgressStatus; + categoryName?: string | undefined; + comments?: CommentDto[] | undefined; - constructor(data?: IIssueDto) { + constructor(data?: IIssueTicketDetailVm) { if (data) { for (var property in data) { if (data.hasOwnProperty(property)) @@ -351,45 +1711,70 @@ export class IssueDto implements IIssueDto { init(_data?: any) { if (_data) { - this.id = _data["id"]; + this.categoryId = _data["categoryId"]; + this.issueTicketId = _data["issueTicketId"]; this.title = _data["title"]; this.stars = _data["stars"]; - this.status = _data["status"]; this.body = _data["body"]; + this.status = _data["status"]; + this.categoryName = _data["categoryName"]; + if (Array.isArray(_data["comments"])) { + this.comments = [] as any; + for (let item of _data["comments"]) + this.comments!.push(CommentDto.fromJS(item)); + } } } - static fromJS(data: any): IssueDto { + static fromJS(data: any): IssueTicketDetailVm { data = typeof data === 'object' ? data : {}; - let result = new IssueDto(); + let result = new IssueTicketDetailVm(); result.init(data); return result; } toJSON(data?: any) { data = typeof data === 'object' ? data : {}; - data["id"] = this.id; + data["categoryId"] = this.categoryId; + data["issueTicketId"] = this.issueTicketId; data["title"] = this.title; data["stars"] = this.stars; - data["status"] = this.status; data["body"] = this.body; + data["status"] = this.status; + data["categoryName"] = this.categoryName; + if (Array.isArray(this.comments)) { + data["comments"] = []; + for (let item of this.comments) + data["comments"].push(item.toJSON()); + } return data; } } -export interface IIssueDto { - id?: number; +export interface IIssueTicketDetailVm { + categoryId?: number; + issueTicketId?: number; title?: string | undefined; stars?: number; - status?: number; body?: string | undefined; + status?: ProgressStatus; + categoryName?: string | undefined; + comments?: CommentDto[] | undefined; +} + +export enum ProgressStatus { + NotAnswered = 0, + InDiscussion = 1, + Answered = 2, } -export class CreateIssueCommand implements ICreateIssueCommand { +export class CreateIssueTicketCommand implements ICreateIssueTicketCommand { + id?: number; title?: string | undefined; + categoryId?: number; body?: string | undefined; - constructor(data?: ICreateIssueCommand) { + constructor(data?: ICreateIssueTicketCommand) { if (data) { for (var property in data) { if (data.hasOwnProperty(property)) @@ -400,38 +1785,92 @@ export class CreateIssueCommand implements ICreateIssueCommand { init(_data?: any) { if (_data) { + this.id = _data["id"]; this.title = _data["title"]; + this.categoryId = _data["categoryId"]; this.body = _data["body"]; } } - static fromJS(data: any): CreateIssueCommand { + static fromJS(data: any): CreateIssueTicketCommand { data = typeof data === 'object' ? data : {}; - let result = new CreateIssueCommand(); + let result = new CreateIssueTicketCommand(); result.init(data); return result; } toJSON(data?: any) { data = typeof data === 'object' ? data : {}; + data["id"] = this.id; data["title"] = this.title; + data["categoryId"] = this.categoryId; data["body"] = this.body; return data; } } -export interface ICreateIssueCommand { +export interface ICreateIssueTicketCommand { + id?: number; title?: string | undefined; + categoryId?: number; body?: string | undefined; } -export class UpdateIssueCommand implements IUpdateIssueCommand { +export class UpdateIssueTicketCommand implements IUpdateIssueTicketCommand { id?: number; - title?: string | undefined; + categoryId?: number; + stars?: number; + status?: ProgressStatus; + + constructor(data?: IUpdateIssueTicketCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.id = _data["id"]; + this.categoryId = _data["categoryId"]; + this.stars = _data["stars"]; + this.status = _data["status"]; + } + } + + static fromJS(data: any): UpdateIssueTicketCommand { + data = typeof data === 'object' ? data : {}; + let result = new UpdateIssueTicketCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["id"] = this.id; + data["categoryId"] = this.categoryId; + data["stars"] = this.stars; + data["status"] = this.status; + return data; + } +} + +export interface IUpdateIssueTicketCommand { + id?: number; + categoryId?: number; + stars?: number; status?: ProgressStatus; +} + +export class UpdateIssueTicketDetailsCommand implements IUpdateIssueTicketDetailsCommand { + id?: number; + title?: string | undefined; + categoryId?: number; body?: string | undefined; - constructor(data?: IUpdateIssueCommand) { + constructor(data?: IUpdateIssueTicketDetailsCommand) { if (data) { for (var property in data) { if (data.hasOwnProperty(property)) @@ -444,14 +1883,14 @@ export class UpdateIssueCommand implements IUpdateIssueCommand { if (_data) { this.id = _data["id"]; this.title = _data["title"]; - this.status = _data["status"]; + this.categoryId = _data["categoryId"]; this.body = _data["body"]; } } - static fromJS(data: any): UpdateIssueCommand { + static fromJS(data: any): UpdateIssueTicketDetailsCommand { data = typeof data === 'object' ? data : {}; - let result = new UpdateIssueCommand(); + let result = new UpdateIssueTicketDetailsCommand(); result.init(data); return result; } @@ -460,23 +1899,125 @@ export class UpdateIssueCommand implements IUpdateIssueCommand { data = typeof data === 'object' ? data : {}; data["id"] = this.id; data["title"] = this.title; - data["status"] = this.status; + data["categoryId"] = this.categoryId; data["body"] = this.body; return data; } } -export interface IUpdateIssueCommand { +export interface IUpdateIssueTicketDetailsCommand { id?: number; title?: string | undefined; - status?: ProgressStatus; + categoryId?: number; body?: string | undefined; } -export enum ProgressStatus { - NotAnswered = 0, - InDiscussion = 1, - Answered = 2, +export class CreateLikeCommand implements ICreateLikeCommand { + commentId?: number; + + constructor(data?: ICreateLikeCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.commentId = _data["commentId"]; + } + } + + static fromJS(data: any): CreateLikeCommand { + data = typeof data === 'object' ? data : {}; + let result = new CreateLikeCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["commentId"] = this.commentId; + return data; + } +} + +export interface ICreateLikeCommand { + commentId?: number; +} + +export class UpdateLikeCommand implements IUpdateLikeCommand { + likeId?: number; + + constructor(data?: IUpdateLikeCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.likeId = _data["likeId"]; + } + } + + static fromJS(data: any): UpdateLikeCommand { + data = typeof data === 'object' ? data : {}; + let result = new UpdateLikeCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["likeId"] = this.likeId; + return data; + } +} + +export interface IUpdateLikeCommand { + likeId?: number; +} + +export class DeleteLikeCommand implements IDeleteLikeCommand { + likeId?: number; + + constructor(data?: IDeleteLikeCommand) { + if (data) { + for (var property in data) { + if (data.hasOwnProperty(property)) + (this)[property] = (data)[property]; + } + } + } + + init(_data?: any) { + if (_data) { + this.likeId = _data["likeId"]; + } + } + + static fromJS(data: any): DeleteLikeCommand { + data = typeof data === 'object' ? data : {}; + let result = new DeleteLikeCommand(); + result.init(data); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["likeId"] = this.likeId; + return data; + } +} + +export interface IDeleteLikeCommand { + likeId?: number; } export interface FileResponse { @@ -488,10 +2029,10 @@ export interface FileResponse { export class SwaggerException extends Error { message: string; - status: number; - response: string; + status: number; + response: string; headers: { [key: string]: any; }; - result: any; + result: any; constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) { super(); @@ -523,12 +2064,12 @@ function blobToText(blob: any): Observable { observer.next(""); observer.complete(); } else { - let reader = new FileReader(); - reader.onload = event => { + let reader = new FileReader(); + reader.onload = event => { observer.next((event.target).result); observer.complete(); }; - reader.readAsText(blob); + reader.readAsText(blob); } }); } \ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/app.component.html b/src/WebUI/ClientApp/src/app/app.component.html index 7173845..f71f158 100644 --- a/src/WebUI/ClientApp/src/app/app.component.html +++ b/src/WebUI/ClientApp/src/app/app.component.html @@ -1,6 +1,4 @@ -
- -
+ diff --git a/src/WebUI/ClientApp/src/app/app.module.ts b/src/WebUI/ClientApp/src/app/app.module.ts index cd549bd..ce2fca1 100644 --- a/src/WebUI/ClientApp/src/app/app.module.ts +++ b/src/WebUI/ClientApp/src/app/app.module.ts @@ -2,7 +2,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; -import { RouterModule } from '@angular/router'; +import { RouterModule, CanActivate } from '@angular/router'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { AppComponent } from './app.component'; @@ -13,12 +13,26 @@ import { AuthorizeGuard } from 'src/api-authorization/authorize.guard'; import { AuthorizeInterceptor } from 'src/api-authorization/authorize.interceptor'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { ModalModule } from 'ngx-bootstrap/modal'; +import { SummaryPipe } from '../pipes/summary/summary.pipe'; +import { LoginFormComponent } from '../api-authorization/login-form/login-form.component'; +import { LoaderComponent } from './components/loader/loader.component'; +import { PostDetailComponent } from './issue-tickets/post-detail/post-detail.component'; +import { NotFoundComponent } from './components/not-found/not-found.component'; +import { PostFormComponent } from './components/post-form/post-form.component'; +import { PostsComponent } from './issue-tickets/posts.component'; @NgModule({ declarations: [ AppComponent, NavMenuComponent, - HomeComponent + HomeComponent, + SummaryPipe, + LoginFormComponent, + PostsComponent, + LoaderComponent, + PostDetailComponent, + NotFoundComponent, + PostFormComponent ], imports: [ BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), @@ -27,7 +41,25 @@ import { ModalModule } from 'ngx-bootstrap/modal'; FormsModule, ApiAuthorizationModule, RouterModule.forRoot([ - { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [AuthorizeGuard] }, + { + path: '', + component: HomeComponent, + pathMatch: 'full' + }, + { + path: 'login', + component: LoginFormComponent + }, + { + path: 'posts/:title/:issueTicketId', + component: PostDetailComponent, + canActivate: [AuthorizeGuard] + }, + + { + path: '**', + component: NotFoundComponent + }, ]), BrowserAnimationsModule, ModalModule.forRoot() diff --git a/src/WebUI/ClientApp/src/app/components/loader/loader.component.css b/src/WebUI/ClientApp/src/app/components/loader/loader.component.css new file mode 100644 index 0000000..f23273f --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/loader/loader.component.css @@ -0,0 +1,23 @@ +#circle { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 150px; + height: 150px +} + +.loader { + width: calc(100% - 0px); + height: calc(100% - 0px); + border: 8px solid #afe1f0; + border-top: 8px solid #09f; + border-radius: 50%; + animation: rotate 5s linear infinite +} + +@keyframes rotate { + 100% { + transform: rotate(360deg) + } +} \ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/components/loader/loader.component.html b/src/WebUI/ClientApp/src/app/components/loader/loader.component.html new file mode 100644 index 0000000..aaba403 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/loader/loader.component.html @@ -0,0 +1,9 @@ +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/components/loader/loader.component.spec.ts b/src/WebUI/ClientApp/src/app/components/loader/loader.component.spec.ts new file mode 100644 index 0000000..35adf49 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/loader/loader.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoaderComponent } from './loader.component'; + +describe('LoaderComponent', () => { + let component: LoaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LoaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LoaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/WebUI/ClientApp/src/app/components/loader/loader.component.ts b/src/WebUI/ClientApp/src/app/components/loader/loader.component.ts new file mode 100644 index 0000000..743a119 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/loader/loader.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-loader', + templateUrl: './loader.component.html', + styleUrls: ['./loader.component.css'] +}) +export class LoaderComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.css b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.html b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.html new file mode 100644 index 0000000..8071020 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.html @@ -0,0 +1 @@ +

not-found works!

diff --git a/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.spec.ts b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.spec.ts new file mode 100644 index 0000000..35189ed --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NotFoundComponent } from './not-found.component'; + +describe('NotFoundComponent', () => { + let component: NotFoundComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NotFoundComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NotFoundComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.ts b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.ts new file mode 100644 index 0000000..33da0a4 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/not-found/not-found.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-not-found', + templateUrl: './not-found.component.html', + styleUrls: ['./not-found.component.css'] +}) +export class NotFoundComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.css b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.css new file mode 100644 index 0000000..5a281ab --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.css @@ -0,0 +1,5 @@ + +.form-control.ng-touched.ng-invalid{ + border : 2px solid red; + border-radius : 4px; +} diff --git a/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.html b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.html new file mode 100644 index 0000000..ae8c24f --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.html @@ -0,0 +1,91 @@ + diff --git a/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.spec.ts b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.spec.ts new file mode 100644 index 0000000..464aa7f --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PostFormComponent } from './post-form.component'; + +describe('PostFormComponent', () => { + let component: PostFormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PostFormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PostFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.ts b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.ts new file mode 100644 index 0000000..1c8292f --- /dev/null +++ b/src/WebUI/ClientApp/src/app/components/post-form/post-form.component.ts @@ -0,0 +1,52 @@ +import { CreateIssueTicketCommand, IssueTicketsClient } from './../../CodeClinic-api'; +import { Component, OnInit, Output } from '@angular/core'; +import { IssueTicketDto, IIssueTicketDto, CategoriesClient, CategoryListVm, CategoryDto } from '../../CodeClinic-api'; +import { NgForm } from '@angular/forms'; +import { EventEmitter } from 'events'; + +@Component({ + selector: 'app-post-form', + templateUrl: './post-form.component.html', + styleUrls: ['./post-form.component.css'] +}) +export class PostFormComponent implements OnInit { + + IssueTicketDto : IIssueTicketDto; + categories: CategoryDto[]; + @Output("submitted") submitted = new EventEmitter(); + + constructor(private client: IssueTicketsClient, private categoriesclient: CategoriesClient) { } + + publish(form : NgForm) { + console.log(form); + + let post = new IssueTicketDto(); + post.title = form.value.title; + post.body = form.value.body; + post.categoryId = form.value.categoryId; + + this.client.create(post).subscribe( + response => { + console.log(response); + + }, (error: Response) => { + if (error.status === 401) { + alert("Failed to publish because your session has expired,quick remedy logout and login again") + } else if (error.status === 500) { + alert("falied to publish. due to internal server error"); + } + alert("An unexpected error occured"); + console.log(error); + } + ); + } + ngOnInit(): void { + + this.categoriesclient.getAll().subscribe( + result => { + this.categories = result.categories; + } + ) + } + +} diff --git a/src/WebUI/ClientApp/src/app/home/home.component.css b/src/WebUI/ClientApp/src/app/home/home.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/WebUI/ClientApp/src/app/home/home.component.html b/src/WebUI/ClientApp/src/app/home/home.component.html index e086d04..3c115d8 100644 --- a/src/WebUI/ClientApp/src/app/home/home.component.html +++ b/src/WebUI/ClientApp/src/app/home/home.component.html @@ -1,11 +1,93 @@ -

Welcome to the Code Clinic

-

Lets help debug your Code

+
+
+
+
+
+

Welcome to the Code Clinic

+

+ Don't die of code frustration when devs exist all over the world. + Join a Community of highly Creative individuals who are always willing to help +

+

+ Login + Sign up +

+
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+
@AdminAdmin
+
Name : Admin clinic
+
About : Developer of web applications, JavaScript, PHP, Java, Python, Ruby, Java, Node.js, etc. +
+
+
    +
  • +
    Followers
    +
    5.2342
    +
  • +
  • +
    Following
    +
    6758
    +
  • +
+
+
+
+
-
-
    -
  • - {{issue.Title}} -
  • -
-
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ + diff --git a/src/WebUI/ClientApp/src/app/home/home.component.ts b/src/WebUI/ClientApp/src/app/home/home.component.ts index 6a311ea..574e6e2 100644 --- a/src/WebUI/ClientApp/src/app/home/home.component.ts +++ b/src/WebUI/ClientApp/src/app/home/home.component.ts @@ -1,18 +1,23 @@ -import { Component } from '@angular/core'; -import { IssueListVm, IssuesClient } from '../CodeClinic-api'; +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { AuthorizeService } from '../../api-authorization/authorize.service'; +import { map } from 'rxjs/operators'; @Component({ selector: 'app-home', templateUrl: './home.component.html', + styleUrls: ['./home.component.css'] }) -export class HomeComponent { +export class HomeComponent implements OnInit { - issuesListvm: IssueListVm; - - constructor(private client: IssuesClient ) { - this.client.getAll().subscribe(result => { - this.issuesListvm = result; - }, error => console.error(error)); + public isAuthenticated: Observable; + public userName: Observable; + + constructor(private authorizeService: AuthorizeService) { } + + ngOnInit() { + this.isAuthenticated = this.authorizeService.isAuthenticated(); + this.userName = this.authorizeService.getUser().pipe(map(u => u && u.name)); } } diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.css b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.css new file mode 100644 index 0000000..f666e4a --- /dev/null +++ b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.css @@ -0,0 +1,312 @@ +body{margin-top:20px;} + +.user-info-wrapper { + position: relative; + width: 100%; + margin-bottom: -1px; + padding-top: 90px; + padding-bottom: 30px; + border: 1px solid #e1e7ec; + border-top-left-radius: 7px; + border-top-right-radius: 7px; + overflow: hidden +} + +.user-info-wrapper .user-cover { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 120px; + background-position: center; + background-color: #f5f5f5; + background-repeat: no-repeat; + background-size: cover +} + +.user-info-wrapper .user-cover .tooltip .tooltip-inner { + width: 230px; + max-width: 100%; + padding: 10px 15px +} + +.user-info-wrapper .info-label { + display: block; + position: absolute; + top: 18px; + right: 18px; + height: 26px; + padding: 0 12px; + border-radius: 13px; + background-color: #fff; + color: #606975; + font-size: 12px; + line-height: 26px; + box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.18); + cursor: pointer +} + +.user-info-wrapper .info-label>i { + display: inline-block; + margin-right: 3px; + font-size: 1.2em; + vertical-align: middle +} + +.user-info-wrapper .user-info { + display: table; + position: relative; + width: 100%; + padding: 0 18px; + z-index: 5 +} + +.user-info-wrapper .user-info .user-avatar, +.user-info-wrapper .user-info .user-data { + display: table-cell; + vertical-align: top +} + +.user-info-wrapper .user-info .user-avatar { + position: relative; + width: 115px +} + +.user-info-wrapper .user-info .user-avatar>img { + display: block; + width: 100%; + border: 5px solid #fff; + border-radius: 50% +} + +.user-info-wrapper .user-info .user-avatar .edit-avatar { + display: block; + position: absolute; + top: -2px; + right: 2px; + width: 36px; + height: 36px; + transition: opacity .3s; + border-radius: 50%; + background-color: #fff; + color: #606975; + line-height: 34px; + box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2); + cursor: pointer; + opacity: 0; + text-align: center; + text-decoration: none +} + +.user-info-wrapper .user-info .user-avatar .edit-avatar::before { + font-family: feather; + font-size: 17px; + content: '\e058' +} + +.user-info-wrapper .user-info .user-avatar:hover .edit-avatar { + opacity: 1 +} + +.user-info-wrapper .user-info .user-data { + padding-top: 48px; + padding-left: 12px +} + +.user-info-wrapper .user-info .user-data h4 { + margin-bottom: 2px +} + +.user-info-wrapper .user-info .user-data span { + display: block; + color: #9da9b9; + font-size: 13px +} + +.user-info-wrapper+.list-group .list-group-item:first-child { + border-radius: 0 +} + +.user-info-wrapper+.list-group .list-group-item:first-child { + border-radius: 0; +} +.list-group-item:first-child { + border-top-left-radius: 7px; + border-top-right-radius: 7px; +} +.list-group-item:first-child { + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; +} +a.list-group-item { + padding-top: .87rem; + padding-bottom: .87rem; +} +a.list-group-item, .list-group-item-action { + transition: all .25s; + color: #606975; + font-weight: 500; +} +.with-badge { + position: relative; + padding-right: 3.3rem; +} +.list-group-item { + border-color: #e1e7ec; + background-color: #fff; + text-decoration: none; +} +.list-group-item { + position: relative; + display: block; + padding: .75rem 1.25rem; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid rgba(0,0,0,0.125); +} + +.badge.badge-primary { + background-color: #0da9ef; +} +.with-badge .badge { + position: absolute; + top: 50%; + right: 1.15rem; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} +.list-group-item i { + margin-top: -4px; + margin-right: 8px; + font-size: 1.1em; +} + + + +.comment { + display: block; + position: relative; + margin-bottom: 30px; + padding-left: 66px +} + +.comment .comment-author-ava { + display: block; + position: absolute; + top: 0; + left: 0; + width: 50px; + border-radius: 50%; + overflow: hidden +} + +.comment .comment-author-ava>img { + display: block; + width: 100% +} + +.comment .comment-body { + position: relative; + padding: 24px; + border: 1px solid #e1e7ec; + border-radius: 7px; + background-color: #fff +} + +.comment .comment-body::after, +.comment .comment-body::before { + position: absolute; + top: 12px; + right: 100%; + width: 0; + height: 0; + border: solid transparent; + content: ''; + pointer-events: none +} + +.comment .comment-body::after { + border-width: 9px; + border-color: transparent; + border-right-color: #fff +} + +.comment .comment-body::before { + margin-top: -1px; + border-width: 10px; + border-color: transparent; + border-right-color: #e1e7ec +} + +.comment .comment-title { + margin-bottom: 8px; + color: #606975; + font-size: 14px; + font-weight: 500 +} + +.comment .comment-text { + margin-bottom: 12px +} + +.comment .comment-footer { + display: table; + width: 100% +} + +.comment .comment-footer>.column { + display: table-cell; + vertical-align: middle +} + +.comment .comment-footer>.column:last-child { + text-align: right +} + +.comment .comment-meta { + color: #9da9b9; + font-size: 13px +} + +.comment .reply-link { + transition: color .3s; + color: #606975; + font-size: 14px; + font-weight: 500; + letter-spacing: .07em; + text-transform: uppercase; + text-decoration: none +} + +.comment .reply-link>i { + display: inline-block; + margin-top: -3px; + margin-right: 4px; + vertical-align: middle +} + +.comment .reply-link:hover { + color: #0da9ef +} + +.comment.comment-reply { + margin-top: 30px; + margin-bottom: 0 +} + +@media (max-width: 576px) { + .comment { + padding-left: 0 + } + .comment .comment-author-ava { + display: none + } + .comment .comment-body { + padding: 15px + } + .comment .comment-body::before, + .comment .comment-body::after { + display: none + } +} \ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.html b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.html new file mode 100644 index 0000000..1c85c84 --- /dev/null +++ b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.html @@ -0,0 +1,114 @@ +
+
+

{{issueTicket.title}}

+

{{issueTicket.body}}

+
+ +
+ + +
+ +
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + +
CategoryDate SubmittedLast UpdatedPriorityStatus
{{issueTicket.categoryName}}08/08/2017 08/14/2017HighOpen
+
+ +
+
Avatar
+
+ {{comment.title}} +
+

+ {{comment.description}} +

+ +
+
+ +
Leave Message
+
+
+ +
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.ts b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.ts new file mode 100644 index 0000000..dfdfeea --- /dev/null +++ b/src/WebUI/ClientApp/src/app/issue-tickets/post-detail/post-detail.component.ts @@ -0,0 +1,38 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { IssueTicketsClient, IssueTicketDetailVm } from '../../CodeClinic-api'; + +@Component({ + selector: 'post-detail', + templateUrl: './post-detail.component.html', + styleUrls: ['./post-detail.component.css'] +}) +export class PostDetailComponent implements OnInit { + + id: number; + issueTicket: IssueTicketDetailVm; + constructor(private route: ActivatedRoute, private client : IssueTicketsClient) { + + } + + ngOnInit(): void { + + this.route.paramMap.subscribe(params => { + this.id = +params.get('issueTicketId'); + }), + this.client.getIssueTicketById(this.id).subscribe( + result => { + this.issueTicket = result; + }); + this.scrollToTop(); + } + + + scrollToTop() { + var currentScroll = document.documentElement.scrollTop || document.body.scrollTop; + if (currentScroll > 0) { + + window.scrollTo(0, currentScroll - (currentScroll / 8)); + } + } +} diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.css b/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.html b/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.html new file mode 100644 index 0000000..d979f4b --- /dev/null +++ b/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.html @@ -0,0 +1,65 @@ + + + + +
+ +
+ + + + + + diff --git a/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.ts b/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.ts new file mode 100644 index 0000000..2841e3c --- /dev/null +++ b/src/WebUI/ClientApp/src/app/issue-tickets/posts.component.ts @@ -0,0 +1,35 @@ +import { Component, OnInit } from '@angular/core'; +import { IssueTicketsClient, IIssueTicketDto, IIssueTicketDetailVm } from '../CodeClinic-api'; + +@Component({ + selector: 'posts', + templateUrl: './posts.component.html', + styleUrls: ['./posts.component.css'] +}) +export class PostsComponent implements OnInit { + + images = [ + '3765114/pexels-photo-3765114.jpeg', + '3779448/pexels-photo-3779448.jpeg', + '415829/pexels-photo-415829.jpeg']; + tickets: IIssueTicketDto[]; + selectedTicket: IIssueTicketDetailVm; + constructor(private client :IssueTicketsClient) { } + + ngOnInit(): void { + + this.client.getAll().subscribe(result => { + this.tickets = result.issues; + }); + } + displayDetails(id: number) { + + } +} + + +enum Status{ + NotAnswered = 0, + InDiscussion = 1, + Answered = 2 +} \ No newline at end of file diff --git a/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.css b/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.css index 10389ef..e69de29 100644 --- a/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.css +++ b/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.css @@ -1,18 +0,0 @@ -a.navbar-brand { - white-space: normal; - text-align: center; - word-break: break-all; -} - -html { - font-size: 14px; -} -@media (min-width: 768px) { - html { - font-size: 16px; - } -} - -.box-shadow { - box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); -} diff --git a/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.html b/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.html index 0178be5..5cbcdd3 100644 --- a/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.html +++ b/src/WebUI/ClientApp/src/app/nav-menu/nav-menu.component.html @@ -1,5 +1,5 @@
-