added profilepicture to user. No functionallity
This commit is contained in:
parent
b213523911
commit
067a3e8d3c
@ -11,6 +11,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.402.4" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.7" />
|
||||
|
@ -82,9 +82,10 @@ namespace API.Application.Users.Commands
|
||||
CreatedAt = DateTime.UtcNow.AddHours(2),
|
||||
UpdatedAt = DateTime.UtcNow.AddHours(2),
|
||||
HashedPassword = hashedPassword,
|
||||
ProfilePicture = "",
|
||||
RefreshToken = System.Guid.NewGuid().ToString(),
|
||||
RefreshTokenExpiresAt = DateTime.UtcNow.AddDays(7),
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using API.Models;
|
||||
using API.Persistence.Repositories;
|
||||
using API.Persistence.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@ -8,10 +9,16 @@ namespace API.Application.Users.Commands
|
||||
public class UpdateUser
|
||||
{
|
||||
private readonly IUserRepository _repository;
|
||||
private readonly R2Service _r2Service;
|
||||
private readonly string _accessKey;
|
||||
private readonly string _secretKey;
|
||||
|
||||
public UpdateUser(IUserRepository repository)
|
||||
public UpdateUser(IUserRepository repository, AppConfiguration config)
|
||||
{
|
||||
_repository = repository;
|
||||
_accessKey = config.AccessKey;
|
||||
_secretKey = config.SecretKey;
|
||||
_r2Service = new R2Service(_accessKey, _secretKey);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Handle(UpdateUserDTO updateUserDTO)
|
||||
@ -31,22 +38,41 @@ namespace API.Application.Users.Commands
|
||||
return new ConflictObjectResult(new { message = "Email is already in use." });
|
||||
}
|
||||
}
|
||||
if (updateUserDTO.Password != "")
|
||||
if (updateUserDTO.Password != "½")
|
||||
{
|
||||
if (IsPasswordSecure(updateUserDTO.Password))
|
||||
{
|
||||
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(updateUserDTO.Password);
|
||||
currentUser.HashedPassword = hashedPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ConflictObjectResult(new { message = "Password is not secure." });
|
||||
}
|
||||
}
|
||||
if (updateUserDTO.Username != "")
|
||||
if (updateUserDTO.Username != "½")
|
||||
currentUser.Username = updateUserDTO.Username;
|
||||
if (updateUserDTO.Email != "")
|
||||
if (updateUserDTO.Email != "½")
|
||||
currentUser.Email = updateUserDTO.Email;
|
||||
|
||||
string imageUrl = null;
|
||||
if (updateUserDTO.ProfilePicture != null && updateUserDTO.ProfilePicture.Length > 0)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
using (var fileStream = updateUserDTO.ProfilePicture.OpenReadStream())
|
||||
{
|
||||
imageUrl = await _r2Service.UploadToR2(fileStream, "PP" + updateUserDTO.Id);
|
||||
currentUser.ProfilePicture = imageUrl;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool success = await _repository.UpdateUserAsync(currentUser);
|
||||
if (success)
|
||||
|
@ -25,7 +25,8 @@ namespace API.Application.Users.Queries
|
||||
{
|
||||
Id = user.Id,
|
||||
Email = user.Email,
|
||||
Username = user.Username
|
||||
Username = user.Username,
|
||||
ProfilePictureURL = user.ProfilePicture,
|
||||
}).ToList();
|
||||
return userDTOs;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace API.Application.Users.Queries
|
||||
return new ConflictObjectResult(new { message = "No user on given Id" });
|
||||
}
|
||||
|
||||
return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, createdAt = user.CreatedAt });
|
||||
return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, profilePictureURL = user.ProfilePicture, createdAt = user.CreatedAt });
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ using System.Text.RegularExpressions;
|
||||
using Helpers;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using API.Persistence.Repositories;
|
||||
using API.Persistence.Services;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
@ -26,6 +27,8 @@ namespace API.Controllers
|
||||
private readonly DeleteUser _deleteUser;
|
||||
private readonly LoginUser _loginUser;
|
||||
private readonly TokenHelper _tokenHelper;
|
||||
|
||||
|
||||
private readonly IUserRepository _repository;
|
||||
|
||||
public UsersController(
|
||||
@ -36,7 +39,8 @@ namespace API.Controllers
|
||||
DeleteUser deleteUser,
|
||||
LoginUser loginUser,
|
||||
TokenHelper tokenHelper,
|
||||
IUserRepository repository)
|
||||
IUserRepository repository
|
||||
)
|
||||
{
|
||||
_queryAllUsers = queryAllUsers;
|
||||
_queryUserById = queryUserById;
|
||||
@ -46,6 +50,8 @@ namespace API.Controllers
|
||||
_loginUser = loginUser;
|
||||
_tokenHelper = tokenHelper;
|
||||
_repository = repository;
|
||||
|
||||
|
||||
}
|
||||
|
||||
[HttpPost("login")]
|
||||
@ -69,7 +75,7 @@ namespace API.Controllers
|
||||
|
||||
[Authorize]
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> PutUser(UpdateUserDTO UpdateUserDTO)
|
||||
public async Task<IActionResult> PutUser([FromForm] UpdateUserDTO UpdateUserDTO)
|
||||
{
|
||||
return await _updateUser.Handle(UpdateUserDTO);
|
||||
}
|
||||
|
62
API/Migrations/20240904110821_addedprofilepicture.Designer.cs
generated
Normal file
62
API/Migrations/20240904110821_addedprofilepicture.Designer.cs
generated
Normal file
@ -0,0 +1,62 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using API;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDBContext))]
|
||||
[Migration("20240904110821_addedprofilepicture")]
|
||||
partial class addedprofilepicture
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.7");
|
||||
|
||||
modelBuilder.Entity("API.Models.User", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("HashedPassword")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("RefreshTokenExpiresAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
29
API/Migrations/20240904110821_addedprofilepicture.cs
Normal file
29
API/Migrations/20240904110821_addedprofilepicture.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class addedprofilepicture : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ProfilePicture",
|
||||
table: "Users",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ProfilePicture",
|
||||
table: "Users");
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,10 @@ namespace API.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ProfilePicture")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
@ -8,6 +8,7 @@ public class User : BaseModel
|
||||
public string? Username { get; set; }
|
||||
public string HashedPassword { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public string ProfilePicture { get; set; }
|
||||
public DateTime RefreshTokenExpiresAt { get; set; }
|
||||
}
|
||||
|
||||
@ -16,6 +17,8 @@ public class UserDTO
|
||||
public string Id { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string ProfilePictureURL { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class LoginDTO
|
||||
@ -37,6 +40,8 @@ public class UpdateUserDTO
|
||||
public string Email { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public IFormFile ProfilePicture { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class RefreshTokenDTO
|
||||
|
8
API/Persistence/Services/AppConfiguration.cs
Normal file
8
API/Persistence/Services/AppConfiguration.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace API.Persistence.Services
|
||||
{
|
||||
public class AppConfiguration
|
||||
{
|
||||
public string AccessKey { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
}
|
||||
}
|
48
API/Persistence/Services/R2Service.cs
Normal file
48
API/Persistence/Services/R2Service.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using Amazon.Runtime;
|
||||
using Amazon.S3.Model;
|
||||
using Amazon.S3;
|
||||
|
||||
namespace API.Persistence.Services
|
||||
{
|
||||
public class R2Service
|
||||
{
|
||||
private readonly IAmazonS3 _s3Client;
|
||||
public string AccessKey { get; }
|
||||
public string SecretKey { get; }
|
||||
|
||||
public R2Service(string accessKey, string secretKey)
|
||||
{
|
||||
AccessKey = accessKey;
|
||||
SecretKey = secretKey;
|
||||
|
||||
var credentials = new BasicAWSCredentials(accessKey, secretKey);
|
||||
var config = new AmazonS3Config
|
||||
{
|
||||
ServiceURL = "https://a6051dbbe0af70488aff47b9f4d9fc1c.r2.cloudflarestorage.com",
|
||||
ForcePathStyle = true
|
||||
};
|
||||
_s3Client = new AmazonS3Client(credentials, config);
|
||||
}
|
||||
|
||||
public async Task<string> UploadToR2(Stream fileStream, string fileName)
|
||||
{
|
||||
var request = new PutObjectRequest
|
||||
{
|
||||
InputStream = fileStream,
|
||||
BucketName = "h4fil",
|
||||
Key = fileName,
|
||||
DisablePayloadSigning = true
|
||||
};
|
||||
|
||||
var response = await _s3Client.PutObjectAsync(request);
|
||||
|
||||
if (response.HttpStatusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
throw new AmazonS3Exception($"Error uploading file to S3. HTTP Status Code: {response.HttpStatusCode}");
|
||||
}
|
||||
|
||||
var imageUrl = $"https://h4file.magsapi.com/{fileName}";
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using System.Text;
|
||||
using Helpers;
|
||||
using API.Persistence.Services;
|
||||
|
||||
namespace API
|
||||
{
|
||||
@ -69,6 +70,8 @@ namespace API
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Swagger does not by default allow to use Bearer tokens
|
||||
// The method AddSwaggerGen with the following options grants access to address a Bearer token -
|
||||
// Simply by clicking the Lock icon and pasting the Bearer Token
|
||||
@ -105,6 +108,15 @@ namespace API
|
||||
|
||||
Console.WriteLine("Connecting to database with connection string: " + connectionString);
|
||||
|
||||
var accessKey = Configuration["AccessKey"] ?? Environment.GetEnvironmentVariable("ACCESS_KEY");
|
||||
var secretKey = Configuration["SecretKey"] ?? Environment.GetEnvironmentVariable("SECRET_KEY");
|
||||
|
||||
builder.Services.AddSingleton(new AppConfiguration
|
||||
{
|
||||
AccessKey = accessKey,
|
||||
SecretKey = secretKey
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
Loading…
Reference in New Issue
Block a user