Skip to content

Commit

Permalink
Merge pull request #29 from Alper-Soy/develop
Browse files Browse the repository at this point in the history
Prod - 08/25/2024 - 3
  • Loading branch information
Alper-Soy authored Aug 25, 2024
2 parents 286e5f8 + b7eef3a commit 4a6ed55
Show file tree
Hide file tree
Showing 35 changed files with 1,062 additions and 66 deletions.
3 changes: 2 additions & 1 deletion API/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public async Task<ActionResult<AuthUserDto>> Register(RegisterDto registerDto)
[HttpGet]
public async Task<ActionResult<AuthUserDto>> GetCurrentUser()
{
var user = await userManager.Users.Include(p => p.Photos).FirstOrDefaultAsync(u => u.Email == User.FindFirstValue(ClaimTypes.Email));
var user = await userManager.Users.Include(p => p.Photos)
.FirstOrDefaultAsync(u => u.Email == User.FindFirstValue(ClaimTypes.Email));

return CreateUserObject(user);
}
Expand Down
4 changes: 1 addition & 3 deletions API/Controllers/ProfilesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ public async Task<IActionResult> GetProfile(string username)
{
return HandleResult(await Mediator.Send(new GetProfileQuery { Username = username }));
}

[HttpPut]
public async Task<IActionResult> Update(UpdateProfileCommand command)
{
return HandleResult(await Mediator.Send(command));
}
}


6 changes: 5 additions & 1 deletion API/Extensions/ApplicationServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
policy => { policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000"); });
policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().AllowCredentials().WithOrigins("http://localhost:3000");
});
});
services.AddMediatR(conf => conf.RegisterServicesFromAssemblies(typeof(GetActivitiesHandler).Assembly));
services.AddAutoMapper(typeof(MappingProfiles).Assembly);
Expand All @@ -29,6 +32,7 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
services.AddScoped<IUserAccessor, UserAccessor>();
services.AddScoped<IPhotoAccessor, PhotoAccessor>();
services.Configure<CloudinarySettings>(config.GetSection("Cloudinary"));
services.AddSignalR();

return services;
}
Expand Down
14 changes: 14 additions & 0 deletions API/Extensions/IdentityServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public static IServiceCollection AddIdentityServices(this IServiceCollection ser
ValidateIssuer = false,
ValidateAudience = false
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/chat"))
{
context.Token = accessToken;
}

return Task.CompletedTask;
}
};
});
services.AddAuthorization(opt =>
{
Expand Down
2 changes: 2 additions & 0 deletions API/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using API.Extensions;
using API.Middleware;
using API.SignalR;
using Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
Expand Down Expand Up @@ -30,6 +31,7 @@
app.UseAuthorization();

app.MapControllers();
app.MapHub<ChatHub>("/chat");

using var scope = app.Services.CreateScope();
var services = scope.ServiceProvider;
Expand Down
25 changes: 25 additions & 0 deletions API/SignalR/ChatHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Application.Features.Comments.Commands.CreateComment;
using Application.Features.Comments.Queries.GetComments;
using MediatR;
using Microsoft.AspNetCore.SignalR;

namespace API.SignalR;

public class ChatHub(IMediator mediator) : Hub
{
public async Task SendComment(CreateCommentCommand command)
{
var comment = await mediator.Send(command);

await Clients.Group(command.ActivityId.ToString()).SendAsync("ReceiveComment", comment.Value);
}

public override async Task OnConnectedAsync()
{
var httpContext = Context.GetHttpContext();
var activityId = httpContext!.Request.Query["activityId"];
await Groups.AddToGroupAsync(Context.ConnectionId, activityId);
var result = await mediator.Send(new GetCommentsQuery { ActivityId = Guid.Parse(activityId) });
await Clients.Caller.SendAsync("LoadComments", result.Value);
}
}
Binary file modified API/activity-hub.db
Binary file not shown.
8 changes: 7 additions & 1 deletion Application/Core/MappingProfiles.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Application.Features.Activities.Contracts;
using Application.Features.Attendance.Contracts;
using Application.Features.Comments.Contracts;
using AutoMapper;
using Domain.Entities;

Expand All @@ -21,7 +22,12 @@ public MappingProfiles()
.ForMember(d => d.Bio, o => o.MapFrom(s => s.User.Bio))
.ForMember(d => d.Image, o => o.MapFrom(s => s.User.Photos.FirstOrDefault(x => x.IsMain).Url));

CreateMap<User, Features.Profiles.Contracts.Profile>()
CreateMap<User, Features.Profiles.Contracts.ProfileDto>()
.ForMember(d => d.Image, s => s.MapFrom(o => o.Photos.FirstOrDefault(x => x.IsMain).Url));

CreateMap<Comment, CommentDto>()
.ForMember(d => d.DisplayName, o => o.MapFrom(s => s.Author.DisplayName))
.ForMember(d => d.Username, o => o.MapFrom(s => s.Author.UserName))
.ForMember(d => d.Image, o => o.MapFrom(s => s.Author.Photos.FirstOrDefault(x => x.IsMain).Url));
}
}
2 changes: 0 additions & 2 deletions Application/Features/Activities/Contracts/ActivityDto.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Application.Features.Attendance.Contracts;
using Application.Features.Profiles;
using Application.Features.Profiles.Contracts;

namespace Application.Features.Activities.Contracts;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Application.Core;
using Application.Features.Comments.Contracts;
using Application.Interfaces;
using AutoMapper;
using Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Persistence;

namespace Application.Features.Comments.Commands.CreateComment;

public class CreateCommandHandler(DataContext context, IMapper mapper, IUserAccessor userAccessor)
: IRequestHandler<CreateCommentCommand, Result<CommentDto>>
{
public async Task<Result<CommentDto>> Handle(CreateCommentCommand request, CancellationToken cancellationToken)
{
var activity = await context.Activities.FindAsync(request.ActivityId);

if (activity == null) return null;

var user = await context.Users.Include(p => p.Photos)
.SingleOrDefaultAsync(x => x.UserName == userAccessor.GetUsername());

var comment = new Comment
{
Author = user,
Activity = activity,
Body = request.Body
};

activity.Comments.Add(comment);

var success = await context.SaveChangesAsync() > 0;

return success
? Result<CommentDto>.Success(mapper.Map<CommentDto>(comment))
: Result<CommentDto>.Failure("Failed to add comment");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Application.Core;
using Application.Features.Comments.Contracts;
using MediatR;

namespace Application.Features.Comments.Commands.CreateComment;

public class CreateCommentCommand : IRequest<Result<CommentDto>>
{
public string Body { get; set; }
public Guid ActivityId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using FluentValidation;

namespace Application.Features.Comments.Commands.CreateComment;

public class CreateCommentValidator : AbstractValidator<CreateCommentCommand>
{
public CreateCommentValidator()
{
RuleFor(x => x.Body).NotEmpty();
}
}
11 changes: 11 additions & 0 deletions Application/Features/Comments/Contracts/CommentDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Application.Features.Comments.Contracts;

public class CommentDto
{
public int Id { get; set; }
public DateTime CreatedAt { get; set; }
public string Body { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public string Image { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Application.Core;
using Application.Features.Comments.Contracts;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Persistence;

namespace Application.Features.Comments.Queries.GetComments;

public class GetCommentsHandler(DataContext context, IMapper mapper)
: IRequestHandler<GetCommentsQuery, Result<List<CommentDto>>>
{
public async Task<Result<List<CommentDto>>> Handle(GetCommentsQuery request, CancellationToken cancellationToken)
{
var comments = await context.Comments
.Where(x => x.Activity.Id == request.ActivityId)
.OrderByDescending(x => x.CreatedAt)
.ProjectTo<CommentDto>(mapper.ConfigurationProvider)
.ToListAsync();

return Result<List<CommentDto>>.Success(comments);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Application.Core;
using Application.Features.Comments.Contracts;
using MediatR;

namespace Application.Features.Comments.Queries.GetComments;

public class GetCommentsQuery : IRequest<Result<List<CommentDto>>>
{
public Guid ActivityId { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Application.Features.Profiles.Commands.UpdateProfile;

public class UpdateProfileCommand:IRequest<Result<Unit>>
public class UpdateProfileCommand : IRequest<Result<Unit>>
{
public string DisplayName { get; set; }
public string Bio { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ namespace Application.Features.Profiles.Commands.UpdateProfile;
public class UpdateProfileHandler(DataContext context, IUserAccessor userAccessor)
: IRequestHandler<UpdateProfileCommand, Result<Unit>>
{

public async Task<Result<Unit>> Handle(UpdateProfileCommand request, CancellationToken cancellationToken)
{
var user = await context.Users.FirstOrDefaultAsync(x =>
x.UserName == userAccessor.GetUsername());

user.Bio = request.Bio ?? user.Bio;
user.DisplayName = request.DisplayName ?? user.DisplayName;

var success = await context.SaveChangesAsync() > 0;

return success ? Result<Unit>.Success(Unit.Value) : Result<Unit>.Failure("Problem updating profile");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Application.Features.Profiles.Commands.UpdateProfile;



public class UpdateProfileValidator:AbstractValidator<UpdateProfileCommand>
public class UpdateProfileValidator : AbstractValidator<UpdateProfileCommand>
{
public UpdateProfileValidator()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Application.Features.Profiles.Contracts;

public class Profile
public class ProfileDto
{
public string Username { get; set; }
public string DisplayName { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
using Application.Core;
using Application.Features.Profiles.Contracts;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Persistence;
using Profile = Application.Features.Profiles.Contracts.Profile;

namespace Application.Features.Profiles.Queries.GetProfile;

public class GetProfileHandler(DataContext context, IMapper mapper) : IRequestHandler<GetProfileQuery, Result<Profile>>
public class GetProfileHandler(DataContext context, IMapper mapper)
: IRequestHandler<GetProfileQuery, Result<ProfileDto>>
{
public async Task<Result<Profile>> Handle(GetProfileQuery request, CancellationToken cancellationToken)
public async Task<Result<ProfileDto>> Handle(GetProfileQuery request, CancellationToken cancellationToken)
{
var user = await context.Users
.ProjectTo<Profile>(mapper.ConfigurationProvider)
.ProjectTo<ProfileDto>(mapper.ConfigurationProvider)
.SingleOrDefaultAsync(x => x.Username == request.Username);

return Result<Profile>.Success(user);
return Result<ProfileDto>.Success(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Application.Features.Profiles.Queries.GetProfile;

public class GetProfileQuery : IRequest<Result<Profile>>
public class GetProfileQuery : IRequest<Result<ProfileDto>>
{
public string Username { get; set; }
}
1 change: 1 addition & 0 deletions Domain/Entities/Activity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public class Activity
public string Venue { get; set; }
public bool IsCancelled { get; set; }
public ICollection<ActivityAttendee> Attendees { get; set; } = new List<ActivityAttendee>();
public ICollection<Comment> Comments { get; set; } = new List<Comment>();
}
10 changes: 10 additions & 0 deletions Domain/Entities/Comment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Domain.Entities;

public class Comment
{
public int Id { get; set; }
public string Body { get; set; }
public User Author { get; set; }
public Activity Activity { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
3 changes: 3 additions & 0 deletions Persistence/DataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class DataContext(DbContextOptions options) : IdentityDbContext<User>(opt
public DbSet<Activity> Activities { get; set; }
public DbSet<ActivityAttendee> ActivityAttendees { get; set; }
public DbSet<Photo> Photos { get; set; }
public DbSet<Comment> Comments { get; set; }

protected override void OnModelCreating(ModelBuilder builder)
{
Expand All @@ -21,5 +22,7 @@ protected override void OnModelCreating(ModelBuilder builder)

builder.Entity<ActivityAttendee>().HasOne(a => a.Activity).WithMany(a => a.Attendees)
.HasForeignKey(aa => aa.ActivityId);

builder.Entity<Comment>().HasOne(a => a.Activity).WithMany(a => a.Comments).OnDelete(DeleteBehavior.Cascade);
}
}
Loading

0 comments on commit 4a6ed55

Please sign in to comment.