aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyndamia <kamen.d.mladenov@protonmail.com>2021-02-03 10:22:37 +0200
committerSyndamia <kamen.d.mladenov@protonmail.com>2021-02-03 10:22:37 +0200
commit01ad75fa5a871a0c9f8cd0c5291312286ae4d52d (patch)
tree4f6b2eaef0424ffbfdd405939fbaa9325cc9d2c8
parent81b3fc43a900857443c3c763f52e0a54719c2fae (diff)
downloadDevHive-01ad75fa5a871a0c9f8cd0c5291312286ae4d52d.tar
DevHive-01ad75fa5a871a0c9f8cd0c5291312286ae4d52d.tar.gz
DevHive-01ad75fa5a871a0c9f8cd0c5291312286ae4d52d.zip
Implemented profile picture table functionality; added models and interfaces for profile picture; added ability for user layers to update the profile picture; added migrations; updated mappings
-rw-r--r--src/DevHive.Data/DevHiveContext.cs5
-rw-r--r--src/DevHive.Data/Interfaces/Models/IProfilePicture.cs13
-rw-r--r--src/DevHive.Data/Interfaces/Models/IUser.cs2
-rw-r--r--src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs1
-rw-r--r--src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs633
-rw-r--r--src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs52
-rw-r--r--src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs36
-rw-r--r--src/DevHive.Data/Models/ProfilePicture.cs14
-rw-r--r--src/DevHive.Data/Models/User.cs2
-rw-r--r--src/DevHive.Data/Repositories/UserRepository.cs10
-rw-r--r--src/DevHive.Services/Configurations/Mapping/UserMappings.cs6
-rw-r--r--src/DevHive.Services/Interfaces/IUserService.cs1
-rw-r--r--src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs7
-rw-r--r--src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs12
-rw-r--r--src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs2
-rw-r--r--src/DevHive.Services/Models/Identity/User/UserServiceModel.cs2
-rw-r--r--src/DevHive.Services/Services/UserService.cs29
-rw-r--r--src/DevHive.Web/Configurations/Mapping/UserMappings.cs3
-rw-r--r--src/DevHive.Web/Controllers/UserController.cs17
-rw-r--r--src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs7
-rw-r--r--src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs9
-rw-r--r--src/DevHive.Web/Models/Identity/User/UserWebModel.cs2
22 files changed, 857 insertions, 8 deletions
diff --git a/src/DevHive.Data/DevHiveContext.cs b/src/DevHive.Data/DevHiveContext.cs
index 417de7f..b3ebd73 100644
--- a/src/DevHive.Data/DevHiveContext.cs
+++ b/src/DevHive.Data/DevHiveContext.cs
@@ -27,6 +27,11 @@ namespace DevHive.Data
.HasIndex(x => x.UserName)
.IsUnique();
+ builder.Entity<User>()
+ .HasOne(x => x.ProfilePicture)
+ .WithOne(x => x.User)
+ .HasForeignKey<ProfilePicture>(x => x.UserId);
+
/* Roles */
builder.Entity<User>()
.HasMany(x => x.Roles)
diff --git a/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs b/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs
new file mode 100644
index 0000000..c3fcbea
--- /dev/null
+++ b/src/DevHive.Data/Interfaces/Models/IProfilePicture.cs
@@ -0,0 +1,13 @@
+using System;
+using DevHive.Data.Models;
+
+namespace DevHive.Data.Interfaces.Models
+{
+ public interface IProfilePicture : IModel
+ {
+ Guid UserId { get; set; }
+ User User { get; set; }
+
+ string PictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Data/Interfaces/Models/IUser.cs b/src/DevHive.Data/Interfaces/Models/IUser.cs
index eb262fd..fcd741c 100644
--- a/src/DevHive.Data/Interfaces/Models/IUser.cs
+++ b/src/DevHive.Data/Interfaces/Models/IUser.cs
@@ -10,7 +10,7 @@ namespace DevHive.Data.Interfaces.Models
string LastName { get; set; }
- string ProfilePictureUrl { get; set; }
+ ProfilePicture ProfilePicture { get; set; }
HashSet<Language> Languages { get; set; }
diff --git a/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs b/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
index 4346e9c..5b6ab9e 100644
--- a/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
+++ b/src/DevHive.Data/Interfaces/Repositories/IUserRepository.cs
@@ -11,6 +11,7 @@ namespace DevHive.Data.Interfaces.Repositories
//Read
Task<User> GetByUsernameAsync(string username);
IEnumerable<User> QueryAll();
+ Task<bool> UpdateProfilePicture(Guid userId, string pictureUrl);
//Validations
Task<bool> DoesEmailExistAsync(string email);
diff --git a/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs
new file mode 100644
index 0000000..b8dbd8e
--- /dev/null
+++ b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.Designer.cs
@@ -0,0 +1,633 @@
+// <auto-generated />
+using System;
+using System.Collections.Generic;
+using DevHive.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace DevHive.Data.Migrations
+{
+ [DbContext(typeof(DevHiveContext))]
+ [Migration("20210203071720_ProfilePicture")]
+ partial class ProfilePicture
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .UseIdentityByDefaultColumns()
+ .HasAnnotation("Relational:MaxIdentifierLength", 63)
+ .HasAnnotation("ProductVersion", "5.0.1");
+
+ modelBuilder.Entity("DevHive.Data.Models.Comment", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Language", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Languages");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<List<string>>("FileUrls")
+ .HasColumnType("text[]");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.ToTable("Posts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("PictureURL")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ProfilePicture");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<int>("Rate")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("Rating");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Role", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Technology", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Technologies");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<int>("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<bool>("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("FirstName")
+ .HasColumnType("text");
+
+ b.Property<string>("LastName")
+ .HasColumnType("text");
+
+ b.Property<bool>("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<DateTimeOffset?>("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<string>("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property<string>("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property<bool>("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property<bool>("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<string>("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("AspNetUsers");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("PostId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "PostId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("RatedPosts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserFriend", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("FriendId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "FriendId");
+
+ b.HasIndex("FriendId");
+
+ b.ToTable("UserFriends");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserRate", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<bool>("Rate")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserRates");
+ });
+
+ modelBuilder.Entity("LanguageUser", b =>
+ {
+ b.Property<Guid>("LanguagesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LanguagesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("LanguageUser");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .UseIdentityByDefaultColumn();
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .UseIdentityByDefaultColumn();
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderDisplayName")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.Property<string>("Value")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.Property<Guid>("RolesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("RolesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("RoleUser");
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.Property<Guid>("TechnologiesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("TechnologiesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("TechnologyUser");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Comment", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Comments")
+ .HasForeignKey("CreatorId");
+
+ b.HasOne("DevHive.Data.Models.Post", "Post")
+ .WithMany("Comments")
+ .HasForeignKey("PostId");
+
+ b.Navigation("Creator");
+
+ b.Navigation("Post");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Posts")
+ .HasForeignKey("CreatorId");
+
+ b.Navigation("Creator");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithOne("ProfilePicture")
+ .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Post", "Post")
+ .WithMany()
+ .HasForeignKey("PostId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Post");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserFriend", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Friend")
+ .WithMany("FriendsOf")
+ .HasForeignKey("FriendId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany("MyFriends")
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Friend");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.RelationModels.UserRate", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LanguageUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Language", null)
+ .WithMany()
+ .HasForeignKey("LanguagesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RolesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Technology", null)
+ .WithMany()
+ .HasForeignKey("TechnologiesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Navigation("Comments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.User", b =>
+ {
+ b.Navigation("Comments");
+
+ b.Navigation("FriendsOf");
+
+ b.Navigation("MyFriends");
+
+ b.Navigation("Posts");
+
+ b.Navigation("ProfilePicture");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs
new file mode 100644
index 0000000..1b0c2c6
--- /dev/null
+++ b/src/DevHive.Data/Migrations/20210203071720_ProfilePicture.cs
@@ -0,0 +1,52 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace DevHive.Data.Migrations
+{
+ public partial class ProfilePicture : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "ProfilePictureUrl",
+ table: "AspNetUsers");
+
+ migrationBuilder.CreateTable(
+ name: "ProfilePicture",
+ columns: table => new
+ {
+ Id = table.Column<Guid>(type: "uuid", nullable: false),
+ UserId = table.Column<Guid>(type: "uuid", nullable: false),
+ PictureURL = table.Column<string>(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_ProfilePicture", x => x.Id);
+ table.ForeignKey(
+ name: "FK_ProfilePicture_AspNetUsers_UserId",
+ column: x => x.UserId,
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_ProfilePicture_UserId",
+ table: "ProfilePicture",
+ column: "UserId",
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "ProfilePicture");
+
+ migrationBuilder.AddColumn<string>(
+ name: "ProfilePictureUrl",
+ table: "AspNetUsers",
+ type: "text",
+ nullable: true);
+ }
+ }
+}
diff --git a/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
index 96cabad..0450670 100644
--- a/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
+++ b/src/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
@@ -86,6 +86,26 @@ namespace DevHive.Data.Migrations
b.ToTable("Posts");
});
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("PictureURL")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ProfilePicture");
+ });
+
modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
{
b.Property<Guid>("Id")
@@ -190,9 +210,6 @@ namespace DevHive.Data.Migrations
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
- b.Property<string>("ProfilePictureUrl")
- .HasColumnType("text");
-
b.Property<string>("SecurityStamp")
.HasColumnType("text");
@@ -437,6 +454,17 @@ namespace DevHive.Data.Migrations
b.Navigation("Creator");
});
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithOne("ProfilePicture")
+ .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
modelBuilder.Entity("DevHive.Data.RelationModels.RatedPost", b =>
{
b.HasOne("DevHive.Data.Models.Post", "Post")
@@ -594,6 +622,8 @@ namespace DevHive.Data.Migrations
b.Navigation("MyFriends");
b.Navigation("Posts");
+
+ b.Navigation("ProfilePicture");
});
#pragma warning restore 612, 618
}
diff --git a/src/DevHive.Data/Models/ProfilePicture.cs b/src/DevHive.Data/Models/ProfilePicture.cs
new file mode 100644
index 0000000..e2ef04b
--- /dev/null
+++ b/src/DevHive.Data/Models/ProfilePicture.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace DevHive.Data.Models
+{
+ public class ProfilePicture
+ {
+ public Guid Id { get; set; }
+
+ public Guid UserId { get; set; }
+ public User User { get; set; }
+
+ public string PictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Data/Models/User.cs b/src/DevHive.Data/Models/User.cs
index 1c365e4..d73f989 100644
--- a/src/DevHive.Data/Models/User.cs
+++ b/src/DevHive.Data/Models/User.cs
@@ -14,7 +14,7 @@ namespace DevHive.Data.Models
public string LastName { get; set; }
- public string ProfilePictureUrl { get; set; }
+ public ProfilePicture ProfilePicture { get; set; }
public HashSet<Language> Languages { get; set; } = new();
diff --git a/src/DevHive.Data/Repositories/UserRepository.cs b/src/DevHive.Data/Repositories/UserRepository.cs
index b46198c..466b123 100644
--- a/src/DevHive.Data/Repositories/UserRepository.cs
+++ b/src/DevHive.Data/Repositories/UserRepository.cs
@@ -38,6 +38,7 @@ namespace DevHive.Data.Repositories
.Include(x => x.Languages)
.Include(x => x.Technologies)
.Include(x => x.Posts)
+ .Include(x => x.ProfilePicture)
.FirstOrDefaultAsync(x => x.Id == id);
}
@@ -48,6 +49,7 @@ namespace DevHive.Data.Repositories
.Include(x => x.Languages)
.Include(x => x.Technologies)
.Include(x => x.Posts)
+ .Include(x => x.ProfilePicture)
.FirstOrDefaultAsync(x => x.UserName == username);
}
#endregion
@@ -93,6 +95,14 @@ namespace DevHive.Data.Repositories
return await this.SaveChangesAsync();
}
+
+ public async Task<bool> UpdateProfilePicture(Guid userId, string pictureUrl) {
+ User user = await this.GetByIdAsync(userId);
+
+ user.ProfilePicture.PictureURL = pictureUrl;
+
+ return await this.SaveChangesAsync();
+ }
#endregion
#region Validations
diff --git a/src/DevHive.Services/Configurations/Mapping/UserMappings.cs b/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
index 5223d84..6922cd7 100644
--- a/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
+++ b/src/DevHive.Services/Configurations/Mapping/UserMappings.cs
@@ -22,10 +22,12 @@ namespace DevHive.Services.Configurations.Mapping
CreateMap<UpdateFriendServiceModel, User>();
CreateMap<User, UserServiceModel>()
- .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.MyFriends));
+ .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.MyFriends))
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL));
// .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.Friends));
CreateMap<User, UpdateUserServiceModel>()
- .ForMember(x => x.Password, opt => opt.Ignore());
+ .ForMember(x => x.Password, opt => opt.Ignore())
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL));
CreateMap<User, FriendServiceModel>();
CreateMap<UserFriend, FriendServiceModel>()
diff --git a/src/DevHive.Services/Interfaces/IUserService.cs b/src/DevHive.Services/Interfaces/IUserService.cs
index b701e4a..9e2b4e3 100644
--- a/src/DevHive.Services/Interfaces/IUserService.cs
+++ b/src/DevHive.Services/Interfaces/IUserService.cs
@@ -14,6 +14,7 @@ namespace DevHive.Services.Interfaces
Task<UserServiceModel> GetUserById(Guid id);
Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateModel);
+ Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel);
Task<bool> DeleteUser(Guid id);
diff --git a/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs b/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs
new file mode 100644
index 0000000..ad81057
--- /dev/null
+++ b/src/DevHive.Services/Models/Identity/User/ProfilePictureServiceModel.cs
@@ -0,0 +1,7 @@
+namespace DevHive.Services.Models.Identity.User
+{
+ public class ProfilePictureServiceModel
+ {
+ public string ProfilePictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs
new file mode 100644
index 0000000..8563953
--- /dev/null
+++ b/src/DevHive.Services/Models/Identity/User/UpdateProfilePictureServiceModel.cs
@@ -0,0 +1,12 @@
+using System;
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Services.Models.Identity.User
+{
+ public class UpdateProfilePictureServiceModel
+ {
+ public Guid UserId { get; set; }
+
+ public IFormFile Picture { get; set; }
+ }
+}
diff --git a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
index 5b197e4..b4e4400 100644
--- a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
+++ b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs
@@ -12,6 +12,8 @@ namespace DevHive.Services.Models.Identity.User
public string Password { get; set; }
+ public string ProfilePictureURL { get; set; }
+
public HashSet<UpdateRoleServiceModel> Roles { get; set; } = new HashSet<UpdateRoleServiceModel>();
public HashSet<UpdateFriendServiceModel> Friends { get; set; } = new HashSet<UpdateFriendServiceModel>();
diff --git a/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
index 5bf58ec..ac7bba2 100644
--- a/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
+++ b/src/DevHive.Services/Models/Identity/User/UserServiceModel.cs
@@ -8,6 +8,8 @@ namespace DevHive.Services.Models.Identity.User
{
public class UserServiceModel : BaseUserServiceModel
{
+ public string ProfilePictureURL { get; set; }
+
public HashSet<RoleServiceModel> Roles { get; set; } = new();
public HashSet<FriendServiceModel> Friends { get; set; } = new();
diff --git a/src/DevHive.Services/Services/UserService.cs b/src/DevHive.Services/Services/UserService.cs
index 09b56c1..d8c4ee5 100644
--- a/src/DevHive.Services/Services/UserService.cs
+++ b/src/DevHive.Services/Services/UserService.cs
@@ -15,6 +15,7 @@ using DevHive.Data.Interfaces.Repositories;
using System.Linq;
using DevHive.Common.Models.Misc;
using DevHive.Data.RelationModels;
+using Microsoft.AspNetCore.Http;
namespace DevHive.Services.Services
{
@@ -26,13 +27,15 @@ namespace DevHive.Services.Services
private readonly ITechnologyRepository _technologyRepository;
private readonly IMapper _userMapper;
private readonly JWTOptions _jwtOptions;
+ private readonly ICloudService _cloudService;
public UserService(IUserRepository userRepository,
ILanguageRepository languageRepository,
IRoleRepository roleRepository,
ITechnologyRepository technologyRepository,
IMapper mapper,
- JWTOptions jwtOptions)
+ JWTOptions jwtOptions,
+ ICloudService cloudService)
{
this._userRepository = userRepository;
this._roleRepository = roleRepository;
@@ -40,6 +43,7 @@ namespace DevHive.Services.Services
this._jwtOptions = jwtOptions;
this._languageRepository = languageRepository;
this._technologyRepository = technologyRepository;
+ this._cloudService = cloudService;
}
#region Authentication
@@ -66,6 +70,7 @@ namespace DevHive.Services.Services
User user = this._userMapper.Map<User>(registerModel);
user.PasswordHash = PasswordModifications.GeneratePasswordHash(registerModel.Password);
+ user.ProfilePicture = new ProfilePicture() { PictureURL = String.Empty };
// Make sure the default role exists
//TODO: Move when project starts
@@ -119,6 +124,28 @@ namespace DevHive.Services.Services
return this._userMapper.Map<UserServiceModel>(
await this._userRepository.GetByIdAsync(user.Id));
}
+
+ public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel)
+ {
+ User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId);
+
+ if (!String.IsNullOrEmpty(user.ProfilePicture.PictureURL))
+ {
+ bool success = await _cloudService.RemoveFilesFromCloud(new List<string> { user.ProfilePicture.PictureURL });
+ if (!success)
+ throw new InvalidCastException("Could not delete old profile picture!");
+ }
+
+ string fileUrl = (await this._cloudService.UploadFilesToCloud(new List<IFormFile> { updateProfilePictureServiceModel.Picture }))[0] ??
+ throw new ArgumentNullException("Unable to upload profile picture to cloud");
+
+ bool successful = await this._userRepository.UpdateProfilePicture(updateProfilePictureServiceModel.UserId, fileUrl);
+
+ if (!successful)
+ throw new InvalidOperationException("Unable to change profile picture!");
+
+ return new ProfilePictureServiceModel() { ProfilePictureURL = fileUrl };
+ }
#endregion
#region Delete
diff --git a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
index 1b26cc9..f58e7ca 100644
--- a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
+++ b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs
@@ -23,6 +23,9 @@ namespace DevHive.Web.Configurations.Mapping
CreateMap<UsernameWebModel, FriendServiceModel>();
CreateMap<UsernameWebModel, UpdateFriendServiceModel>();
+ CreateMap<UpdateProfilePictureWebModel, UpdateProfilePictureServiceModel>();
+ CreateMap<ProfilePictureServiceModel, ProfilePictureWebModel>();
+
CreateMap<UpdateUserServiceModel, UpdateUserWebModel>();
CreateMap<FriendServiceModel, UsernameWebModel>();
}
diff --git a/src/DevHive.Web/Controllers/UserController.cs b/src/DevHive.Web/Controllers/UserController.cs
index fdf317c..109bbaa 100644
--- a/src/DevHive.Web/Controllers/UserController.cs
+++ b/src/DevHive.Web/Controllers/UserController.cs
@@ -94,6 +94,23 @@ namespace DevHive.Web.Controllers
return new AcceptedResult("UpdateUser", userWebModel);
}
+
+ [HttpPut]
+ [Route("ProfilePicture")]
+ [Authorize(Roles = "User,Admin")]
+ public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization)
+ {
+ if (!await this._userService.ValidJWT(userId, authorization))
+ return new UnauthorizedResult();
+
+ UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map<UpdateProfilePictureServiceModel>(updateProfilePictureWebModel);
+ updateProfilePictureServiceModel.UserId = userId;
+
+ ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel);
+ ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map<ProfilePictureWebModel>(profilePictureServiceModel);
+
+ return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel);
+ }
#endregion
#region Delete
diff --git a/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs b/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs
new file mode 100644
index 0000000..9fb1516
--- /dev/null
+++ b/src/DevHive.Web/Models/Identity/User/ProfilePictureWebModel.cs
@@ -0,0 +1,7 @@
+namespace DevHive.Web.Models.Identity.User
+{
+ public class ProfilePictureWebModel
+ {
+ public string ProfilePictureURL { get; set; }
+ }
+}
diff --git a/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs b/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs
new file mode 100644
index 0000000..6efe968
--- /dev/null
+++ b/src/DevHive.Web/Models/Identity/User/UpdateProfilePictureWebModel.cs
@@ -0,0 +1,9 @@
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Web.Models.Identity.User
+{
+ public class UpdateProfilePictureWebModel
+ {
+ public IFormFile Picture { get; set; }
+ }
+}
diff --git a/src/DevHive.Web/Models/Identity/User/UserWebModel.cs b/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
index 1a5484a..7ab8cca 100644
--- a/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
+++ b/src/DevHive.Web/Models/Identity/User/UserWebModel.cs
@@ -10,6 +10,8 @@ namespace DevHive.Web.Models.Identity.User
{
public class UserWebModel : BaseUserWebModel
{
+ public string ProfilePictureURL { get; set; }
+
[NotNull]
[Required]
public HashSet<RoleWebModel> Roles { get; set; } = new();