Skip to content
Snippets Groups Projects
Commit 4b769c7b authored by Adiv Asif's avatar Adiv Asif
Browse files

Merged PR 40: removed profile pictures

removed profile pictures
parents e03af042 fb52f842
No related branches found
No related tags found
No related merge requests found
......@@ -258,15 +258,6 @@ public class AuthController : BaseAuthController
return Ok(null);
}
[HttpPost("UploadProfilePicture")]
[Consumes("multipart/form-data")]
public async Task<ActionResult<ResponseEnvelope<string>>> UploadProfilePicture(IFormFile? profilePicture)
{
if (profilePicture == null)
return BadRequest("Please upload a proper image.");
return Ok(await _userService.UploadProfilePicture(UserId, profilePicture));
}
[AllowAnonymous]
[HttpPost("SendEmail")]
[SwaggerResponse(204)]
......@@ -284,4 +275,34 @@ public class AuthController : BaseAuthController
return Ok(null);
}
[AllowAnonymous]
[HttpGet("GetUserById")]
[SwaggerResponse(200, Type = typeof(ResponseEnvelope<UserDTO>))]
public async Task<ActionResult<ResponseEnvelope<UserDTO>>> GetUserById(int userId)
{
try
{
return Ok(await _userService.GetUserById(userId));
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[AllowAnonymous]
[HttpPost("GetUsersById")]
[SwaggerResponse(200, Type = typeof(ResponseEnvelope<List<UserDTO>>))]
public async Task<ActionResult<ResponseEnvelope<List<UserDTO>>>> GetUsersById(List<int> userIds)
{
try
{
return Ok(await _userService.GetUsersById(userIds));
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
\ No newline at end of file
// <auto-generated />
using System;
using AuthenticationMicroservice.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AuthenticationMicroservice.Migrations
{
[DbContext(typeof(AuthenticationDbContext))]
[Migration("20230505160442_RemovedProfilePictures")]
partial class RemovedProfilePictures
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("AuthenticationMicroservice.Models.Entities.RefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier")
.HasDefaultValueSql("newid()");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("datetimeoffset");
b.Property<bool>("Deleted")
.HasColumnType("bit");
b.Property<DateTimeOffset?>("DeletedAt")
.HasColumnType("datetimeoffset");
b.Property<long>("Expires")
.HasColumnType("bigint");
b.Property<string>("IpAddress")
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsValid")
.HasColumnType("bit");
b.Property<string>("Reason")
.HasColumnType("nvarchar(max)");
b.Property<string>("Token")
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset?>("UpdatedAt")
.HasColumnType("datetimeoffset");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("UserId");
b.HasIndex("CreatedAt", "Deleted");
b.ToTable("RefreshToken");
});
modelBuilder.Entity("AuthenticationMicroservice.Models.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("DeletedAt")
.HasColumnType("datetimeoffset");
b.Property<string>("EmailAddress")
.IsRequired()
.HasColumnType("nvarchar(450)");
b.Property<Guid?>("EmailConfirmationToken")
.HasColumnType("uniqueidentifier");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset?>("LastLogin")
.HasColumnType("datetimeoffset");
b.Property<DateTimeOffset?>("LastRefreshTokenIssued")
.HasColumnType("datetimeoffset");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<Guid?>("PasswordResetToken")
.HasColumnType("uniqueidentifier");
b.Property<string>("Surname")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("UnconfirmedEmail")
.HasColumnType("nvarchar(max)");
b.Property<DateTimeOffset?>("UpdatedAt")
.HasColumnType("datetimeoffset");
b.HasKey("Id");
b.HasIndex("EmailAddress")
.IsUnique();
b.ToTable("User");
});
modelBuilder.Entity("AuthenticationMicroservice.Models.Entities.RefreshToken", b =>
{
b.HasOne("AuthenticationMicroservice.Models.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace AuthenticationMicroservice.Migrations
{
/// <inheritdoc />
public partial class RemovedProfilePictures : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ProfilePictureUrl",
table: "User");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ProfilePictureUrl",
table: "User",
type: "nvarchar(max)",
nullable: true);
}
}
}
......@@ -17,7 +17,7 @@ namespace AuthenticationMicroservice.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0-preview.2.23128.3")
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
......@@ -106,9 +106,6 @@ namespace AuthenticationMicroservice.Migrations
b.Property<Guid?>("PasswordResetToken")
.HasColumnType("uniqueidentifier");
b.Property<string>("ProfilePictureUrl")
.HasColumnType("nvarchar(max)");
b.Property<string>("Surname")
.IsRequired()
.HasColumnType("nvarchar(max)");
......
......@@ -16,8 +16,6 @@ public class UserDTO : BaseIntDto
public DateTimeOffset? LastLogin { get; set; }
public DateTimeOffset? LastRefreshTokenIssued { get; set; }
public string? ProfilePictureUrl { get; set; }
public string? UnconfirmedEmail { get; set; }
}
......
......@@ -17,8 +17,6 @@ public class User : BaseIntEntity
public DateTimeOffset? LastLogin { get; set; }
public DateTimeOffset? LastRefreshTokenIssued { get; set; }
public string? ProfilePictureUrl { get; set; }
public string? UnconfirmedEmail { get; set; }
public Guid? PasswordResetToken { get; set; }
......
......@@ -114,7 +114,6 @@ builder.Services.AddSingleton(mapper);
builder.Services.AddTransient(typeof(IBaseRepository<>), typeof(BaseRepository<>));
// Add services from /Services
builder.Services.AddTransient<IStorageService, StorageService>();
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddTransient<IRefreshTokenService, RefreshTokenService>();
builder.Services.AddTransient<IEmailService, EmailService>();
......
......@@ -29,14 +29,12 @@ public class AuthService : IAuthService
private readonly AuthenticationDbContext _context;
private readonly IEmailService _emailService;
private readonly IRefreshTokenService _refreshTokenService;
private readonly IStorageService _storageService;
public AuthService(AuthenticationDbContext context, IEmailService emailService,
IRefreshTokenService refreshTokenService, IStorageService storageService)
IRefreshTokenService refreshTokenService)
{
_context = context;
_emailService = emailService;
_storageService = storageService;
_refreshTokenService = refreshTokenService;
}
......@@ -79,9 +77,6 @@ public class AuthService : IAuthService
AccessTokenExpiresIn = newAccess.ExpiresIn,
RefreshToken = newRefresh!.Token,
RefreshTokenExpires = newRefresh.Expires,
ProfilePictureUrl = user.ProfilePictureUrl,
ProfilePictureSas = _storageService.GetSasForFile(Constants.AzureBlobContainers.ProfilePictures,
user.ProfilePictureUrl ?? string.Empty),
UserId = user.Id
};
......
namespace AuthenticationMicroservice.Services;
using System.Web;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Sas;
using Microsoft.Extensions.Options;
using Settings;
public interface IStorageService
{
Task<Uri> SaveImageAsJpgBlob(string containerName, string fileName, Stream input,
Dictionary<string, string>? metadata = null);
string? GetSasForFile(string containerName, string url, DateTimeOffset? expires = null);
}
public class StorageService : IStorageService
{
private readonly ConnectionStrings _connectionStrings;
public StorageService(IOptions<ConnectionStrings> connectionStrings)
{
_connectionStrings = connectionStrings.Value;
}
public string? GetSasForFile(string containerName, string url, DateTimeOffset? expires = null)
{
url = GetFileFromUrl(url, containerName) ?? string.Empty;
if (string.IsNullOrWhiteSpace(url))
return null;
var container = new BlobContainerClient(_connectionStrings.AzureBlobStorage, containerName);
var blob = container.GetBlobClient(url);
var urlWithSas = blob.GenerateSasUri(BlobSasPermissions.Read, DateTimeOffset.Now.AddHours(3));
return urlWithSas.Query;
}
public async Task<Uri> SaveImageAsJpgBlob(string containerName, string fileName, Stream input,
Dictionary<string, string>? metadata = null)
{
using var image = await Image.LoadAsync(input);
using var croppedImage = new MemoryStream();
var clone = image.Clone(context =>
context.Resize(new ResizeOptions {Mode = ResizeMode.Max, Size = new Size(1366, 768)}));
await clone.SaveAsJpegAsync(croppedImage);
croppedImage.Position = 0;
var blob = await GetBlobReference(containerName, fileName);
await blob.UploadAsync(croppedImage, new BlobHttpHeaders {ContentType = "image/jpeg"});
return blob.Uri;
}
private async Task<BlobClient> GetBlobReference(string? containerName, string blobName)
{
var container = new BlobContainerClient(_connectionStrings.AzureBlobStorage, containerName);
await container.CreateIfNotExistsAsync();
var blob = container.GetBlobClient(blobName);
return blob;
}
private static string? GetFileFromUrl(string url, string container)
{
if (string.IsNullOrEmpty(url))
return null;
var userDataContainerString = container + "/";
var fileUrl =
url[(url.IndexOf(userDataContainerString, StringComparison.Ordinal) + userDataContainerString.Length)..];
return HttpUtility.UrlDecode(fileUrl);
}
}
\ No newline at end of file
......@@ -13,21 +13,20 @@ using Repositories;
public interface IUserService
{
Task<User> CreateUser(UserRegisterRequestDTO request);
Task<string?> UploadProfilePicture(int userId, IFormFile profilePicture);
Task<UserDTO> GetUserById(int userId);
Task<List<UserDTO>> GetUsersById(List<int> userIds);
List<UserDTO> GetListOfAllUsers();
}
public class UserService : IUserService
{
private readonly IMapper _mapper;
private readonly IStorageService _storageService;
private readonly IBaseRepository<User> _userRepo;
public UserService(IMapper mapper, IBaseRepository<User> userRepo, IStorageService storageService)
public UserService(IMapper mapper, IBaseRepository<User> userRepo)
{
_mapper = mapper;
_userRepo = userRepo;
_storageService = storageService;
}
public async Task<User> CreateUser(UserRegisterRequestDTO request)
......@@ -52,18 +51,15 @@ public class UserService : IUserService
return await _userRepo.CreateAndSaveAsync(newUser);
}
public async Task<string?> UploadProfilePicture(int userId, IFormFile profilePicture)
public async Task<UserDTO> GetUserById(int userId)
{
var user = _userRepo.GetByIdThrowIfNull(userId);
using var ms = new MemoryStream();
await profilePicture.CopyToAsync(ms);
ms.Position = 0;
var fileName = $"{user.Id}/{user.FirstName}";
var image = await _storageService.SaveImageAsJpgBlob(Constants.AzureBlobContainers.ProfilePictures, fileName,
ms);
user.ProfilePictureUrl = image.ToString();
await _userRepo.UpdateAndSaveAsync(user);
return _storageService.GetSasForFile(Constants.AzureBlobContainers.ProfilePictures, image.ToString());
return _mapper.Map<UserDTO>(_userRepo.GetByIdThrowIfNull(userId));
}
public async Task<List<UserDTO>> GetUsersById(List<int> userIds)
{
var users = _userRepo.GetAll().AsNoTracking().Where(u => userIds.Contains(u.Id));
return await _mapper.ProjectTo<UserDTO>(users).ToListAsync();
}
public List<UserDTO> GetListOfAllUsers()
......
......@@ -3,10 +3,10 @@
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
- main
- main
resources:
- repo: self
- repo: self
variables:
# Container registry service connection established during pipeline creation
......@@ -20,20 +20,20 @@ variables:
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment