Skip to content

Commit 3bdda3c

Browse files
committed
add-image-API
1 parent a78edc1 commit 3bdda3c

27 files changed

+847
-17
lines changed

API/Controllers/AccountController.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Persistence;
77
using Microsoft.EntityFrameworkCore;
88
using System.Security.Claims;
9+
using System.Linq;
910

1011
namespace API.Controllers
1112
{
@@ -25,7 +26,8 @@ public AccountController(UserManager<AppUser> userManager, TokenService tokenSer
2526
[HttpPost("login")]
2627
public async Task<ActionResult<UserDto>> Login(LoginDTO loginDto)
2728
{
28-
var user = await _userManager.FindByEmailAsync(loginDto.Email);
29+
var user = await _userManager.Users.Include(p => p.Photos)
30+
.FirstOrDefaultAsync(x => x.Email == loginDto.Email);
2931

3032
if (user == null) return Unauthorized();
3133

@@ -75,7 +77,8 @@ public async Task<ActionResult<UserDto>> Register(RegisterDTO registerDTO)
7577
[HttpGet]
7678
public async Task<ActionResult<UserDto>> GetCurrentUser()
7779
{
78-
var user = await _userManager.FindByEmailAsync(User.FindFirstValue(ClaimTypes.Email));
80+
var user = await _userManager.Users.Include(p => p.Photos)
81+
.FirstOrDefaultAsync(x => x.Email == User.FindFirstValue(ClaimTypes.Email));
7982
return CreateUserObject(user);
8083

8184
}
@@ -85,7 +88,7 @@ private UserDto CreateUserObject(AppUser user)
8588
return new UserDto
8689
{
8790
DisplayName = user.DisplayName,
88-
Image = null,
91+
Image = user?.Photos?.FirstOrDefault(x => x.IsMain)?.Url,
8992
Token = _tokenService.CreateToken(user),
9093
Username = user.UserName
9194
};

API/Controllers/PhotosController.cs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Application.Photos;
2+
using Microsoft.AspNetCore.Mvc;
3+
4+
namespace API.Controllers
5+
{
6+
public class PhotosController : BaseApiController
7+
{
8+
[HttpPost]
9+
public async Task<IActionResult> Add([FromForm] Add.Command command)
10+
{
11+
return HandleResult(await Mediator.Send(command));
12+
}
13+
14+
[HttpDelete("{id}")]
15+
public async Task<IActionResult> Delete(string id)
16+
{
17+
return HandleResult(await Mediator.Send(new Delete.Command { Id = id }));
18+
}
19+
20+
[HttpPost("{id}/setMain")]
21+
public async Task<IActionResult> SetMain(string id)
22+
{
23+
return HandleResult(await Mediator.Send(new SetMain.Command { Id = id }));
24+
}
25+
}
26+
}

API/Controllers/ProfilesController.cs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Application.Profiles;
2+
using Microsoft.AspNetCore.Mvc;
3+
4+
namespace API.Controllers
5+
{
6+
public class ProfilesController : BaseApiController
7+
{
8+
[HttpGet("{username}")]
9+
public async Task<IActionResult> GetProfile(string username)
10+
{
11+
return HandleResult(await Mediator.Send(new Details.Query{Username = username}));
12+
}
13+
}
14+
}

API/Extentions/ApplicationServiceExtentions.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using FluentValidation.AspNetCore;
88
using Application.Interfaces;
99
using Infrastructure.Security;
10+
using Infrastructure.Photos;
1011

1112
namespace API.Extentions
1213
{
@@ -26,7 +27,7 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
2627
{
2728
opt.AddPolicy("CorsPolicy", policy =>
2829
{
29-
policy.AllowAnyMethod().AllowAnyHeader().WithOrigins("http://localhost:3000");
30+
policy.AllowAnyMethod().AllowAnyHeader().WithOrigins("http://localhost:3001");
3031
});
3132
});
3233

@@ -36,7 +37,8 @@ public static IServiceCollection AddApplicationServices(this IServiceCollection
3637
services.AddValidatorsFromAssemblyContaining<Create>();
3738
services.AddHttpContextAccessor();
3839
services.AddScoped<IUserAccessor, UserAccessor>();
39-
40+
services.AddScoped<IPhotoAccessor, PhotoAccessor>();
41+
services.Configure<CloundinarySettings>(config.GetSection("Cloudinary"));
4042

4143
return services;
4244
}

API/reactivities.db

12 KB
Binary file not shown.

API/reactivities.db-shm

0 Bytes
Binary file not shown.

Application/Activities/ActivityDto.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public class ActivityDto
1313
public string Venue { get; set; }
1414
public string HostUsername { get; set; }
1515
public bool IsCancelled { get; set; }
16-
public ICollection<Profile> Attendees { get; set; }
16+
public ICollection<AttendeeDto> Attendees { get; set; }
1717
}
1818
}

Application/Activities/AttendeeDto.cs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Application.Activities
2+
{
3+
public class AttendeeDto
4+
{
5+
public string Username { get; set; }
6+
public string DisplayName { get; set; }
7+
public string Bio { get; set; }
8+
public string Image { get; set; }
9+
}
10+
}

Application/Core/MappingProfiles.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Application.Activities;
22
using AutoMapper;
33
using Domain;
4+
using Persistence;
45

56
namespace Application.Core
67
{
@@ -12,10 +13,15 @@ public MappingProfiles()
1213
CreateMap<Activity, ActivityDto>()
1314
.ForMember(d => d.HostUsername, o => o.MapFrom(s =>
1415
s.Attendees.FirstOrDefault(x => x.IsHost).AppUser.UserName));
15-
CreateMap<ActivityAttendee, Profiles.Profile>()
16+
CreateMap<ActivityAttendee, AttendeeDto>()
1617
.ForMember(d => d.DisplayName, o => o.MapFrom(s => s.AppUser.DisplayName))
1718
.ForMember(d => d.Username, o => o.MapFrom(s => s.AppUser.UserName))
18-
.ForMember(d => d.Bio, o => o.MapFrom(s => s.AppUser.Bio));
19+
.ForMember(d => d.Bio, o => o.MapFrom(s => s.AppUser.Bio))
20+
.ForMember(d => d.Image, o =>
21+
o.MapFrom(s => s.AppUser.Photos.FirstOrDefault(x => x.IsMain).Url));
22+
CreateMap<AppUser, Profiles.Profile>()
23+
.ForMember(d => d.Image, o =>
24+
o.MapFrom(s => s.Photos.FirstOrDefault(x => x.IsMain).Url));
1925
}
2026
}
2127
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Application.Photos;
2+
using Microsoft.AspNetCore.Http;
3+
4+
namespace Application.Interfaces
5+
{
6+
public interface IPhotoAccessor
7+
{
8+
Task<PhotoUploadResult> AddPhoto(IFormFile file);
9+
Task<string> DeletePhoto(string PublicId);
10+
}
11+
}

Application/Photos/Add.cs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Application.Core;
2+
using Application.Interfaces;
3+
using Domain;
4+
using MediatR;
5+
using Microsoft.AspNetCore.Http;
6+
using Microsoft.EntityFrameworkCore;
7+
using Persistence;
8+
9+
namespace Application.Photos
10+
{
11+
public class Add
12+
{
13+
public class Command : IRequest<Result<Photo>>
14+
{
15+
public IFormFile File { get; set; }
16+
}
17+
18+
public class Handler : IRequestHandler<Command, Result<Photo>>
19+
{
20+
private readonly DataContext _context;
21+
private readonly IPhotoAccessor _photoAccessor;
22+
private readonly IUserAccessor _userAccessor;
23+
24+
public Handler(DataContext context, IPhotoAccessor photoAccessor, IUserAccessor userAccessor)
25+
{
26+
_userAccessor = userAccessor;
27+
_photoAccessor = photoAccessor;
28+
_context = context;
29+
}
30+
31+
public async Task<Result<Photo>> Handle(Command request, CancellationToken cancellationToken)
32+
{
33+
var user = await _context.Users.Include(p => p.Photos)
34+
.FirstOrDefaultAsync(x => x.UserName == _userAccessor.GetUserName());
35+
36+
if (user == null) return null;
37+
38+
var photoUploadResult = await _photoAccessor.AddPhoto(request.File);
39+
40+
var photo = new Photo
41+
{
42+
Url = photoUploadResult.Url,
43+
Id = photoUploadResult.PublicId,
44+
};
45+
46+
if (!user.Photos.Any(x => x.IsMain)) photo.IsMain = true;
47+
48+
user.Photos.Add(photo);
49+
50+
var result = await _context.SaveChangesAsync() > 0;
51+
52+
if (result) return Result<Photo>.Success(photo);
53+
54+
return Result<Photo>.Failure("Problem adding photo");
55+
}
56+
}
57+
}
58+
}

Application/Photos/Delete.cs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Application.Core;
2+
using Application.Interfaces;
3+
using MediatR;
4+
using Microsoft.EntityFrameworkCore;
5+
using Persistence;
6+
7+
namespace Application.Photos
8+
{
9+
public class Delete
10+
{
11+
public class Command : IRequest<Result<Unit>>
12+
{
13+
public string Id { get; set; }
14+
}
15+
16+
public class Handler : IRequestHandler<Command, Result<Unit>>
17+
{
18+
private readonly DataContext _context;
19+
private readonly IPhotoAccessor _photoAccessor;
20+
private readonly IUserAccessor _userAccessor;
21+
22+
public Handler(DataContext context, IPhotoAccessor photoAccessor, IUserAccessor userAccessor)
23+
{
24+
_userAccessor = userAccessor;
25+
_photoAccessor = photoAccessor;
26+
_context = context;
27+
}
28+
29+
public async Task<Result<Unit>> Handle(Command request, CancellationToken cancellationToken)
30+
{
31+
var user = await _context.Users.Include(p => p.Photos)
32+
.FirstOrDefaultAsync(x => x.UserName == _userAccessor.GetUserName());
33+
34+
if (user == null) return null;
35+
36+
var photo = user.Photos.FirstOrDefault(x => x.Id == request.Id);
37+
38+
if (photo == null) return null;
39+
40+
if (photo.IsMain) return Result<Unit>.Failure("You cannot delete your main photo");
41+
42+
var result = await _photoAccessor.DeletePhoto(photo.Id);
43+
44+
if (result == null) return Result<Unit>.Failure("Problem deleting photo from Cloudinary");
45+
46+
user.Photos.Remove(photo);
47+
48+
var success = await _context.SaveChangesAsync() > 0;
49+
50+
if (success) return Result<Unit>.Success(Unit.Value);
51+
52+
return Result<Unit>.Failure("Problem deleting photo from API");
53+
}
54+
}
55+
}
56+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Application.Photos
2+
{
3+
public class PhotoUploadResult
4+
{
5+
public string PublicId { get; set; }
6+
public string Url { get; set; }
7+
}
8+
}

Application/Photos/SetMain.cs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Application.Core;
2+
using Application.Interfaces;
3+
using MediatR;
4+
using Microsoft.EntityFrameworkCore;
5+
using Persistence;
6+
7+
namespace Application.Photos
8+
{
9+
public class SetMain
10+
{
11+
public class Command : IRequest<Result<Unit>>
12+
{
13+
public string Id { get; set; }
14+
}
15+
16+
public class Handler : IRequestHandler<Command, Result<Unit>>
17+
{
18+
private readonly DataContext _context;
19+
private readonly IUserAccessor _userAccessor;
20+
public Handler(DataContext context, IUserAccessor userAccessor)
21+
{
22+
_userAccessor = userAccessor;
23+
_context = context;
24+
}
25+
26+
public async Task<Result<Unit>> Handle(Command request, CancellationToken cancellationToken)
27+
{
28+
var user = await _context.Users.Include(p => p.Photos)
29+
.FirstOrDefaultAsync(x => x.UserName == _userAccessor.GetUserName());
30+
31+
if(user == null) return null;
32+
33+
var photo = user.Photos.FirstOrDefault(x => x.Id == request.Id);
34+
35+
if(photo == null) return null;
36+
37+
var currentMain = user.Photos.FirstOrDefault(x => x.IsMain);
38+
39+
if(currentMain != null) currentMain.IsMain = false;
40+
41+
photo.IsMain = true;
42+
43+
var success = await _context.SaveChangesAsync() > 0;
44+
45+
if(success) return Result<Unit>.Success(Unit.Value);
46+
47+
return Result<Unit>.Failure("Problem setting main photo");
48+
}
49+
}
50+
}
51+
}

Application/Profiles/Details.cs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Application.Core;
2+
using AutoMapper;
3+
using AutoMapper.QueryableExtensions;
4+
using MediatR;
5+
using Microsoft.EntityFrameworkCore;
6+
using Persistence;
7+
8+
namespace Application.Profiles
9+
{
10+
public class Details
11+
{
12+
public class Query : IRequest<Result<Profile>>
13+
{
14+
public string Username { get; set; }
15+
}
16+
17+
public class Handler : IRequestHandler<Query, Result<Profile>>
18+
{
19+
private readonly DataContext _context;
20+
private readonly IMapper _mapper;
21+
22+
public Handler(DataContext context, IMapper mapper)
23+
{
24+
_mapper = mapper;
25+
_context = context;
26+
}
27+
28+
public async Task<Result<Profile>> Handle(Query request, CancellationToken cancellationToken)
29+
{
30+
var user = await _context.Users
31+
.ProjectTo<Profile>(_mapper.ConfigurationProvider)
32+
.SingleOrDefaultAsync(x => x.Username == request.Username);
33+
34+
if(user == null) return null;
35+
36+
return Result<Profile>.Success(user);
37+
}
38+
}
39+
}
40+
}

Application/Profiles/Handler.cs

Whitespace-only changes.

0 commit comments

Comments
 (0)