From d53caaea6094136bac3d01ce9dd2782bb1819fe2 Mon Sep 17 00:00:00 2001 From: transtrike Date: Thu, 25 Mar 2021 12:22:54 +0200 Subject: Profile Picture implemented; Tests and Front end work await --- src/Data/DevHive.Data.Models/ProfilePicture.cs | 3 - src/Data/DevHive.Data/DevHiveContext.cs | 5 +- .../Interfaces/IProfilePictureRepository.cs | 11 + ...0210325081526_Profile_Picture_Layer.Designer.cs | 667 +++++++++++++++++++++ .../20210325081526_Profile_Picture_Layer.cs | 78 +++ .../Migrations/DevHiveContextModelSnapshot.cs | 30 +- .../Repositories/ProfilePictureRepository.cs | 25 + .../ProfilePicture/ProfilePictureServiceModel.cs | 11 + .../User/ProfilePictureServiceModel.cs | 7 - .../User/UpdateProfilePictureServiceModel.cs | 12 - .../Interfaces/IProfilePictureService.cs | 22 + .../DevHive.Services/Interfaces/IUserService.cs | 8 - .../Services/ProfilePictureService.cs | 99 +++ .../DevHive.Services/Services/UserService.cs | 22 - .../ProfilePicture/ProfilePictureWebModel.cs | 9 + .../User/ProfilePictureWebModel.cs | 7 - .../User/UpdateProfilePictureWebModel.cs | 9 - .../Extensions/ConfigureDependencyInjection.cs | 7 +- .../Mapping/ProfilePictureMappings.cs | 16 + .../Configurations/Mapping/UserMappings.cs | 3 - .../Controllers/ProfilePictureController.cs | 42 +- 21 files changed, 978 insertions(+), 115 deletions(-) create mode 100644 src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs create mode 100644 src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.Designer.cs create mode 100644 src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.cs create mode 100644 src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs create mode 100644 src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs delete mode 100644 src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs delete mode 100644 src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs create mode 100644 src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs create mode 100644 src/Services/DevHive.Services/Services/ProfilePictureService.cs create mode 100644 src/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs delete mode 100644 src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs delete mode 100644 src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs create mode 100644 src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs diff --git a/src/Data/DevHive.Data.Models/ProfilePicture.cs b/src/Data/DevHive.Data.Models/ProfilePicture.cs index e2ef04b..4b629c2 100644 --- a/src/Data/DevHive.Data.Models/ProfilePicture.cs +++ b/src/Data/DevHive.Data.Models/ProfilePicture.cs @@ -6,9 +6,6 @@ namespace DevHive.Data.Models { public Guid Id { get; set; } - public Guid UserId { get; set; } - public User User { get; set; } - public string PictureURL { get; set; } } } diff --git a/src/Data/DevHive.Data/DevHiveContext.cs b/src/Data/DevHive.Data/DevHiveContext.cs index b0bbdc6..c3adf2d 100644 --- a/src/Data/DevHive.Data/DevHiveContext.cs +++ b/src/Data/DevHive.Data/DevHiveContext.cs @@ -17,6 +17,7 @@ namespace DevHive.Data public DbSet PostAttachments { get; set; } public DbSet Comments { get; set; } public DbSet Rating { get; set; } + public DbSet ProfilePicture { get; set; } public DbSet RatedPost { get; set; } public DbSet UserRate { get; set; } @@ -28,9 +29,7 @@ namespace DevHive.Data .IsUnique(); builder.Entity() - .HasOne(x => x.ProfilePicture) - .WithOne(x => x.User) - .HasForeignKey(x => x.UserId); + .HasOne(x => x.ProfilePicture); /* Roles */ builder.Entity() diff --git a/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs b/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs new file mode 100644 index 0000000..45beaa0 --- /dev/null +++ b/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; +using DevHive.Data.Models; + +namespace DevHive.Data.Interfaces +{ + public interface IProfilePictureRepository : IRepository + { + Task GetByURLAsync(string picUrl); + } +} diff --git a/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.Designer.cs b/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.Designer.cs new file mode 100644 index 0000000..189060d --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.Designer.cs @@ -0,0 +1,667 @@ +// +using System; +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("20210325081526_Profile_Picture_Layer")] + partial class Profile_Picture_Layer + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("DevHive.Data.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("TimeCreated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("PictureURL") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ProfilePicture"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsLike") + .HasColumnType("boolean"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Rating"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FileUrl") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostAttachments"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "PostId"); + + b.HasIndex("PostId"); + + b.ToTable("RatedPosts"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Liked") + .HasColumnType("boolean"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("UserRates"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("ProfilePictureId"); + + b.HasIndex("UserId"); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("LanguageUser", b => + { + b.Property("LanguagesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("LanguagesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("LanguageUser"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("RoleUser", b => + { + b.Property("RolesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("RolesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("RoleUser"); + }); + + modelBuilder.Entity("TechnologyUser", b => + { + b.Property("TechnologiesId") + .HasColumnType("uuid"); + + b.Property("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.Rating", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Ratings") + .HasForeignKey("PostId"); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Attachments") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany("RatedPosts") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany() + .HasForeignKey("PostId"); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.HasOne("DevHive.Data.Models.ProfilePicture", "ProfilePicture") + .WithMany() + .HasForeignKey("ProfilePictureId"); + + b.HasOne("DevHive.Data.Models.User", null) + .WithMany("Friends") + .HasForeignKey("UserId"); + + b.Navigation("ProfilePicture"); + }); + + 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", b => + { + b.HasOne("DevHive.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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("Attachments"); + + b.Navigation("Comments"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Navigation("Comments"); + + b.Navigation("Friends"); + + b.Navigation("Posts"); + + b.Navigation("RatedPosts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.cs b/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.cs new file mode 100644 index 0000000..0ee1fb7 --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210325081526_Profile_Picture_Layer.cs @@ -0,0 +1,78 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace DevHive.Data.Migrations +{ + public partial class Profile_Picture_Layer : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_ProfilePicture_AspNetUsers_UserId", + table: "ProfilePicture"); + + migrationBuilder.DropIndex( + name: "IX_ProfilePicture_UserId", + table: "ProfilePicture"); + + migrationBuilder.DropColumn( + name: "UserId", + table: "ProfilePicture"); + + migrationBuilder.AddColumn( + name: "ProfilePictureId", + table: "AspNetUsers", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_ProfilePictureId", + table: "AspNetUsers", + column: "ProfilePictureId"); + + migrationBuilder.AddForeignKey( + name: "FK_AspNetUsers_ProfilePicture_ProfilePictureId", + table: "AspNetUsers", + column: "ProfilePictureId", + principalTable: "ProfilePicture", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_AspNetUsers_ProfilePicture_ProfilePictureId", + table: "AspNetUsers"); + + migrationBuilder.DropIndex( + name: "IX_AspNetUsers_ProfilePictureId", + table: "AspNetUsers"); + + migrationBuilder.DropColumn( + name: "ProfilePictureId", + table: "AspNetUsers"); + + migrationBuilder.AddColumn( + name: "UserId", + table: "ProfilePicture", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000")); + + migrationBuilder.CreateIndex( + name: "IX_ProfilePicture_UserId", + table: "ProfilePicture", + column: "UserId", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_ProfilePicture_AspNetUsers_UserId", + table: "ProfilePicture", + column: "UserId", + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs index 80e3ac0..8877fab 100644 --- a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs +++ b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs @@ -91,14 +91,8 @@ namespace DevHive.Data.Migrations b.Property("PictureURL") .HasColumnType("text"); - b.Property("UserId") - .HasColumnType("uuid"); - b.HasKey("Id"); - b.HasIndex("UserId") - .IsUnique(); - b.ToTable("ProfilePicture"); }); @@ -274,6 +268,9 @@ namespace DevHive.Data.Migrations b.Property("PhoneNumberConfirmed") .HasColumnType("boolean"); + b.Property("ProfilePictureId") + .HasColumnType("uuid"); + b.Property("SecurityStamp") .HasColumnType("text"); @@ -296,6 +293,8 @@ namespace DevHive.Data.Migrations .IsUnique() .HasDatabaseName("UserNameIndex"); + b.HasIndex("ProfilePictureId"); + b.HasIndex("UserId"); b.HasIndex("UserName") @@ -474,17 +473,6 @@ 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.Models.Rating", b => { b.HasOne("DevHive.Data.Models.Post", "Post") @@ -545,9 +533,15 @@ namespace DevHive.Data.Migrations modelBuilder.Entity("DevHive.Data.Models.User", b => { + b.HasOne("DevHive.Data.Models.ProfilePicture", "ProfilePicture") + .WithMany() + .HasForeignKey("ProfilePictureId"); + b.HasOne("DevHive.Data.Models.User", null) .WithMany("Friends") .HasForeignKey("UserId"); + + b.Navigation("ProfilePicture"); }); modelBuilder.Entity("LanguageUser", b => @@ -663,8 +657,6 @@ namespace DevHive.Data.Migrations b.Navigation("Posts"); - b.Navigation("ProfilePicture"); - b.Navigation("RatedPosts"); }); #pragma warning restore 612, 618 diff --git a/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs b/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs new file mode 100644 index 0000000..7284464 --- /dev/null +++ b/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using Microsoft.EntityFrameworkCore; + +namespace DevHive.Data.Repositories +{ + public class ProfilePictureRepository : BaseRepository, IProfilePictureRepository + { + private readonly DevHiveContext _context; + + public ProfilePictureRepository(DevHiveContext context) + : base(context) + { + this._context = context; + } + + public async Task GetByURLAsync(string picUrl) + { + return await this._context + .ProfilePicture + .FirstOrDefaultAsync(x => x.PictureURL == picUrl); + } + } +} diff --git a/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs new file mode 100644 index 0000000..5e69d13 --- /dev/null +++ b/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs @@ -0,0 +1,11 @@ +using System; +using Microsoft.AspNetCore.Http; + +namespace DevHive.Services.Models.ProfilePicture +{ + public class ProfilePictureServiceModel + { + public Guid UserId { get; set; } + public IFormFile ProfilePictureFormFile { get; set; } + } +} diff --git a/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs deleted file mode 100644 index cbe64b2..0000000 --- a/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DevHive.Services.Models.User -{ - public class ProfilePictureServiceModel - { - public string ProfilePictureURL { get; set; } - } -} diff --git a/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs deleted file mode 100644 index 19ba08f..0000000 --- a/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; - -namespace DevHive.Services.Models.User -{ - public class UpdateProfilePictureServiceModel - { - public Guid UserId { get; set; } - - public IFormFile Picture { get; set; } - } -} diff --git a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs new file mode 100644 index 0000000..b0673ac --- /dev/null +++ b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading.Tasks; +using DevHive.Services.Models.ProfilePicture; + +namespace DevHive.Services.Interfaces +{ + public interface IProfilePictureService + { + Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + + Task GetProfilePictureById(Guid id); + + /// + /// Uploads the given picture and assigns it's link to the user in the database + /// + /// Contains User's Guid and the new picture to be updated + /// The new picture's URL + Task UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + + Task DeleteProfilePicture(Guid id); + } +} diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs index a55f9dd..da07507 100644 --- a/src/Services/DevHive.Services/Interfaces/IUserService.cs +++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs @@ -44,14 +44,6 @@ namespace DevHive.Services.Interfaces /// Read model of the new user Task UpdateUser(UpdateUserServiceModel updateUserServiceModel); - /// - /// Uploads the given picture and assigns it's link to the user in the database - /// Requires authenticated user - /// - /// Contains User's Guid and the new picture to be updated - /// The new picture's URL - Task UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel); - /// /// Deletes a user from the database and removes his data entirely /// Requires authenticated user diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs new file mode 100644 index 0000000..0636f5c --- /dev/null +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using Microsoft.AspNetCore.Http; + +namespace DevHive.Services.Services +{ + public class ProfilePictureService : IProfilePictureService + { + private readonly IUserRepository _userRepository; + private readonly IProfilePictureRepository _profilePictureRepository; + private readonly ICloudService _cloudinaryService; + + public ProfilePictureService(IUserRepository userRepository, IProfilePictureRepository profilePictureRepository, ICloudService cloudinaryService) + { + this._userRepository = userRepository; + this._profilePictureRepository = profilePictureRepository; + this._cloudinaryService = cloudinaryService; + } + + public async Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) + { + await ValidateServiceModel(profilePictureServiceModel); + + return await SaveProfilePictureInDatabase(profilePictureServiceModel); + } + + public async Task GetProfilePictureById(Guid id) + { + return (await this._profilePictureRepository.GetByIdAsync(id)).PictureURL; + } + + public async Task UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) + { + await ValidateServiceModel(profilePictureServiceModel); + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + if (!string.IsNullOrEmpty(user.ProfilePicture.PictureURL)) + { + List file = new() { user.ProfilePicture.PictureURL }; + bool removed = await this._cloudinaryService.RemoveFilesFromCloud(file); + + if (!removed) + throw new ArgumentException("Cannot delete old picture"); + } + + return await SaveProfilePictureInDatabase(profilePictureServiceModel); + } + + public async Task DeleteProfilePicture(Guid id) + { + ProfilePicture profilePic = await this._profilePictureRepository.GetByIdAsync(id) ?? + throw new ArgumentException("Such picture doesn't exist!"); + + bool removedFromDb = await this._profilePictureRepository.DeleteAsync(profilePic); + if (!removedFromDb) + throw new ArgumentException("Cannot delete picture from database!"); + + List file = new() { profilePic.PictureURL }; + bool removedFromCloud = await this._cloudinaryService.RemoveFilesFromCloud(file); + if (!removedFromCloud) + throw new ArgumentException("Cannot delete picture from cloud!"); + + return true; + } + + private async Task SaveProfilePictureInDatabase(ProfilePictureServiceModel profilePictureServiceModel) + { + List file = new() { profilePictureServiceModel.ProfilePictureFormFile }; + string picUrl = (await this._cloudinaryService.UploadFilesToCloud(file))[0]; + ProfilePicture profilePic = new() { PictureURL = picUrl }; + + bool success = await this._profilePictureRepository.AddAsync(profilePic); + if (!success) + throw new ArgumentException("Unable to upload picture!"); + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + user.ProfilePicture = await this._profilePictureRepository.GetByURLAsync(picUrl); + bool userProfilePicAlter = await this._userRepository.EditAsync(user.Id, user); + if (!userProfilePicAlter) + throw new ArgumentException("Unable to alter user's profile picture"); + + return picUrl; + } + + private async Task ValidateServiceModel(ProfilePictureServiceModel profilePictureServiceModel) + { + if (profilePictureServiceModel.ProfilePictureFormFile.Length == 0) + throw new ArgumentException("Picture cannot be null"); + + if (!await this._userRepository.DoesUserExistAsync(profilePictureServiceModel.UserId)) + throw new ArgumentException("User does not exist!"); + } + } +} diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs index 4f74b06..d487de4 100644 --- a/src/Services/DevHive.Services/Services/UserService.cs +++ b/src/Services/DevHive.Services/Services/UserService.cs @@ -119,28 +119,6 @@ namespace DevHive.Services.Services User newUser = await this._userRepository.GetByIdAsync(user.Id); return this._userMapper.Map(newUser); } - - public async Task UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel) - { - User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId); - - if (!string.IsNullOrEmpty(user.ProfilePicture.PictureURL)) - { - bool success = await _cloudService.RemoveFilesFromCloud(new List { user.ProfilePicture.PictureURL }); - if (!success) - throw new InvalidCastException("Could not delete old profile picture!"); - } - - string fileUrl = (await this._cloudService.UploadFilesToCloud(new List { updateProfilePictureServiceModel.Picture }))[0] ?? - throw new ArgumentException("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/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs b/src/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs new file mode 100644 index 0000000..3fe201c --- /dev/null +++ b/src/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Http; + +namespace DevHive.Web.Models.ProfilePicture +{ + public class ProfilePictureWebModel + { + public IFormFile Picture { get; set; } + } +} diff --git a/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs b/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs deleted file mode 100644 index e09ee08..0000000 --- a/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DevHive.Web.Models.User -{ - public class ProfilePictureWebModel - { - public string ProfilePictureURL { get; set; } - } -} diff --git a/src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs b/src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs deleted file mode 100644 index 196d1e7..0000000 --- a/src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace DevHive.Web.Models.User -{ - public class UpdateProfilePictureWebModel - { - public IFormFile Picture { get; set; } - } -} diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs index a0d0979..20b66e1 100644 --- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs +++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs @@ -17,20 +17,22 @@ namespace DevHive.Web.Configurations.Extensions services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(options => new CloudinaryService( @@ -43,7 +45,6 @@ namespace DevHive.Web.Configurations.Extensions signingKey: Encoding.ASCII.GetBytes(configuration.GetSection("Jwt").GetSection("signingKey").Value), validationIssuer: configuration.GetSection("Jwt").GetSection("validationIssuer").Value, audience: configuration.GetSection("Jwt").GetSection("audience").Value)); - services.AddTransient(); } } } diff --git a/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs b/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs new file mode 100644 index 0000000..8c12a20 --- /dev/null +++ b/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs @@ -0,0 +1,16 @@ +using System; +using AutoMapper; +using DevHive.Web.Models.ProfilePicture; +using DevHive.Services.Models.ProfilePicture; + +namespace DevHive.Web.Configurations.Mapping +{ + public class ProfilePictureMappings : Profile + { + public ProfilePictureMappings() + { + CreateMap() + .ForMember(dest => dest.ProfilePictureFormFile, src => src.MapFrom(p => p.Picture)); + } + } +} diff --git a/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs b/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs index 14aaa3a..dabec93 100644 --- a/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs +++ b/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs @@ -23,9 +23,6 @@ namespace DevHive.Web.Configurations.Mapping CreateMap(); CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); CreateMap(); } diff --git a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs index 2eec99e..1c736f6 100644 --- a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs +++ b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs @@ -1,8 +1,12 @@ using System; using System.Threading.Tasks; -using DevHive.Web.Models.User; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using DevHive.Common.Jwt.Interfaces; +using AutoMapper; +using DevHive.Web.Models.ProfilePicture; namespace DevHive.Web.Controllers { @@ -13,36 +17,36 @@ namespace DevHive.Web.Controllers [Route("api/[controller]")] public class ProfilePictureController { - // private readonly ProfilePictureService _profilePictureService; + private readonly IProfilePictureService _profilePictureService; + private readonly IJwtService _jwtService; + private readonly IMapper _profilePictureMapper; - // public ProfilePictureController(ProfilePictureService profilePictureService) - // { - // this._profilePictureService = profilePictureService; - // } + public ProfilePictureController(IProfilePictureService profilePictureService, IJwtService jwtService, IMapper profilePictureMapper) + { + this._profilePictureService = profilePictureService; + this._jwtService = jwtService; + this._profilePictureMapper = profilePictureMapper; + } /// /// Alter the profile picture of a user /// /// The user's Id - /// The new profile picture + /// The new profile picture /// JWT Bearer Token - /// ??? + /// The URL of the new profile picture [HttpPut] - [Route("ProfilePicture")] [Authorize(Roles = "User,Admin")] - public async Task UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization) + public async Task UpdateProfilePicture(Guid userId, [FromForm] ProfilePictureWebModel profilePictureWebModel, [FromHeader] string authorization) { - throw new NotImplementedException(); - // if (!await this._userService.ValidJWT(userId, authorization)) - // return new UnauthorizedResult(); - - // UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map(updateProfilePictureWebModel); - // updateProfilePictureServiceModel.UserId = userId; + if (!this._jwtService.ValidateToken(userId, authorization)) + return new UnauthorizedResult(); - // ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel); - // ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map(profilePictureServiceModel); + ProfilePictureServiceModel profilePictureServiceModel = this._profilePictureMapper.Map(profilePictureWebModel); + profilePictureServiceModel.UserId = userId; - // return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel); + string url = await this._profilePictureService.UpdateProfilePicture(profilePictureServiceModel); + return new OkObjectResult(new { URL = url }); } } } -- cgit v1.2.3 From a58b73c11e9d017fcae59f2820a68b88888267ba Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 26 Mar 2021 17:25:07 +0200 Subject: Splitted validation in Service --- .../DevHive.Services/Services/ProfilePictureService.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs index 0636f5c..8a9bb29 100644 --- a/src/Services/DevHive.Services/Services/ProfilePictureService.cs +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -24,7 +24,8 @@ namespace DevHive.Services.Services public async Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) { - await ValidateServiceModel(profilePictureServiceModel); + ValidateProfPic(profilePictureServiceModel.ProfilePictureFormFile); + await ValidateUserExistsAsync(profilePictureServiceModel.UserId); return await SaveProfilePictureInDatabase(profilePictureServiceModel); } @@ -36,7 +37,8 @@ namespace DevHive.Services.Services public async Task UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) { - await ValidateServiceModel(profilePictureServiceModel); + ValidateProfPic(profilePictureServiceModel.ProfilePictureFormFile); + await ValidateUserExistsAsync(profilePictureServiceModel.UserId); User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); if (!string.IsNullOrEmpty(user.ProfilePicture.PictureURL)) @@ -87,12 +89,15 @@ namespace DevHive.Services.Services return picUrl; } - private async Task ValidateServiceModel(ProfilePictureServiceModel profilePictureServiceModel) + private static void ValidateProfPic(IFormFile profilePictureFormFile) { - if (profilePictureServiceModel.ProfilePictureFormFile.Length == 0) + if (profilePictureFormFile.Length == 0) throw new ArgumentException("Picture cannot be null"); + } - if (!await this._userRepository.DoesUserExistAsync(profilePictureServiceModel.UserId)) + private async Task ValidateUserExistsAsync(Guid userId) + { + if (!await this._userRepository.DoesUserExistAsync(userId)) throw new ArgumentException("User does not exist!"); } } -- cgit v1.2.3 From 4f6d554f95afac9c4eb7358596e4a7ce3aeb5a30 Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 26 Mar 2021 21:08:13 +0200 Subject: Fixed default Picture URL --- src/Data/DevHive.Data.Models/User.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/DevHive.Data.Models/User.cs b/src/Data/DevHive.Data.Models/User.cs index eb5ae41..feae197 100644 --- a/src/Data/DevHive.Data.Models/User.cs +++ b/src/Data/DevHive.Data.Models/User.cs @@ -13,7 +13,7 @@ namespace DevHive.Data.Models public string LastName { get; set; } - public ProfilePicture ProfilePicture { get; set; } = new() { PictureURL = "/assets/images/feed/profile-pic.png" }; + public ProfilePicture ProfilePicture { get; set; } = new() { PictureURL = "/assets/icons/tabler-icon-user.svg" }; public HashSet Languages { get; set; } = new(); -- cgit v1.2.3 From 416fd94399bf0b58fc0d201c0294f0869517a743 Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 26 Mar 2021 22:05:07 +0200 Subject: Rating's GetById and GetRatingByPostAndUser return null if User hasn't rated; Updated connection string --- src/Services/DevHive.Services/Services/RatingService.cs | 10 ++++++---- src/Web/DevHive.Web/appsettings.json | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Services/DevHive.Services/Services/RatingService.cs b/src/Services/DevHive.Services/Services/RatingService.cs index 1f77a6e..9d8f4b0 100644 --- a/src/Services/DevHive.Services/Services/RatingService.cs +++ b/src/Services/DevHive.Services/Services/RatingService.cs @@ -57,8 +57,9 @@ namespace DevHive.Services.Services #region Read public async Task GetRatingById(Guid ratingId) { - Rating rating = await this._ratingRepository.GetByIdAsync(ratingId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map(rating); readRatingServiceModel.UserId = rating.User.Id; @@ -68,8 +69,9 @@ namespace DevHive.Services.Services public async Task GetRatingByPostAndUser(Guid userId, Guid postId) { - Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map(rating); readRatingServiceModel.UserId = rating.User.Id; diff --git a/src/Web/DevHive.Web/appsettings.json b/src/Web/DevHive.Web/appsettings.json index fcf9805..053007d 100644 --- a/src/Web/DevHive.Web/appsettings.json +++ b/src/Web/DevHive.Web/appsettings.json @@ -5,7 +5,7 @@ "audience": "" }, "ConnectionStrings": { - "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=;" + "DEV": "Server=localhost;Port=5432;Database=DevHive API;User Id=postgres;Password=;" }, "Cloud": { "cloudName": "devhive", -- cgit v1.2.3 From 418552fcb981443f2a89340c01efadc439f3f854 Mon Sep 17 00:00:00 2001 From: Danail Dimitrov Date: Mon, 22 Mar 2021 19:21:30 +0200 Subject: removing parts of old rating system --- .../RelationalModels/RatedPost.cs | 18 - .../RelationalModels/UserRate.cs | 18 - src/Data/DevHive.Data.Models/User.cs | 2 - src/Data/DevHive.Data/DevHiveContext.cs | 16 - ...0322171857_Remove_old_rating_system.Designer.cs | 600 +++++++++++++++++++++ .../20210322171857_Remove_old_rating_system.cs | 85 +++ .../Migrations/DevHiveContextModelSnapshot.cs | 75 --- 7 files changed, 685 insertions(+), 129 deletions(-) delete mode 100644 src/Data/DevHive.Data.Models/RelationalModels/RatedPost.cs delete mode 100644 src/Data/DevHive.Data.Models/RelationalModels/UserRate.cs create mode 100644 src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.Designer.cs create mode 100644 src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.cs diff --git a/src/Data/DevHive.Data.Models/RelationalModels/RatedPost.cs b/src/Data/DevHive.Data.Models/RelationalModels/RatedPost.cs deleted file mode 100644 index fb63848..0000000 --- a/src/Data/DevHive.Data.Models/RelationalModels/RatedPost.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Reflection.Metadata.Ecma335; -using DevHive.Data.Models; -using Microsoft.EntityFrameworkCore; - -namespace DevHive.Data.Models.Relational -{ - [Table("RatedPosts")] - public class RatedPost - { - public Guid UserId { get; set; } - public User User { get; set; } - - public Guid PostId { get; set; } - public Post Post { get; set; } - } -} diff --git a/src/Data/DevHive.Data.Models/RelationalModels/UserRate.cs b/src/Data/DevHive.Data.Models/RelationalModels/UserRate.cs deleted file mode 100644 index 46bd605..0000000 --- a/src/Data/DevHive.Data.Models/RelationalModels/UserRate.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations.Schema; -using DevHive.Data.Models; - -namespace DevHive.Data.Models.Relational -{ - [Table("UserRates")] - public class UserRate - { - public Guid Id { get; set; } - - public User User { get; set; } - - public bool Liked { get; set; } - - public Post Post { get; set; } - } -} diff --git a/src/Data/DevHive.Data.Models/User.cs b/src/Data/DevHive.Data.Models/User.cs index eb5ae41..ea0b4f2 100644 --- a/src/Data/DevHive.Data.Models/User.cs +++ b/src/Data/DevHive.Data.Models/User.cs @@ -26,7 +26,5 @@ namespace DevHive.Data.Models public HashSet Friends { get; set; } = new(); public HashSet Comments { get; set; } = new(); - - public HashSet RatedPosts { get; set; } = new(); } } diff --git a/src/Data/DevHive.Data/DevHiveContext.cs b/src/Data/DevHive.Data/DevHiveContext.cs index b0bbdc6..621336f 100644 --- a/src/Data/DevHive.Data/DevHiveContext.cs +++ b/src/Data/DevHive.Data/DevHiveContext.cs @@ -17,8 +17,6 @@ namespace DevHive.Data public DbSet PostAttachments { get; set; } public DbSet Comments { get; set; } public DbSet Rating { get; set; } - public DbSet RatedPost { get; set; } - public DbSet UserRate { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -94,20 +92,6 @@ namespace DevHive.Data .HasMany(x => x.Ratings) .WithOne(x => x.Post); - /* User Rated Posts */ - builder.Entity() - .HasKey(x => new { x.UserId, x.PostId }); - - builder.Entity() - .HasOne(x => x.User) - .WithMany(x => x.RatedPosts); - - builder.Entity() - .HasOne(x => x.Post); - - builder.Entity() - .HasMany(x => x.RatedPosts); - base.OnModelCreating(builder); } } diff --git a/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.Designer.cs b/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.Designer.cs new file mode 100644 index 0000000..0aefeb1 --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.Designer.cs @@ -0,0 +1,600 @@ +// +using System; +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("20210322171857_Remove_old_rating_system")] + partial class Remove_old_rating_system + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("DevHive.Data.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("TimeCreated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("PictureURL") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ProfilePicture"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsLike") + .HasColumnType("boolean"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Rating"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FileUrl") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostAttachments"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("UserId"); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("LanguageUser", b => + { + b.Property("LanguagesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("LanguagesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("LanguageUser"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("RoleUser", b => + { + b.Property("RolesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("RolesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("RoleUser"); + }); + + modelBuilder.Entity("TechnologyUser", b => + { + b.Property("TechnologiesId") + .HasColumnType("uuid"); + + b.Property("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.Models.Rating", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Ratings") + .HasForeignKey("PostId"); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Attachments") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany("Friends") + .HasForeignKey("UserId"); + }); + + 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", b => + { + b.HasOne("DevHive.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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("Attachments"); + + b.Navigation("Comments"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Navigation("Comments"); + + b.Navigation("Friends"); + + b.Navigation("Posts"); + + b.Navigation("ProfilePicture"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.cs b/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.cs new file mode 100644 index 0000000..3d5690e --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210322171857_Remove_old_rating_system.cs @@ -0,0 +1,85 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace DevHive.Data.Migrations +{ + public partial class Remove_old_rating_system : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RatedPosts"); + + migrationBuilder.DropTable( + name: "UserRates"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "RatedPosts", + columns: table => new + { + UserId = table.Column(type: "uuid", nullable: false), + PostId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RatedPosts", x => new { x.UserId, x.PostId }); + table.ForeignKey( + name: "FK_RatedPosts_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_RatedPosts_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "UserRates", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Liked = table.Column(type: "boolean", nullable: false), + PostId = table.Column(type: "uuid", nullable: true), + UserId = table.Column(type: "uuid", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_UserRates", x => x.Id); + table.ForeignKey( + name: "FK_UserRates_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_UserRates_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_RatedPosts_PostId", + table: "RatedPosts", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRates_PostId", + table: "UserRates", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_UserRates_UserId", + table: "UserRates", + column: "UserId"); + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs index 80e3ac0..3b328c6 100644 --- a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs +++ b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs @@ -145,45 +145,6 @@ namespace DevHive.Data.Migrations b.ToTable("PostAttachments"); }); - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.Property("UserId") - .HasColumnType("uuid"); - - b.Property("PostId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "PostId"); - - b.HasIndex("PostId"); - - b.ToTable("RatedPosts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Liked") - .HasColumnType("boolean"); - - b.Property("PostId") - .HasColumnType("uuid"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("UserRates"); - }); - modelBuilder.Entity("DevHive.Data.Models.Role", b => { b.Property("Id") @@ -509,40 +470,6 @@ namespace DevHive.Data.Migrations b.Navigation("Post"); }); - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany("RatedPosts") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId"); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - modelBuilder.Entity("DevHive.Data.Models.User", b => { b.HasOne("DevHive.Data.Models.User", null) @@ -664,8 +591,6 @@ namespace DevHive.Data.Migrations b.Navigation("Posts"); b.Navigation("ProfilePicture"); - - b.Navigation("RatedPosts"); }); #pragma warning restore 612, 618 } -- cgit v1.2.3 From 7d5544626c21b90da0b538da83c112c0f8adec9d Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sat, 27 Mar 2021 08:48:49 +0200 Subject: Updated database name in appsettings and ConnectionString --- src/Data/DevHive.Data/ConnectionString.json | 4 ++-- src/Web/DevHive.Web/appsettings.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/DevHive.Data/ConnectionString.json b/src/Data/DevHive.Data/ConnectionString.json index c8300b2..1281a1c 100644 --- a/src/Data/DevHive.Data/ConnectionString.json +++ b/src/Data/DevHive.Data/ConnectionString.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=password;" + "DEV": "Server=localhost;Port=5432;Database=DevHive_API;User Id=postgres;Password=password;" } -} \ No newline at end of file +} diff --git a/src/Web/DevHive.Web/appsettings.json b/src/Web/DevHive.Web/appsettings.json index 053007d..036af82 100644 --- a/src/Web/DevHive.Web/appsettings.json +++ b/src/Web/DevHive.Web/appsettings.json @@ -5,7 +5,7 @@ "audience": "" }, "ConnectionStrings": { - "DEV": "Server=localhost;Port=5432;Database=DevHive API;User Id=postgres;Password=;" + "DEV": "Server=localhost;Port=5432;Database=DevHive_API;User Id=postgres;Password=;" }, "Cloud": { "cloudName": "devhive", -- cgit v1.2.3 From ca5f507952b2e8b4e24729d648226dd4c7be28aa Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 28 Mar 2021 15:39:33 +0300 Subject: Moved API GitHub wiki data to a docs folder --- docs/API-Endpoints.md | 864 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/Authentication.md | 52 +++ docs/File-Structure.md | 495 ++++++++++++++++++++++++++++ docs/Privacy-Policy.md | 23 ++ 4 files changed, 1434 insertions(+) create mode 100644 docs/API-Endpoints.md create mode 100644 docs/Authentication.md create mode 100644 docs/File-Structure.md create mode 100644 docs/Privacy-Policy.md diff --git a/docs/API-Endpoints.md b/docs/API-Endpoints.md new file mode 100644 index 0000000..503bfc4 --- /dev/null +++ b/docs/API-Endpoints.md @@ -0,0 +1,864 @@ +### Contents: +- [/api/User](#apiuser) + - [/Login](#login) + - [/Register](#register) + - [/GetUser](#getuser) + - [/ProfilePicture](#profilepicture) + - [Get User By Id](#get-user-by-id) + - [Update User By Id](#update-user-by-id) + - [Delete User By Id](#delete-user-by-id) +- [/api/Role](#apirole) + - [Create Role](#create-role) + - [Get Role By Id](#get-role-by-id) + - [Update Role By Id](#update-role-by-id) + - [Delete Role By Id](#delete-role-by-id) +- [/api/Feed](#apifeed) + - [/GetPosts](#getposts) + - [/GetUserPosts](#getuserposts) +- [/api/Post](#apipost) + - [Create Post](#create-post) + - [Get Post By Id](#get-post-by-id) + - [Update Post By Id](#update-post-by-id) + - [Delete Post By Id](#delete-post-by-id) +- [/api/Comment](#apicomment) + - [Create Comment](#create-comment) + - [Get Comment By Id](#get-comment-by-id) + - [Update Comment By Id](#update-comment-by-id) + - [Delete Comment By Id](#delete-comment-by-id) +- [/api/Language](#apilanguage) + - [/GetLanguages](#getlanguages) + - [Create Language](#create-language) + - [Get Language By Id](#get-language-by-id) + - [Update Language By Id](#update-language-by-id) + - [Delete Language By Id](#delete-language-by-id) +- [/api/Technology](#apitechnology) + - [/GetTechnologies](#gettechnologies) + - [Create Technology](#create-technology) + - [Get Technology By Id](#get-technology-by-id) + - [Update Technology By Id](#update-technology-by-id) + - [Delete Technology By Id](#delete-technology-by-id) + +*** + +# /api/User + +## /Login + +||| +|---|---| +|Description|Get a JWT for an existing user| +|Type|POST| +|URL structure|`http://localhost:5000/api/User/login`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; The JWT| +||| + +Sample body: +```json +{ + "userName": "string", + "password": "string" +} +``` +Sample response: +```json +{ + "token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjFiMTU2ZTY3LTVhZmItNGZmMi1hYzRmLTY4NjVmZWI5NzFiYiIsIlVzZXJuYW1lIjoieW9yZ3VzIiwicm9sZSI6IlVzZXIiLCJuYmYiOjE2MTIzMzg5NzIsImV4cCI6MTYxMjkwODAwMCwiaWF0IjoxNjEyMzM4OTcyfQ.dneQidggMu9FD7UXBzn5td3phX3OIgp7y4BygHTqq5Un5D67xH1jZTRQpi9Zqcq76mODvUToAo7j4PFdJtIdtg" +} +``` + +## /Register + +||| +|---|---| +|Description|Add an account to the database and get a JWT| +|Type|POST| +|URL structure|`http://localhost:5000/api/User/register`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; The JWT| + +Sample body: +```json +{ + "userName": "string", + "email": "user@example.com", + "firstName": "string", + "lastName": "string", + "password": "string" +} +``` +Sample response: +```json +{ + "token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjFiMTU2ZTY3LTVhZmItNGZmMi1hYzRmLTY4NjVmZWI5NzFiYiIsIlVzZXJuYW1lIjoieW9yZ3VzIiwicm9sZSI6IlVzZXIiLCJuYmYiOjE2MTIzMzg5NzIsImV4cCI6MTYxMjkwODAwMCwiaWF0IjoxNjEyMzM4OTcyfQ.dneQidggMu9FD7UXBzn5td3phX3OIgp7y4BygHTqq5Un5D67xH1jZTRQpi9Zqcq76mODvUToAo7j4PFdJtIdtg" +} +``` + +## /GetUser + +||| +|---|---| +|Description|Get a user via his UserName| +|Type|GET| +|URL structure|`http://localhost:5000/api/User/GetUser?UserName=test`| +|Authentication|None| +|Body|None| +|Returns|JSON; The object of the user| +||| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [ + ], + "languages": [ + { + "id": "cf40034d-75d7-4792-821d-c16220a5b928" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [ + { + "id": "850d0655-72cb-4477-b69b-35e8645db266" + } + ], + "userName": "test", + "email": "test@bg.com", + "firstName": "Test", + "lastName": "Test" +} +``` + +## /ProfilePicture + +||| +|---|---| +|Description|Update the profile picture of the given User| +|Type|PUT| +|URL structure|`http://localhost:5000/api/User/ProfilePicture?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The link to the uploaded profile picture| +||| + +Sample body: +|Name|Value| +|---|---| +|Picture|`new-profile-picture.png` (this is the actual file)| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4" +} +``` + +## Get User By Id + +||| +|---|---| +|Description|Get a user via his Id| +|Type|GET| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The object of the user| +||| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [ + ], + "languages": [ + { + "id": "cf40034d-75d7-4792-821d-c16220a5b928" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [ + { + "id": "850d0655-72cb-4477-b69b-35e8645db266" + } + ], + "userName": "test", + "email": "test@bg.com", + "firstName": "Test", + "lastName": "Test" +} +``` + +## Update User By Id + +||| +|---|---| +|Description|Modify the values in an existing user (account)| +|Type|PUT| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The updated user object| +||| + +Sample body: +```json +{ + "userName": "string", + "email": "user@example.com", + "firstName": "string", + "lastName": "string", + "password": "string", + "friends": [ + { + "userName": "string" + } + ], + "roles": [ + { + "name": "string" + } + ], + "languages": [ + { + "name": "string" + } + ], + "technologies": [ + { + "name": "string" + } + ] +} +``` +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [], + "languages": [ + { + "id": "33397a3b-46eb-424f-8e19-d88dbf3e953b" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [], + "userName": "test", + "email": "test1@bg.com", + "firstName": "Tester", + "lastName": "Tester" +} +``` + +## Delete User By Id + +||| +|---|---| +|Description|Delete an existing user from the database `WARNING: THIS IS IRREVERSIBLE`| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|Nothing| +||| + +*** + +# /api/Role + +## Create Role + +||| +|---|---| +|Description|Add a new Role to the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Role`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result role object, only with the role Id| +||| + +Sample body: +```json +{ + "name": "string" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Role By Id + +||| +|---|---| +|Description|Get an existing Role via it's Id| +|Type|GET| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The role object, only with it's name| +||| + +Sample response: +```json +{ + "name": "Test" +} +``` + +## Update Role By Id + +||| +|---|---| +|Description|Modify the values (name) of an existing role| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|Nothing| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Role By Id + +||| +|---|---| +|Description|Remove an existing Role from the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|Nothing| +||| + +*** + +# /api/Feed + +## /GetPosts + +||| +|---|---| +|Description|Get a certain amount of the latest posts of a User's friends| +|Type|POST| +|URL structure|`http://localhost:5000/api/Feed/GetPosts?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; An array with the selected posts| +||| + +Sample body: +```json +{ + "pageNumber": 1, + "firstPageTimeIssued": "2022-01-30T18:43:01.082Z", + "pageSize": 5 +} +``` +Sample response: +```json +{ + "posts": [ + { + "postId": "850d0655-72cb-4477-b69b-35e8645db266", + "creatorFirstName": "test", + "creatorLastName": "Test", + "creatorUsername": "Test", + "message": "A sample post", + "timeCreated": "2021-02-03T10:52:38.271647", + "comments": [], + "fileUrls": [] + } + ] +} +``` + +## /GetUserPosts + +||| +|---|---| +|Description|Get a certain amount of the latest posts from a User| +|Type|POST| +|URL structure|`http://localhost:5000/api/GetUserPosts?UserName=test`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; An array with the selected posts| +||| + +Sample body: +```json +{ + "pageNumber": 1, + "firstPageTimeIssued": "2022-01-30T18:43:01.082Z", + "pageSize": 5 +} +``` +Sample response: +```json +{ + "posts": [ + { + "postId": "850d0655-72cb-4477-b69b-35e8645db266", + "creatorFirstName": "test", + "creatorLastName": "Test", + "creatorUsername": "Test", + "message": "A sample post", + "timeCreated": "2021-02-03T10:52:38.271647", + "comments": [], + "fileUrls": [] + } + ] +} +``` + +*** + +# /api/Post + +## Create Post + +||| +|---|---| +|Description|Add a new Post to the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Post?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The result Post object, only with the Post Id| +||| + +Sample body: +|Name|Value| +|---|---| +|Message|The message of my post| +|Files|`attachment.txt` (that is the actual file)| +|Files|`attachment2.txt` (that is the actual file)| +|...|| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Post By Id + +||| +|---|---| +|Description|Get an existing Post from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Post?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Post object| +||| + +Sample response: +```json +{ + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "creatorFirstName": "Test", + "creatorLastName": "Test", + "creatorUsername": "test", + "message": "A sample post", + "timeCreated": "2021-02-02T18:29:31.942772", + "comments": [], + "fileUrls": [] +} +``` + +## Update Post By Id + +||| +|---|---| +|Description|Update the values of an existing post| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Post?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The result Post object, only with the Post Id| +||| + +**Note:** When editing a post's files, they all get replaced, you cannot just add new files. After post is edited, it's "timeCreated" get's updated. + +Sample body: +|Name|Value| +|---|---| +|PostId|1cc9773f-8d9a-4bfd-83ca-2099dc787a39| +|NewMessage|The new message of the post| +|Files|`attachment3.txt` (that is the actual file)| +|Files|`attachment4.txt` (that is the actual file)| +|...| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Delete Post By Id + +||| +|---|---| +|Description|Remove an existing Post from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Post?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Comment + +## Add comment + +||| +|---|---| +|Description|Add a new Comment to an existing Post| +|Type|POST| +|URL structure|`http://localhost:5000/api/Comment?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "message": "First comment" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Comment By Id + +||| +|---|---| +|Description|Get an existing Comment from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Comment?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Comment object| +||| + +Sample response: +```json +{ + "commentId": "086d1a23-c977-4cdc-9bdf-dc81992b3a12", + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "issuerFirstName": "Test", + "issuerLastName": "Test", + "issuerUsername": "test", + "message": "First coment", + "timeCreated": "2021-02-01T13:18:57.434512" +} +``` + +## Update Comment By Id + +||| +|---|---| +|Description|Update the values of an existing comment| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Comment?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "commentId": "086d1a23-c977-4cdc-9bdf-dc81992b3a12", + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "newMessage": "string" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Delete Comment By Id + +||| +|---|---| +|Description|Remove an existing Comment from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Comment?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Language + +## /GetLanguages + +||| +|---|---| +|Description|Get all available Languages from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language/GetLanguages`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The result Language array object| +||| + +Sample response: +```json +[ + { + "id": "5286821a-1407-4daf-ac3e-49153c2d3f66", + "name": "CSharp" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696", + "name": "Perl" + }, + { + "id": "6dc1cb1a-1c4f-41af-8b44-86441cb60136", + "name": "Java" + } +] +``` + +## Create Language + +||| +|---|---| +|Description|Add a new Language in the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Comment`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "name": "Perl" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Language By Id + +||| +|---|---| +|Description|Get an existing Language from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Language object| +||| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "name": "Perl" +} +``` + +## Update Language By Id + +||| +|---|---| +|Description|Update the values of an existing Language| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Language?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|None| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Language By Id + +||| +|---|---| +|Description|Remove an existing Language from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Language?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Technology + +## /GetTechnologies + +||| +|---|---| +|Description|Get all available Technologies from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language/GetTechnologies`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The result Technology array object| +||| + +Sample response: +```json +[ + { + "id": "5286821a-1407-4daf-ac3e-49153c2d3f66", + "name": "ASP.NET" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696", + "name": "Angular" + } +] +``` + +## Create Technology + +||| +|---|---| +|Description|Add a new Technology in the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Technology`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Technology object, only with the Technology Id| +||| + +Sample body: +```json +{ + "name": "Angular" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Technology By Id + +||| +|---|---| +|Description|Get an existing Technology from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Technology?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Technology object| +||| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "name": "Angular" +} +``` + +## Update Technology By Id + +||| +|---|---| +|Description|Update the values of an existing Technology| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Technology?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|None| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Technology By Id + +||| +|---|---| +|Description|Remove an existing Technology from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Technology?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| \ No newline at end of file diff --git a/docs/Authentication.md b/docs/Authentication.md new file mode 100644 index 0000000..f9e6525 --- /dev/null +++ b/docs/Authentication.md @@ -0,0 +1,52 @@ +Certain actions with the API require User authentication. In DevHive, all authentication is done with [JSON Web Tokens](https://en.wikipedia.org/wiki/JSON_Web_Token). + +The JWTs must be sent as a [Bearer Token](https://www.oauth.com/oauth2-servers/differences-between-oauth-1-2/bearer-tokens/). + +## Structure of tokens + +The main contents of a User's token are the `UserName`, `ID` and `Roles`. + +Sample token: +``` +eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjI3ZTIwM2JkLTUzMTItNDgzMS05MzM0LWNkM2MyMGU1ZDY3MiIsIlVzZXJuYW1lIjoidGVzdCIsInJvbGUiOiJVc2VyIiwibmJmIjoxNjEyMzYxOTc1LCJleHAiOjE2MTI5MDgwMDAsImlhdCI6MTYxMjM2MTk3NX0.ZxhDSUsDf9cGig03QpzNgj3dkqbcfAoFXVIfixYGurzhd0l1_IO79UpE_Sb6ZU9hz3IT1XPrlrQ_Kd46L7xcQg +``` +[Decoded](https://jwt.io/): + +- Header +```json +{ + "alg": "HS512", + "typ": "JWT" +} +``` + +- Data +```json +{ + "ID": "27e203bd-5312-4831-9334-cd3c20e5d672", + "Username": "test", + "role": "User", + "nbf": 1612361975, + "exp": 1612908000, + "iat": 1612361975 +} +``` + +- Signature +``` +HMACSHA512( + base64UrlEncode(header) + "." + + base64UrlEncode(payload) +) +``` + +## Token validation + +All token validations are done in the User Service. Depending on the situation, we can differentiate a couple types of authentication: + +||| +|---|---| +|1|Has the role "User" or "Admin"| +|2|Has the role "User" and is the owner/author of the object or has the role "Admin"| +|3|Has the role "Admin"| +||| \ No newline at end of file diff --git a/docs/File-Structure.md b/docs/File-Structure.md new file mode 100644 index 0000000..4d0341e --- /dev/null +++ b/docs/File-Structure.md @@ -0,0 +1,495 @@ +DevHive has a lot of files and it can be hard to really see the whole structure of everything from a first glance. In this document, all of the important/notable files and folders are represented in a tree structure. + +### Contents: +- [Common](#common) +- [Data](#data) +- [Service](#service) +- [Tests](#tests) +- [Web](#web) +- [Full Overview](#full-overview) + +# Common + +``` +└── DevHive.Common + └── Models +    ├── Identity +    │   └── TokenModel.cs +    └── Misc +    ├── IdModel.cs +    ├── PasswordModifications.cs +    └── Patch.cs +``` + +# Data + +``` +└── DevHive.Data +    ├── ConnectionString.json +    ├── DevHiveContext.cs +    ├── DevHiveContextFactory.cs + ├── Interfaces + | ├── Models + | │   ├── IComment.cs + │ |   ├── ILanguage.cs + │ |   ├── IModel.cs + │ |   ├── IPost.cs + │ |   ├── IProfilePicture.cs + │ |   ├── IRating.cs + │ |   ├── IRole.cs + │ |   ├── ITechnology.cs + │ |   └── IUser.cs + | └── Repositories + | ├── ICommentRepository.cs + | ├── IFeedRepository.cs + | ├── ILanguageRepository.cs + | ├── IPostRepository.cs + | ├── IRatingRepository.cs + | ├── IRepository.cs + | ├── IRoleRepository.cs + | ├── ITechnologyRepository.cs + | └── IUserRepository.cs +    ├── Migrations +    ├── Models +    │   ├── Comment.cs +    │   ├── Language.cs +    │   ├── Post.cs +    │   ├── ProfilePicture.cs +    │   ├── Rating.cs +    │   ├── Role.cs +    │   ├── Technology.cs +    │   └── User.cs +    ├── RelationModels +    │   ├── RatedPost.cs +    │   ├── UserFriend.cs +    │   └── UserRate.cs +    └── Repositories +    ├── BaseRepository.cs +    ├── CommentRepository.cs +    ├── FeedRepository.cs +    ├── LanguageRepository.cs +    ├── PostRepository.cs +    ├── RatingRepository.cs +    ├── RoleRepository.cs +    ├── TechnologyRepository.cs +    └── UserRepository.cs +``` + +# Service + +``` +└── DevHive.Services +    ├── Configurations +    │   └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMapings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs +    ├── Interfaces +    │   ├── ICloudService.cs +    │   ├── ICommentService.cs +    │   ├── IFeedService.cs +    │   ├── ILanguageService.cs +    │   ├── IPostService.cs +    │   ├── IRateService.cs +    │   ├── IRoleService.cs +    │   ├── ITechnologyService.cs +    │   └── IUserService.cs +    ├── Models + | ├── Cloud + | │   └── CloudinaryService.cs + | ├── Comment + | │   ├── CreateCommentServiceModel.cs + | │   ├── ReadCommentServiceModel.cs + | │   └── UpdateCommentServiceModel.cs + | ├── Feed + | │   ├── GetPageServiceModel.cs + | │   └── ReadPageServiceModel.cs + | ├── Identity + | │   ├── Role + | │   │   ├── CreateRoleServiceModel.cs + | │   │   ├── RoleServiceModel.cs + | │   │   └── UpdateRoleServiceModel.cs + | │   └── User + | │   ├── BaseUserServiceModel.cs + | │   ├── FriendServiceModel.cs + | │   ├── LoginServiceModel.cs + | │   ├── ProfilePictureServiceModel.cs + | │   ├── RegisterServiceModel.cs + | │   ├── UpdateFriendServiceModel.cs + | │   ├── UpdateProfilePictureServiceModel.cs + | │   ├── UpdateUserServiceModel.cs + | │   └── UserServiceModel.cs + | ├── Language + | │   ├── CreateLanguageServiceModel.cs + | │   ├── LanguageServiceModel.cs + | │   ├── ReadLanguageServiceModel.cs + | │   └── UpdateLanguageServiceModel.cs + | ├── Post + | | ├── Rating + | | │   ├── RatePostServiceModel.cs + | | │   └── ReadPostRatingServiceModel.cs + | │   ├── CreatePostServiceModel.cs + | │   ├── ReadPostServiceModel.cs + | │   └── UpdatePostServiceModel.cs + | └── Technology + | ├── CreateTechnologyServiceModel.cs + | ├── ReadTechnologyServiceModel.cs + | ├── TechnologyServiceModel.cs + | └── UpdateTechnologyServiceModel.cs +    ├── Options +    │   └── JWTOptions.cs +    └── Services +    ├── CommentService.cs +    ├── FeedService.cs +    ├── LanguageService.cs +    ├── PostService.cs +    ├── RateService.cs +    ├── RoleService.cs +    ├── TechnologyService.cs +    └── UserService.cs +``` + +# Tests + +``` +└── DevHive.Tests +    ├── DevHive.Data.Tests +    │   ├── CommentRepository.Tests.cs +    │   ├── FeedRepository.Tests.cs +    │   ├── LenguageRepository.Tests.cs +    │   ├── PostRepository.Tests.cs +    │   ├── RoleRepository.Tests.cs +    │   ├── TechnologyRepository.Tests.cs +    │   └── UserRepositoryTests.cs +    ├── DevHive.Services.Tests +    │   ├── FeedService.Tests.cs +    │   ├── LanguageService.Tests.cs +    │   ├── PostService.Tests.cs +    │   ├── RoleService.Tests.cs +    │   ├── TechnologyServices.Tests.cs +    │   └── UserService.Tests.cs +    └── DevHive.Web.Tests +    ├── LanguageController.Tests.cs +    └── TechnologyController.Tests.cs +``` + +# Web + +``` +└── DevHive.Web + ├── appsettings.json + ├── Attributes + │   ├── GoodPasswordModelValidation.cs + │   └── OnlyLettersModelValidation.cs + ├── Configurations + | ├── Extensions + | │   ├── ConfigureAutoMapper.cs + | │   ├── ConfigureDatabase.cs + | │   ├── ConfigureDependencyInjection.cs + | │   ├── ConfigureExceptionHandlerMiddleware.cs + | │   ├── ConfigureJWT.cs + | │   └── ConfigureSwagger.cs + | └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMappings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs + ├── Controllers + │   ├── CommentController.cs + │   ├── FeedController.cs + │   ├── LanguageController.cs + │   ├── PostController.cs + │   ├── RateController.cs + │   ├── RoleController.cs + │   ├── TechnologyController.cs + │   └── UserController.cs + ├── Middleware + │   └── ExceptionMiddleware.cs + ├── Models + | ├── Comment + | │   ├── CreateCommentWebModel.cs + | │   ├── ReadCommentWebModel.cs + | │   └── UpdateCommentWebModel.cs + | ├── Feed + | │   ├── GetPageWebModel.cs + | │   └── ReadPageWebModel.cs + | ├── Identity + | │   ├── Role + | │   │   ├── CreateRoleWebModel.cs + | │   │   ├── RoleWebModel.cs + | │   │   └── UpdateRoleWebModel.cs + | │   └── User + | │   ├── BaseUserWebModel.cs + | │   ├── LoginWebModel.cs + | │   ├── ProfilePictureWebModel.cs + | │   ├── RegisterWebModel.cs + | │   ├── TokenWebModel.cs + | │   ├── UpdateProfilePictureWebModel.cs + | │   ├── UpdateUserWebModel.cs + | │   ├── UsernameWebModel.cs + | │   └── UserWebModel.cs + | ├── Language + | │   ├── CreateLanguageWebModel.cs + | │   ├── LanguageWebModel.cs + | │   ├── ReadLanguageWebModel.cs + | │   └── UpdateLanguageWebModel.cs + | ├── Post + | │   ├── Rating + | │   │   ├── RatePostWebModel.cs + | │   │   └── ReadPostRatingWebModel.cs + | │   ├── CreatePostWebModel.cs + | │   ├── ReadPostWebModel.cs + | │   └── UpdatePostWebModel.cs + | └── Technology + | ├── CreateTechnologyWebModel.cs + | ├── ReadTechnologyWebModel.cs + | ├── TechnologyWebModel.cs + | └── UpdateTechnologyWebModel.cs + ├── Program.cs + ├── Properties + │   └── launchSettings.json + └── Startup.cs +``` + +# Full overview + +``` +. +├── DevHive.code-workspace +├── DevHive.Common +| └── Models +|    ├── Identity +|    │   └── TokenModel.cs +|    └── Misc +|    ├── IdModel.cs +|    ├── PasswordModifications.cs +|    └── Patch.cs +├── DevHive.Data +│   ├── ConnectionString.json +│   ├── DevHiveContext.cs +│   ├── DevHiveContextFactory.cs +| ├── Interfaces +| | ├── Models +| | │   ├── IComment.cs +| │ |   ├── ILanguage.cs +| │ |   ├── IModel.cs +| │ |   ├── IPost.cs +| │ |   ├── IProfilePicture.cs +| │ |   ├── IRating.cs +| │ |   ├── IRole.cs +| │ |   ├── ITechnology.cs +| │ |   └── IUser.cs +| | └── Repositories +| | ├── ICommentRepository.cs +| | ├── IFeedRepository.cs +| | ├── ILanguageRepository.cs +| | ├── IPostRepository.cs +| | ├── IRatingRepository.cs +| | ├── IRepository.cs +| | ├── IRoleRepository.cs +| | ├── ITechnologyRepository.cs +| | └── IUserRepository.cs +│   ├── Migrations +│   ├── Models +│   │   ├── Comment.cs +│   │   ├── Language.cs +│   │   ├── Post.cs +│   │   ├── ProfilePicture.cs +│   │   ├── Rating.cs +│   │   ├── Role.cs +│   │   ├── Technology.cs +│   │   └── User.cs +│   ├── RelationModels +│   │   ├── RatedPost.cs +│   │   ├── UserFriend.cs +│   │   └── UserRate.cs +│   └── Repositories +│   ├── BaseRepository.cs +│   ├── CommentRepository.cs +│   ├── FeedRepository.cs +│   ├── LanguageRepository.cs +│   ├── PostRepository.cs +│   ├── RatingRepository.cs +│   ├── RoleRepository.cs +│   ├── TechnologyRepository.cs +│   └── UserRepository.cs +├── DevHive.Services +│   ├── Configurations +│   │   └── Mapping +| | ├── CommentMappings.cs +| | ├── FeedMappings.cs +| | ├── LanguageMappings.cs +| | ├── PostMappings.cs +| | ├── RatingMappings.cs +| | ├── RoleMapings.cs +| | ├── TechnologyMappings.cs +| | └── UserMappings.cs +│   ├── Interfaces +│   │   ├── ICloudService.cs +│   │   ├── ICommentService.cs +│   │   ├── IFeedService.cs +│   │   ├── ILanguageService.cs +│   │   ├── IPostService.cs +│   │   ├── IRateService.cs +│   │   ├── IRoleService.cs +│   │   ├── ITechnologyService.cs +│   │   └── IUserService.cs +│   ├── Models +| | ├── Cloud +| | │   └── CloudinaryService.cs +| | ├── Comment +| | │   ├── CreateCommentServiceModel.cs +| | │   ├── ReadCommentServiceModel.cs +| | │   └── UpdateCommentServiceModel.cs +| | ├── Feed +| | │   ├── GetPageServiceModel.cs +| | │   └── ReadPageServiceModel.cs +| | ├── Identity +| | │   ├── Role +| | │   │   ├── CreateRoleServiceModel.cs +| | │   │   ├── RoleServiceModel.cs +| | │   │   └── UpdateRoleServiceModel.cs +| | │   └── User +| | │   ├── BaseUserServiceModel.cs +| | │   ├── FriendServiceModel.cs +| | │   ├── LoginServiceModel.cs +| | │   ├── ProfilePictureServiceModel.cs +| | │   ├── RegisterServiceModel.cs +| | │   ├── UpdateFriendServiceModel.cs +| | │   ├── UpdateProfilePictureServiceModel.cs +| | │   ├── UpdateUserServiceModel.cs +| | │   └── UserServiceModel.cs +| | ├── Language +| | │   ├── CreateLanguageServiceModel.cs +| | │   ├── LanguageServiceModel.cs +| | │   ├── ReadLanguageServiceModel.cs +| | │   └── UpdateLanguageServiceModel.cs +| | ├── Post +| | | ├── Rating +| | | │   ├── RatePostServiceModel.cs +| | | │   └── ReadPostRatingServiceModel.cs +| | │   ├── CreatePostServiceModel.cs +| | │   ├── ReadPostServiceModel.cs +| | │   └── UpdatePostServiceModel.cs +| | └── Technology +| | ├── CreateTechnologyServiceModel.cs +| | ├── ReadTechnologyServiceModel.cs +| | ├── TechnologyServiceModel.cs +| | └── UpdateTechnologyServiceModel.cs +│   ├── Options +│   │   └── JWTOptions.cs +│   └── Services +│   ├── CommentService.cs +│   ├── FeedService.cs +│   ├── LanguageService.cs +│   ├── PostService.cs +│   ├── RateService.cs +│   ├── RoleService.cs +│   ├── TechnologyService.cs +│   └── UserService.cs +├── DevHive.Tests +│   ├── DevHive.Data.Tests +│   │   ├── CommentRepository.Tests.cs +│   │   ├── FeedRepository.Tests.cs +│   │   ├── LenguageRepository.Tests.cs +│   │   ├── PostRepository.Tests.cs +│   │   ├── RoleRepository.Tests.cs +│   │   ├── TechnologyRepository.Tests.cs +│   │   └── UserRepositoryTests.cs +│   ├── DevHive.Services.Tests +│   │   ├── FeedService.Tests.cs +│   │   ├── LanguageService.Tests.cs +│   │   ├── PostService.Tests.cs +│   │   ├── RoleService.Tests.cs +│   │   ├── TechnologyServices.Tests.cs +│   │   └── UserService.Tests.cs +│   └── DevHive.Web.Tests +│   ├── LanguageController.Tests.cs +│   └── TechnologyController.Tests.cs +└── DevHive.Web + ├── appsettings.json + ├── Attributes + │   ├── GoodPasswordModelValidation.cs + │   └── OnlyLettersModelValidation.cs + ├── Configurations + | ├── Extensions + | │   ├── ConfigureAutoMapper.cs + | │   ├── ConfigureDatabase.cs + | │   ├── ConfigureDependencyInjection.cs + | │   ├── ConfigureExceptionHandlerMiddleware.cs + | │   ├── ConfigureJWT.cs + | │   └── ConfigureSwagger.cs + | └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMappings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs + ├── Controllers + │   ├── CommentController.cs + │   ├── FeedController.cs + │   ├── LanguageController.cs + │   ├── PostController.cs + │   ├── RateController.cs + │   ├── RoleController.cs + │   ├── TechnologyController.cs + │   └── UserController.cs + ├── Middleware + │   └── ExceptionMiddleware.cs + ├── Models + | ├── Comment + | │   ├── CreateCommentWebModel.cs + | │   ├── ReadCommentWebModel.cs + | │   └── UpdateCommentWebModel.cs + | ├── Feed + | │   ├── GetPageWebModel.cs + | │   └── ReadPageWebModel.cs + | ├── Identity + | │   ├── Role + | │   │   ├── CreateRoleWebModel.cs + | │   │   ├── RoleWebModel.cs + | │   │   └── UpdateRoleWebModel.cs + | │   └── User + | │   ├── BaseUserWebModel.cs + | │   ├── LoginWebModel.cs + | │   ├── ProfilePictureWebModel.cs + | │   ├── RegisterWebModel.cs + | │   ├── TokenWebModel.cs + | │   ├── UpdateProfilePictureWebModel.cs + | │   ├── UpdateUserWebModel.cs + | │   ├── UsernameWebModel.cs + | │   └── UserWebModel.cs + | ├── Language + | │   ├── CreateLanguageWebModel.cs + | │   ├── LanguageWebModel.cs + | │   ├── ReadLanguageWebModel.cs + | │   └── UpdateLanguageWebModel.cs + | ├── Post + | │   ├── Rating + | │   │   ├── RatePostWebModel.cs + | │   │   └── ReadPostRatingWebModel.cs + | │   ├── CreatePostWebModel.cs + | │   ├── ReadPostWebModel.cs + | │   └── UpdatePostWebModel.cs + | └── Technology + | ├── CreateTechnologyWebModel.cs + | ├── ReadTechnologyWebModel.cs + | ├── TechnologyWebModel.cs + | └── UpdateTechnologyWebModel.cs + ├── Program.cs + ├── Properties + │   └── launchSettings.json + └── Startup.cs +``` diff --git a/docs/Privacy-Policy.md b/docs/Privacy-Policy.md new file mode 100644 index 0000000..c338763 --- /dev/null +++ b/docs/Privacy-Policy.md @@ -0,0 +1,23 @@ +DevHive **doesn't collect any user data, that you haven't personally submitted** (there is no telemetry), and that won't ever change! + +The only potentially sensitive that that could be stored is your profile (first and last name, email, ..) and your posts (if you've shared anything sensitive), but in both cases you've personally given this information. + +## Data on the server + +All data is stored in the database and isn't shared with anyone. The entity that is hosting an instance of the application could expose data to unknown third parties, but DevHive doesn't do anything of the sorts by itself! + +## Data on your machine + +On your computer, the only thing that is saved is your [authentication token](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication) in session storage. This is done so you could stay logged in the website in the current tab, and after closing it, the data gets deleted. + +In the future we could add a cookie to your computer storage, but that will still only hold the token for authentication purposes, so you can reopen your browser and still be logged in. **Tracking and third-party cookies are *never* going to be implemented!** + +## Telemetry by tools + +DevHive itself doesn't collect any type of telemetry, but that isn't the same for the tools it uses. + +The `dotnet` CLI tool is used to run the API, and `dotnet` does [`collect telemetry`](https://docs.microsoft.com/en-us/dotnet/core/tools/telemetry). [The same](https://angular.io/cli/usage-analytics-gathering) can be said for the Angular CLI (`ng`). + +Thankfully in both cases, you can opt out. Ask the administrator(s) of the instance you're using whether they have disabled telemetry. + +**Although**, it's important to mention that **this telemetry might not be collecting your data**, but the data of the server that uses it. Do your own research! \ No newline at end of file -- cgit v1.2.3 From 15904cb3d2ef9442b682322353c378ab321520e5 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 28 Mar 2021 17:43:41 +0300 Subject: Improved formating of response from exception middleware --- src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs index f159b69..e2521bd 100644 --- a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs +++ b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs @@ -2,7 +2,7 @@ using System; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace DevHive.Web.Middleware { @@ -32,11 +32,14 @@ namespace DevHive.Web.Middleware context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.BadRequest; - return context.Response.WriteAsync(new - { - context.Response.StatusCode, - exception.Message - }.ToString()); + // Made to ressemble the formatting of property validation errors (like [MinLength(3)]) + string message = JsonConvert.SerializeObject(new { + errors = new { + Exception = new String[] { exception.Message } + } + }); + + return context.Response.WriteAsync(message); } } } -- cgit v1.2.3 From 8282f6c3f89ee65be155d453ddd705892b07628e Mon Sep 17 00:00:00 2001 From: transtrike Date: Sun, 28 Mar 2021 19:21:49 +0300 Subject: ProfilePic saved in User fixed --- src/Data/DevHive.Data.Models/ProfilePicture.cs | 5 + src/Data/DevHive.Data.Models/User.cs | 3 +- src/Data/DevHive.Data/DevHiveContext.cs | 12 +- ...28161726_Profile_Pic_Property_Alter.Designer.cs | 600 +++++++++++++++++++++ .../20210328161726_Profile_Pic_Property_Alter.cs | 526 ++++++++++++++++++ .../Migrations/DevHiveContextModelSnapshot.cs | 598 ++++++++++++++++++++ .../User/UserServiceModel.cs | 2 +- .../Services/ProfilePictureService.cs | 6 +- 8 files changed, 1745 insertions(+), 7 deletions(-) create mode 100644 src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs create mode 100644 src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs create mode 100644 src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs diff --git a/src/Data/DevHive.Data.Models/ProfilePicture.cs b/src/Data/DevHive.Data.Models/ProfilePicture.cs index 5877861..e8166d7 100644 --- a/src/Data/DevHive.Data.Models/ProfilePicture.cs +++ b/src/Data/DevHive.Data.Models/ProfilePicture.cs @@ -6,8 +6,13 @@ namespace DevHive.Data.Models [Table("ProfilePictures")] public class ProfilePicture { + public const string DefaultURL = "/assets/icons/tabler-icon-user.svg"; + public Guid Id { get; set; } + public Guid UserId { get; set; } + public User User { get; set; } + public string PictureURL { get; set; } } } diff --git a/src/Data/DevHive.Data.Models/User.cs b/src/Data/DevHive.Data.Models/User.cs index f6cd3b9..d3789ec 100644 --- a/src/Data/DevHive.Data.Models/User.cs +++ b/src/Data/DevHive.Data.Models/User.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using DevHive.Data.Models.Relational; using Microsoft.AspNetCore.Identity; namespace DevHive.Data.Models @@ -13,7 +12,7 @@ namespace DevHive.Data.Models public string LastName { get; set; } - public ProfilePicture ProfilePicture { get; set; } = new(); + public ProfilePicture ProfilePicture { get; set; } = new() { PictureURL = ProfilePicture.DefaultURL }; public HashSet Languages { get; set; } = new(); diff --git a/src/Data/DevHive.Data/DevHiveContext.cs b/src/Data/DevHive.Data/DevHiveContext.cs index f8574a4..0606864 100644 --- a/src/Data/DevHive.Data/DevHiveContext.cs +++ b/src/Data/DevHive.Data/DevHiveContext.cs @@ -26,9 +26,6 @@ namespace DevHive.Data .HasIndex(x => x.UserName) .IsUnique(); - builder.Entity() - .HasOne(x => x.ProfilePicture); - /* Roles */ builder.Entity() .HasMany(x => x.Roles) @@ -91,6 +88,15 @@ namespace DevHive.Data .HasMany(x => x.Ratings) .WithOne(x => x.Post); + /* Profile Picture */ + builder.Entity() + .HasKey(x => x.Id); + + builder.Entity() + .HasOne(x => x.ProfilePicture) + .WithOne(x => x.User) + .HasForeignKey(x => x.UserId); + base.OnModelCreating(builder); } } diff --git a/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs new file mode 100644 index 0000000..a3fcb2d --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs @@ -0,0 +1,600 @@ +// +using System; +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("20210328161726_Profile_Pic_Property_Alter")] + partial class Profile_Pic_Property_Alter + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("DevHive.Data.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("TimeCreated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("PictureURL") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ProfilePictures"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsLike") + .HasColumnType("boolean"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Rating"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FileUrl") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostAttachments"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("UserId"); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("LanguageUser", b => + { + b.Property("LanguagesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("LanguagesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("LanguageUser"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("RoleUser", b => + { + b.Property("RolesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("RolesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("RoleUser"); + }); + + modelBuilder.Entity("TechnologyUser", b => + { + b.Property("TechnologiesId") + .HasColumnType("uuid"); + + b.Property("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.Models.Rating", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Ratings") + .HasForeignKey("PostId"); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Attachments") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany("Friends") + .HasForeignKey("UserId"); + }); + + 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", b => + { + b.HasOne("DevHive.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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("Attachments"); + + b.Navigation("Comments"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Navigation("Comments"); + + b.Navigation("Friends"); + + b.Navigation("Posts"); + + b.Navigation("ProfilePicture"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs new file mode 100644 index 0000000..5aca664 --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs @@ -0,0 +1,526 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace DevHive.Data.Migrations +{ + public partial class Profile_Pic_Property_Alter : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + FirstName = table.Column(type: "text", nullable: true), + LastName = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "uuid", nullable: true), + UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "boolean", nullable: false), + PasswordHash = table.Column(type: "text", nullable: true), + SecurityStamp = table.Column(type: "text", nullable: true), + ConcurrencyStamp = table.Column(type: "text", nullable: true), + PhoneNumber = table.Column(type: "text", nullable: true), + PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false), + TwoFactorEnabled = table.Column(type: "boolean", nullable: false), + LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true), + LockoutEnabled = table.Column(type: "boolean", nullable: false), + AccessFailedCount = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUsers_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Languages", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Languages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Technologies", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Technologies", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + RoleId = table.Column(type: "uuid", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column(type: "uuid", nullable: false), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "text", nullable: false), + ProviderKey = table.Column(type: "text", nullable: false), + ProviderDisplayName = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "uuid", nullable: false), + RoleId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "uuid", nullable: false), + LoginProvider = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Posts", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + CreatorId = table.Column(type: "uuid", nullable: true), + Message = table.Column(type: "text", nullable: true), + TimeCreated = table.Column(type: "timestamp without time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Posts", x => x.Id); + table.ForeignKey( + name: "FK_Posts_AspNetUsers_CreatorId", + column: x => x.CreatorId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "ProfilePictures", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: false), + PictureURL = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProfilePictures", x => x.Id); + table.ForeignKey( + name: "FK_ProfilePictures_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "RoleUser", + columns: table => new + { + RolesId = table.Column(type: "uuid", nullable: false), + UsersId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RoleUser", x => new { x.RolesId, x.UsersId }); + table.ForeignKey( + name: "FK_RoleUser_AspNetRoles_RolesId", + column: x => x.RolesId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_RoleUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "LanguageUser", + columns: table => new + { + LanguagesId = table.Column(type: "uuid", nullable: false), + UsersId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_LanguageUser", x => new { x.LanguagesId, x.UsersId }); + table.ForeignKey( + name: "FK_LanguageUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_LanguageUser_Languages_LanguagesId", + column: x => x.LanguagesId, + principalTable: "Languages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TechnologyUser", + columns: table => new + { + TechnologiesId = table.Column(type: "uuid", nullable: false), + UsersId = table.Column(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TechnologyUser", x => new { x.TechnologiesId, x.UsersId }); + table.ForeignKey( + name: "FK_TechnologyUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TechnologyUser_Technologies_TechnologiesId", + column: x => x.TechnologiesId, + principalTable: "Technologies", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Comments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + PostId = table.Column(type: "uuid", nullable: true), + CreatorId = table.Column(type: "uuid", nullable: true), + Message = table.Column(type: "text", nullable: true), + TimeCreated = table.Column(type: "timestamp without time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Comments", x => x.Id); + table.ForeignKey( + name: "FK_Comments_AspNetUsers_CreatorId", + column: x => x.CreatorId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Comments_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "PostAttachments", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + PostId = table.Column(type: "uuid", nullable: true), + FileUrl = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PostAttachments", x => x.Id); + table.ForeignKey( + name: "FK_PostAttachments_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Rating", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + UserId = table.Column(type: "uuid", nullable: true), + PostId = table.Column(type: "uuid", nullable: true), + IsLike = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Rating", x => x.Id); + table.ForeignKey( + name: "FK_Rating_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Rating_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_UserId", + table: "AspNetUsers", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_UserName", + table: "AspNetUsers", + column: "UserName", + unique: true); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Comments_CreatorId", + table: "Comments", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Comments_PostId", + table: "Comments", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_LanguageUser_UsersId", + table: "LanguageUser", + column: "UsersId"); + + migrationBuilder.CreateIndex( + name: "IX_PostAttachments_PostId", + table: "PostAttachments", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_CreatorId", + table: "Posts", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_ProfilePictures_UserId", + table: "ProfilePictures", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Rating_PostId", + table: "Rating", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_Rating_UserId", + table: "Rating", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_RoleUser_UsersId", + table: "RoleUser", + column: "UsersId"); + + migrationBuilder.CreateIndex( + name: "IX_TechnologyUser_UsersId", + table: "TechnologyUser", + column: "UsersId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "Comments"); + + migrationBuilder.DropTable( + name: "LanguageUser"); + + migrationBuilder.DropTable( + name: "PostAttachments"); + + migrationBuilder.DropTable( + name: "ProfilePictures"); + + migrationBuilder.DropTable( + name: "Rating"); + + migrationBuilder.DropTable( + name: "RoleUser"); + + migrationBuilder.DropTable( + name: "TechnologyUser"); + + migrationBuilder.DropTable( + name: "Languages"); + + migrationBuilder.DropTable( + name: "Posts"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "Technologies"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs new file mode 100644 index 0000000..242473b --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs @@ -0,0 +1,598 @@ +// +using System; +using DevHive.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace DevHive.Data.Migrations +{ + [DbContext(typeof(DevHiveContext))] + partial class DevHiveContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.3") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("DevHive.Data.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatorId") + .HasColumnType("uuid"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("TimeCreated") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("CreatorId"); + + b.ToTable("Posts"); + }); + + modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("PictureURL") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("ProfilePictures"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Rating", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsLike") + .HasColumnType("boolean"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("UserId"); + + b.ToTable("Rating"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FileUrl") + .HasColumnType("text"); + + b.Property("PostId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("PostAttachments"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.HasIndex("UserId"); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("LanguageUser", b => + { + b.Property("LanguagesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("LanguagesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("LanguageUser"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uuid"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("RoleUser", b => + { + b.Property("RolesId") + .HasColumnType("uuid"); + + b.Property("UsersId") + .HasColumnType("uuid"); + + b.HasKey("RolesId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("RoleUser"); + }); + + modelBuilder.Entity("TechnologyUser", b => + { + b.Property("TechnologiesId") + .HasColumnType("uuid"); + + b.Property("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.Models.Rating", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Ratings") + .HasForeignKey("PostId"); + + b.HasOne("DevHive.Data.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Post"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => + { + b.HasOne("DevHive.Data.Models.Post", "Post") + .WithMany("Attachments") + .HasForeignKey("PostId"); + + b.Navigation("Post"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany("Friends") + .HasForeignKey("UserId"); + }); + + 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", b => + { + b.HasOne("DevHive.Data.Models.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("DevHive.Data.Models.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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("Attachments"); + + b.Navigation("Comments"); + + b.Navigation("Ratings"); + }); + + modelBuilder.Entity("DevHive.Data.Models.User", b => + { + b.Navigation("Comments"); + + b.Navigation("Friends"); + + b.Navigation("Posts"); + + b.Navigation("ProfilePicture"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Services/DevHive.Services.Models/User/UserServiceModel.cs b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs index ad4e553..f48c703 100644 --- a/src/Services/DevHive.Services.Models/User/UserServiceModel.cs +++ b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs @@ -8,7 +8,7 @@ namespace DevHive.Services.Models.User { public class UserServiceModel : BaseUserServiceModel { - public string ProfilePictureURL { get; set; } = new("/assets/icons/tabler-icon-user.svg"); + public string ProfilePictureURL { get; set; } = new(string.Empty); public HashSet Roles { get; set; } = new(); diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs index 7093818..0a4c824 100644 --- a/src/Services/DevHive.Services/Services/ProfilePictureService.cs +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -41,6 +41,7 @@ namespace DevHive.Services.Services await ValidateUserExistsAsync(profilePictureServiceModel.UserId); User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + // if (user.ProfilePicture.PictureURL != ProfilePicture.DefaultURL) if (user.ProfilePicture.Id != Guid.Empty) { List file = new() { user.ProfilePicture.PictureURL }; @@ -76,11 +77,14 @@ namespace DevHive.Services.Services string picUrl = (await this._cloudinaryService.UploadFilesToCloud(file))[0]; ProfilePicture profilePic = new() { PictureURL = picUrl }; + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + profilePic.UserId = user.Id; + profilePic.User = user; + bool success = await this._profilePictureRepository.AddAsync(profilePic); if (!success) throw new ArgumentException("Unable to upload picture!"); - User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); user.ProfilePicture = profilePic; bool userProfilePicAlter = await this._userRepository.EditAsync(user.Id, user); -- cgit v1.2.3 From 92c8160d4796c6a4cefb5770f4f4ff1e082e3f41 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Sun, 28 Mar 2021 19:34:06 +0300 Subject: Uploading files to cloudinary now uses the filename, not a guid --- src/Services/DevHive.Services/Services/CloudinaryService.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs index 57955a2..6e2e975 100644 --- a/src/Services/DevHive.Services/Services/CloudinaryService.cs +++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudinaryDotNet; using CloudinaryDotNet.Actions; @@ -11,6 +12,10 @@ namespace DevHive.Services.Services { public class CloudinaryService : ICloudService { + // Regex for getting the filename without (final) filename extension + // So, from image.png, it will match image, and from doc.my.txt will match doc.my + private static Regex _imageRegex = new Regex(".*(?=\\.)"); + private readonly Cloudinary _cloudinary; public CloudinaryService(string cloudName, string apiKey, string apiSecret) @@ -23,7 +28,7 @@ namespace DevHive.Services.Services List fileUrls = new(); foreach (var formFile in formFiles) { - string formFileId = Guid.NewGuid().ToString(); + string fileName = _imageRegex.Match(formFile.FileName).ToString(); using (var ms = new MemoryStream()) { @@ -32,8 +37,8 @@ namespace DevHive.Services.Services RawUploadParams rawUploadParams = new() { - File = new FileDescription(formFileId, new MemoryStream(formBytes)), - PublicId = formFileId, + File = new FileDescription(fileName, new MemoryStream(formBytes)), + PublicId = fileName, UseFilename = true }; -- cgit v1.2.3 From 418c04807eae6220ef609a8c208d67c08cf7f723 Mon Sep 17 00:00:00 2001 From: transtrike Date: Sun, 28 Mar 2021 21:58:50 +0300 Subject: Added profile picture documentation --- .../ProfilePictureService.Tests.cs | 9 +++++++++ .../Interfaces/IProfilePictureService.cs | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs diff --git a/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs new file mode 100644 index 0000000..691b8b5 --- /dev/null +++ b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs @@ -0,0 +1,9 @@ +using System; + +namespace DevHive.Services.Tests +{ + public class ProfilePictureServiceTests + { + + } +} diff --git a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs index b0673ac..c455831 100644 --- a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs +++ b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs @@ -6,17 +6,32 @@ namespace DevHive.Services.Interfaces { public interface IProfilePictureService { + /// + /// Inserts a user's profile picture in the database and cloud + /// + /// User's Guid and his/hers profile picture as file + /// The new profile picture's URL in the cloud Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + /// + /// Get a profile picture by it's Guid + /// + /// Profile picture's Guid + /// The profile picture's URL in the cloud Task GetProfilePictureById(Guid id); /// /// Uploads the given picture and assigns it's link to the user in the database /// /// Contains User's Guid and the new picture to be updated - /// The new picture's URL + /// The new profile picture's URL in the cloud Task UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + /// + /// Delete a profile picture from the cloud and the database + /// + /// The profile picture's Guid + /// True if the picture is deleted, false otherwise Task DeleteProfilePicture(Guid id); } } -- cgit v1.2.3 From 0cf2a3c99141f878168271e53999cdacac95f3c4 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Mon, 29 Mar 2021 13:03:10 +0300 Subject: Fixed warnings for commented code and async cloudinary method --- src/Data/DevHive.Data/Repositories/PostRepository.cs | 3 --- src/Services/DevHive.Services/Services/CloudinaryService.cs | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/DevHive.Data/Repositories/PostRepository.cs b/src/Data/DevHive.Data/Repositories/PostRepository.cs index 0a88cf2..b5228c2 100644 --- a/src/Data/DevHive.Data/Repositories/PostRepository.cs +++ b/src/Data/DevHive.Data/Repositories/PostRepository.cs @@ -60,7 +60,6 @@ namespace DevHive.Data.Repositories public override async Task EditAsync(Guid id, Post newEntity) { Post post = await this.GetByIdAsync(id); - // var ratingId = post.Rating.Id; this._context .Entry(post) @@ -76,8 +75,6 @@ namespace DevHive.Data.Repositories foreach (var comment in newEntity.Comments) post.Comments.Add(comment); - // post.Rating.Id = ratingId; - this._context.Entry(post).State = EntityState.Modified; return await this.SaveChangesAsync(); diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs index 6e2e975..05600cc 100644 --- a/src/Services/DevHive.Services/Services/CloudinaryService.cs +++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs @@ -52,6 +52,9 @@ namespace DevHive.Services.Services public async Task RemoveFilesFromCloud(List fileUrls) { + // Workaround, this method isn't fully implemented yet + await Task.Run(null); + return true; } } -- cgit v1.2.3 From d672c515eb760a5351affeb5600640569ed5ee16 Mon Sep 17 00:00:00 2001 From: transtrike Date: Tue, 30 Mar 2021 11:46:58 +0300 Subject: First test implementation and exploration --- .../ProfilePictureService.Tests.cs | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs index 691b8b5..a7a2963 100644 --- a/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs +++ b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs @@ -1,9 +1,84 @@ using System; +using System.IO; +using System.Threading.Tasks; +using DevHive.Data; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Data.Repositories; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using DevHive.Services.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Moq; +using NUnit.Framework; namespace DevHive.Services.Tests { + [TestFixture] public class ProfilePictureServiceTests { + private DevHiveContext _context; + private Mock _userRepositoryMock; + private Mock _profilePictureRepository; + private Mock _cloudService; + private ProfilePictureService _profilePictureService; + [SetUp] + public void Setup() + { + DbContextOptionsBuilder options = new DbContextOptionsBuilder() + .UseInMemoryDatabase("DevHive_UserRepository_Database"); + this._context = new DevHiveContext(options.Options); + this._userRepositoryMock = new Mock(); + this._profilePictureRepository = new Mock(this._context); + this._cloudService = new Mock(); + + this._profilePictureService = new ProfilePictureService( + this._userRepositoryMock.Object, + this._profilePictureRepository.Object, + this._cloudService.Object + ); + } + + [Test] + public async Task InsertProfilePicture_ShouldInsertProfilePicToDatabaseAndUploadToCloud() + { + //Arrange + Guid userId = Guid.NewGuid(); + Mock fileMock = new(); + + //File mocking setup + var content = "Hello World from a Fake File"; + var fileName = "test.jpg"; + var ms = new MemoryStream(); + var writer = new StreamWriter(ms); + writer.Write(content); + writer.Flush(); + ms.Position = 0; + fileMock.Setup(p => p.FileName).Returns(fileName); + fileMock.Setup(p => p.Length).Returns(ms.Length); + fileMock.Setup(p => p.OpenReadStream()).Returns(ms); + + //User Setup + this._userRepositoryMock + .Setup(p => p.GetByIdAsync(userId)) + .ReturnsAsync(new User() + { + Id = userId + }); + + ProfilePictureServiceModel profilePictureServiceModel = new() + { + UserId = userId, + ProfilePictureFormFile = fileMock.Object + }; + + //Act + string profilePicURL = await this._profilePictureService.InsertProfilePicture(profilePictureServiceModel); + + //Assert + Assert.IsNotEmpty(profilePicURL); + } } } -- cgit v1.2.3 From fb421f1ab78c1358af5dddc467db7ab02a59110d Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 2 Apr 2021 11:30:02 +0300 Subject: Introduced Logger; Replaced DevExcHandler with Custom; Logging Errors to file; Replaced Console logger for requests --- .../DevHive.Common.Models.csproj | 2 +- src/Common/DevHive.Common/DevHive.Common.csproj | 4 +-- .../DevHive.Data.Models/DevHive.Data.Models.csproj | 4 +-- .../DevHive.Data.Tests/DevHive.Data.Tests.csproj | 4 +-- src/Data/DevHive.Data/DevHive.Data.csproj | 6 ++-- .../DevHive.Services.Models.csproj | 2 +- .../DevHive.Services.Tests.csproj | 4 +-- .../DevHive.Services/DevHive.Services.csproj | 8 ++--- .../DevHive.Web.Models/DevHive.Web.Models.csproj | 2 +- src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj | 2 +- .../Configurations/Extensions/ConfigureDatabase.cs | 2 +- src/Web/DevHive.Web/DevHive.Web.csproj | 31 ++++++++++-------- .../DevHive.Web/Middleware/ExceptionMiddleware.cs | 8 ++--- src/Web/DevHive.Web/Program.cs | 26 ++++++++++++++- src/Web/DevHive.Web/Startup.cs | 6 +++- src/Web/DevHive.Web/appsettings.json | 38 +++++++++++++++++++--- 16 files changed, 103 insertions(+), 46 deletions(-) diff --git a/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj index a952c59..db8d1c9 100644 --- a/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj +++ b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj @@ -4,7 +4,7 @@ - + true diff --git a/src/Common/DevHive.Common/DevHive.Common.csproj b/src/Common/DevHive.Common/DevHive.Common.csproj index cd60d85..a5758f4 100644 --- a/src/Common/DevHive.Common/DevHive.Common.csproj +++ b/src/Common/DevHive.Common/DevHive.Common.csproj @@ -6,6 +6,6 @@ net5.0 - + - + \ No newline at end of file diff --git a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj index d249c77..2958f86 100644 --- a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj +++ b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj @@ -4,7 +4,7 @@ - - + + \ No newline at end of file diff --git a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj index 25b2b39..e9b33e5 100644 --- a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj +++ b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj @@ -4,12 +4,12 @@ false - + - + diff --git a/src/Data/DevHive.Data/DevHive.Data.csproj b/src/Data/DevHive.Data/DevHive.Data.csproj index fcdb7ae..62320f7 100644 --- a/src/Data/DevHive.Data/DevHive.Data.csproj +++ b/src/Data/DevHive.Data/DevHive.Data.csproj @@ -5,14 +5,14 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj index a55972a..2345a8e 100644 --- a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj +++ b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj @@ -4,7 +4,7 @@ - + diff --git a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj index d85eea2..4a7237b 100644 --- a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj +++ b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj @@ -4,12 +4,12 @@ false - + - + diff --git a/src/Services/DevHive.Services/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj index f51c1b6..2468711 100644 --- a/src/Services/DevHive.Services/DevHive.Services.csproj +++ b/src/Services/DevHive.Services/DevHive.Services.csproj @@ -4,15 +4,15 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - - + + diff --git a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj index 9d62eee..79c856f 100644 --- a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj +++ b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj @@ -8,6 +8,6 @@ - + \ No newline at end of file diff --git a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj index 5099119..49a9173 100644 --- a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj +++ b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs index 1bd8df0..b4c49b4 100644 --- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs +++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs @@ -18,7 +18,7 @@ namespace DevHive.Web.Configurations.Extensions { services.AddDbContext(options => { - options.EnableSensitiveDataLogging(true); + // options.EnableSensitiveDataLogging(true); options.UseNpgsql(configuration.GetConnectionString("DEV"), options => { options.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); diff --git a/src/Web/DevHive.Web/DevHive.Web.csproj b/src/Web/DevHive.Web/DevHive.Web.csproj index 39322ae..5b3a920 100644 --- a/src/Web/DevHive.Web/DevHive.Web.csproj +++ b/src/Web/DevHive.Web/DevHive.Web.csproj @@ -9,25 +9,30 @@ true - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs index e2521bd..ebec5e8 100644 --- a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs +++ b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs @@ -32,12 +32,8 @@ namespace DevHive.Web.Middleware context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.BadRequest; - // Made to ressemble the formatting of property validation errors (like [MinLength(3)]) - string message = JsonConvert.SerializeObject(new { - errors = new { - Exception = new String[] { exception.Message } - } - }); + // Made to resemble the formatting of property validation errors (like [MinLength(3)]) + string message = JsonConvert.SerializeObject(new { Error = exception.Message }); return context.Response.WriteAsync(message); } diff --git a/src/Web/DevHive.Web/Program.cs b/src/Web/DevHive.Web/Program.cs index fdb6889..e7c47a9 100644 --- a/src/Web/DevHive.Web/Program.cs +++ b/src/Web/DevHive.Web/Program.cs @@ -1,5 +1,8 @@ +using System; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Configuration; +using Serilog; namespace DevHive.Web { @@ -11,11 +14,32 @@ namespace DevHive.Web public static void Main(string[] args) { - CreateHostBuilder(args).Build().Run(); + var config = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(config) + .CreateLogger(); + + try + { + Log.Information("Application Starting Up"); + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "The application failed to start correctly."); + } + finally + { + Log.CloseAndFlush(); + } } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) + .UseSerilog() .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureKestrel(opt => opt.ListenLocalhost(HTTP_PORT)); diff --git a/src/Web/DevHive.Web/Startup.cs b/src/Web/DevHive.Web/Startup.cs index 002c718..05a75d9 100644 --- a/src/Web/DevHive.Web/Startup.cs +++ b/src/Web/DevHive.Web/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using DevHive.Web.Configurations.Extensions; using Newtonsoft.Json; +using Serilog; namespace DevHive.Web { @@ -46,7 +47,8 @@ namespace DevHive.Web if (env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); + app.UseExceptionHandlerMiddlewareConfiguration(); + // app.UseDeveloperExceptionPage(); } else { @@ -58,6 +60,8 @@ namespace DevHive.Web app.UseDatabaseConfiguration(); app.UseAutoMapperConfiguration(); + app.UseSerilogRequestLogging(); + app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( diff --git a/src/Web/DevHive.Web/appsettings.json b/src/Web/DevHive.Web/appsettings.json index 036af82..84d534d 100644 --- a/src/Web/DevHive.Web/appsettings.json +++ b/src/Web/DevHive.Web/appsettings.json @@ -12,11 +12,39 @@ "apiKey": "488664116365813", "apiSecret": "" }, - "Logging": { - "LogLevel": { + "Serilog": { + "Using": [], + "LevelSwitches": { + "$consoleSwitch": "Verbose", + "$fileSwitch": "Error" + }, + "MinimumLevel": { "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } + "Override": { + "Microsoft": "Warning", + "System": "Warning" + } + }, + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithProcessId", + "WithThreadId" + ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "levelSwitch": "$consoleSwitch" + } + }, + { + "Name": "File", + "Args": { + "path": "./Logs/errors.log", + "levelSwitch": "$fileSwitch" + } + } + ] } } -- cgit v1.2.3 From 19172a7b0a0f07144943fa7df9fb9090c9a87ec1 Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 2 Apr 2021 11:31:18 +0300 Subject: Excluding Log folder in gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 32533c2..ff542fa 100644 --- a/.gitignore +++ b/.gitignore @@ -354,4 +354,5 @@ MigrationBackup/ *.blob appsettings.Development.json **/.vscode/ -**/*.swp \ No newline at end of file +**/*.swp +**/Logs -- cgit v1.2.3 From adff0d579e7e23fd78cce144b358f98737c91bcf Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 2 Apr 2021 23:23:49 +0300 Subject: InsertProfilePic removed(useless, since every User has one at creation that gets replaced) --- src/Services/DevHive.Services/Services/ProfilePictureService.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs index 0a4c824..1de2114 100644 --- a/src/Services/DevHive.Services/Services/ProfilePictureService.cs +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -22,14 +22,6 @@ namespace DevHive.Services.Services this._cloudinaryService = cloudinaryService; } - public async Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) - { - ValidateProfPic(profilePictureServiceModel.ProfilePictureFormFile); - await ValidateUserExistsAsync(profilePictureServiceModel.UserId); - - return await SaveProfilePictureInDatabase(profilePictureServiceModel); - } - public async Task GetProfilePictureById(Guid id) { return (await this._profilePictureRepository.GetByIdAsync(id)).PictureURL; -- cgit v1.2.3 From b0c6c6e1795a1cc8fe82a60ce16a263ab4cad397 Mon Sep 17 00:00:00 2001 From: transtrike Date: Fri, 2 Apr 2021 23:53:11 +0300 Subject: ReadProfilePic endpoint implemented --- .../DevHive.Services/Interfaces/IProfilePictureService.cs | 7 ------- .../DevHive.Web/Controllers/ProfilePictureController.cs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs index c455831..edf2775 100644 --- a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs +++ b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs @@ -6,13 +6,6 @@ namespace DevHive.Services.Interfaces { public interface IProfilePictureService { - /// - /// Inserts a user's profile picture in the database and cloud - /// - /// User's Guid and his/hers profile picture as file - /// The new profile picture's URL in the cloud - Task InsertProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); - /// /// Get a profile picture by it's Guid /// diff --git a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs index 1c736f6..9a76e2c 100644 --- a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs +++ b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs @@ -28,6 +28,20 @@ namespace DevHive.Web.Controllers this._profilePictureMapper = profilePictureMapper; } + /// + /// Get the URL of user's profile picture + /// + /// The profile picture's Id + /// JWT Bearer Token + /// The URL of the profile picture + [HttpGet] + [AllowAnonymous] + public async Task ReadProfilePicture(Guid profilePictureId, [FromHeader] string authorization) + { + string profilePicURL = await this._profilePictureService.GetProfilePictureById(profilePictureId); + return new OkObjectResult(new { ProfilePictureURL = profilePicURL} ); + } + /// /// Alter the profile picture of a user /// -- cgit v1.2.3 From da7d6223c261aac8e8f18458c11fb48cf9ca4cfe Mon Sep 17 00:00:00 2001 From: transtrike Date: Mon, 5 Apr 2021 13:41:31 +0300 Subject: Introduced consts for every string possible. FML --- .../DevHive.Common/Constants/ClassesConstants.cs | 22 +++++++ .../DevHive.Common/Constants/ErrorMessages.cs | 16 +++++ src/Data/DevHive.Data.Models/Comment.cs | 4 -- .../DevHive.Data/Repositories/RatingRepository.cs | 10 ++-- .../DevHive.Services.Tests/UserService.Tests.cs | 2 +- .../DevHive.Services/Services/CloudinaryService.cs | 30 +++++----- .../DevHive.Services/Services/CommentService.cs | 29 ++++----- .../DevHive.Services/Services/FeedService.cs | 14 +++-- .../DevHive.Services/Services/LanguageService.cs | 12 ++-- .../DevHive.Services/Services/PostService.cs | 41 ++++++------- .../Services/ProfilePictureService.cs | 18 +++--- .../DevHive.Services/Services/RatingService.cs | 17 +++--- .../DevHive.Services/Services/RoleService.cs | 12 ++-- .../DevHive.Services/Services/TechnologyService.cs | 12 ++-- .../DevHive.Services/Services/UserService.cs | 69 ++++++++++++---------- 15 files changed, 177 insertions(+), 131 deletions(-) create mode 100644 src/Common/DevHive.Common/Constants/ClassesConstants.cs create mode 100644 src/Common/DevHive.Common/Constants/ErrorMessages.cs diff --git a/src/Common/DevHive.Common/Constants/ClassesConstants.cs b/src/Common/DevHive.Common/Constants/ClassesConstants.cs new file mode 100644 index 0000000..825f737 --- /dev/null +++ b/src/Common/DevHive.Common/Constants/ClassesConstants.cs @@ -0,0 +1,22 @@ +namespace DevHive.Common.Constants +{ + public static class ClassesConstants + { + public const string Data = "Data"; + + public const string Post = "The Post"; + public const string Comment = "The Comment"; + public const string User = "The User"; + public const string Language = "The Language"; + public const string Picture = "The Picture"; + public const string Files = "The Files"; + public const string Rating = "The Rating"; + public const string Role = "The Role"; + public const string Technology = "The Technology"; + + public const string Username = "The Username"; + public const string Email = "The Email"; + public const string Password = "Password"; + public const string OneOrMoreFriends = "One or more Friends"; + } +} diff --git a/src/Common/DevHive.Common/Constants/ErrorMessages.cs b/src/Common/DevHive.Common/Constants/ErrorMessages.cs new file mode 100644 index 0000000..30ca544 --- /dev/null +++ b/src/Common/DevHive.Common/Constants/ErrorMessages.cs @@ -0,0 +1,16 @@ +namespace DevHive.Common.Constants +{ + public static class ErrorMessages + { + public const string InvalidData = "Invalid {0}!"; + public const string IncorrectData = "Incorrect {0}!"; + public const string DoesNotExist = "{0} does not exist!"; + public const string AlreadyExists = "{0} already exists!"; + + public const string CannotAdd = "Could not add {0}!"; + public const string CannotCreate = "Could not create {0}!"; + public const string CannotDelete = "Could not delete {0}!"; + public const string CannotUpload = "Could not upload {0}!"; + public const string CannotEdit = "Could not edit {0}!"; + } +} diff --git a/src/Data/DevHive.Data.Models/Comment.cs b/src/Data/DevHive.Data.Models/Comment.cs index 0af40bf..8a58edd 100644 --- a/src/Data/DevHive.Data.Models/Comment.cs +++ b/src/Data/DevHive.Data.Models/Comment.cs @@ -6,12 +6,8 @@ namespace DevHive.Data.Models { public Guid Id { get; set; } - // public Guid PostId { get; set; } - public Post Post { get; set; } - // public Guid CreatorId { get; set; } - public User Creator { get; set; } public string Message { get; set; } diff --git a/src/Data/DevHive.Data/Repositories/RatingRepository.cs b/src/Data/DevHive.Data/Repositories/RatingRepository.cs index c35f6d5..2048c3f 100644 --- a/src/Data/DevHive.Data/Repositories/RatingRepository.cs +++ b/src/Data/DevHive.Data/Repositories/RatingRepository.cs @@ -11,13 +11,11 @@ namespace DevHive.Data.Repositories public class RatingRepository : BaseRepository, IRatingRepository { private readonly DevHiveContext _context; - private readonly IPostRepository _postRepository; - public RatingRepository(DevHiveContext context, IPostRepository postRepository) + public RatingRepository(DevHiveContext context) : base(context) { this._context = context; - this._postRepository = postRepository; } public override async Task GetByIdAsync(Guid id) @@ -28,7 +26,7 @@ namespace DevHive.Data.Repositories .FirstOrDefaultAsync(x => x.Id == id); } /// - /// Gets all the ratings for a psot. + /// Gets all the ratings for a post. /// /// Id of the post. /// @@ -40,10 +38,10 @@ namespace DevHive.Data.Repositories .Where(x => x.Post.Id == postId).ToListAsync(); } /// - /// Checks if a user rated a given post. In DevHive every user has one or no rating for every post. + /// Checks if a user rated a given post. In DevHive every user has one or no rating for every post. /// /// Id of the user. - /// Id of the psot. + /// Id of the post. /// True if the user has already rated the post and false if he hasn't. public async Task UserRatedPost(Guid userId, Guid postId) { diff --git a/src/Services/DevHive.Services.Tests/UserService.Tests.cs b/src/Services/DevHive.Services.Tests/UserService.Tests.cs index 7990b32..9d1bca5 100644 --- a/src/Services/DevHive.Services.Tests/UserService.Tests.cs +++ b/src/Services/DevHive.Services.Tests/UserService.Tests.cs @@ -344,7 +344,7 @@ namespace DevHive.Services.Tests // } // else // { - // const string EXCEPTION_MESSAGE = "Unable to edit user!"; + // const string EXCEPTION_MESSAGE = string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower()); // // Exception ex = Assert.ThrowsAsync(() => this._userService.UpdateUser(updateUserServiceModel); // diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs index 05600cc..078bb5d 100644 --- a/src/Services/DevHive.Services/Services/CloudinaryService.cs +++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs @@ -14,7 +14,7 @@ namespace DevHive.Services.Services { // Regex for getting the filename without (final) filename extension // So, from image.png, it will match image, and from doc.my.txt will match doc.my - private static Regex _imageRegex = new Regex(".*(?=\\.)"); + private static readonly Regex s_imageRegex = new(".*(?=\\.)"); private readonly Cloudinary _cloudinary; @@ -28,23 +28,21 @@ namespace DevHive.Services.Services List fileUrls = new(); foreach (var formFile in formFiles) { - string fileName = _imageRegex.Match(formFile.FileName).ToString(); + string fileName = s_imageRegex.Match(formFile.FileName).ToString(); - using (var ms = new MemoryStream()) + using var ms = new MemoryStream(); + formFile.CopyTo(ms); + byte[] formBytes = ms.ToArray(); + + RawUploadParams rawUploadParams = new() { - formFile.CopyTo(ms); - byte[] formBytes = ms.ToArray(); - - RawUploadParams rawUploadParams = new() - { - File = new FileDescription(fileName, new MemoryStream(formBytes)), - PublicId = fileName, - UseFilename = true - }; - - RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); - fileUrls.Add(rawUploadResult.Url.AbsoluteUri); - } + File = new FileDescription(fileName, new MemoryStream(formBytes)), + PublicId = fileName, + UseFilename = true + }; + + RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); + fileUrls.Add(rawUploadResult.Url.AbsoluteUri); } return fileUrls; diff --git a/src/Services/DevHive.Services/Services/CommentService.cs b/src/Services/DevHive.Services/Services/CommentService.cs index b48bac8..1c388f6 100644 --- a/src/Services/DevHive.Services/Services/CommentService.cs +++ b/src/Services/DevHive.Services/Services/CommentService.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; +using DevHive.Data.Interfaces; using DevHive.Data.Models; -using DevHive.Services.Models.Comment; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Services.Models.Comment; namespace DevHive.Services.Services { @@ -31,7 +32,7 @@ namespace DevHive.Services.Services public async Task AddComment(CreateCommentServiceModel createCommentServiceModel) { if (!await this._postRepository.DoesPostExist(createCommentServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Comment comment = this._postMapper.Map(createCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -56,10 +57,10 @@ namespace DevHive.Services.Services public async Task GetCommentById(Guid id) { Comment comment = await this._commentRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The comment does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this._userRepository.GetByIdAsync(comment.Creator.Id) ?? - throw new ArgumentException("The user does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); ReadCommentServiceModel readCommentServiceModel = this._postMapper.Map(comment); readCommentServiceModel.IssuerFirstName = user.FirstName; @@ -74,7 +75,7 @@ namespace DevHive.Services.Services public async Task UpdateComment(UpdateCommentServiceModel updateCommentServiceModel) { if (!await this._commentRepository.DoesCommentExist(updateCommentServiceModel.CommentId)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = this._postMapper.Map(updateCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -95,7 +96,7 @@ namespace DevHive.Services.Services public async Task DeleteComment(Guid id) { if (!await this._commentRepository.DoesCommentExist(id)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = await this._commentRepository.GetByIdAsync(id); return await this._commentRepository.DeleteAsync(comment); @@ -121,7 +122,7 @@ namespace DevHive.Services.Services public async Task ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this.GetUserForValidation(rawTokenData); //If user made the comment @@ -141,10 +142,10 @@ namespace DevHive.Services.Services { JwtSecurityToken jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7)); - Guid jwtUserId = Guid.Parse(this.GetClaimTypeValues("ID", jwt.Claims).First()); + Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } @@ -152,7 +153,7 @@ namespace DevHive.Services.Services /// /// Returns all values from a given claim type /// - private List GetClaimTypeValues(string type, IEnumerable claims) + private static List GetClaimTypeValues(string type, IEnumerable claims) { List toReturn = new(); diff --git a/src/Services/DevHive.Services/Services/FeedService.cs b/src/Services/DevHive.Services/Services/FeedService.cs index 0af8093..9c622b3 100644 --- a/src/Services/DevHive.Services/Services/FeedService.cs +++ b/src/Services/DevHive.Services/Services/FeedService.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -26,10 +28,11 @@ namespace DevHive.Services.Services /// /// This method is used in the feed page. - /// See the FeedRepository "GetFriendsPosts" menthod for more information on how it works. + /// See the FeedRepository "GetFriendsPosts" method for more information on how it works. /// public async Task GetPage(GetPageServiceModel getPageServiceModel) { + //TODO: Rework the initialization of User User user = null; if (getPageServiceModel.UserId != Guid.Empty) @@ -37,10 +40,10 @@ namespace DevHive.Services.Services else if (!string.IsNullOrEmpty(getPageServiceModel.Username)) user = await this._userRepository.GetByUsernameAsync(getPageServiceModel.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List posts = await this._feedRepository .GetFriendsPosts(user.Friends.ToList(), getPageServiceModel.FirstRequestIssued, getPageServiceModel.PageNumber, getPageServiceModel.PageSize); @@ -58,15 +61,16 @@ namespace DevHive.Services.Services /// public async Task GetUserPage(GetPageServiceModel model) { + //TODO: Rework the initialization of User User user = null; if (!string.IsNullOrEmpty(model.Username)) user = await this._userRepository.GetByUsernameAsync(model.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List posts = await this._feedRepository .GetUsersPosts(user, model.FirstRequestIssued, model.PageNumber, model.PageSize); diff --git a/src/Services/DevHive.Services/Services/LanguageService.cs b/src/Services/DevHive.Services/Services/LanguageService.cs index 9d2041e..7ee7d9f 100644 --- a/src/Services/DevHive.Services/Services/LanguageService.cs +++ b/src/Services/DevHive.Services/Services/LanguageService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task CreateLanguage(CreateLanguageServiceModel createLanguageServiceModel) { if (await this._languageRepository.DoesLanguageNameExistAsync(createLanguageServiceModel.Name)) - throw new ArgumentException("Language already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language language = this._languageMapper.Map(createLanguageServiceModel); bool success = await this._languageRepository.AddAsync(language); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Language language = await this._languageRepository.GetByIdAsync(id); if (language == null) - throw new ArgumentException("The language does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); return this._languageMapper.Map(language); } @@ -65,10 +67,10 @@ namespace DevHive.Services.Services bool newLangNameExists = await this._languageRepository.DoesLanguageNameExistAsync(languageServiceModel.Name); if (!langExists) - throw new ArgumentException("Language does not exist!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); if (newLangNameExists) - throw new ArgumentException("Language name already exists in our data base!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language lang = this._languageMapper.Map(languageServiceModel); return await this._languageRepository.EditAsync(languageServiceModel.Id, lang); @@ -79,7 +81,7 @@ namespace DevHive.Services.Services public async Task DeleteLanguage(Guid id) { if (!await this._languageRepository.DoesLanguageExistAsync(id)) - throw new ArgumentException("Language does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); Language language = await this._languageRepository.GetByIdAsync(id); return await this._languageRepository.DeleteAsync(language); diff --git a/src/Services/DevHive.Services/Services/PostService.cs b/src/Services/DevHive.Services/Services/PostService.cs index a565473..8580e82 100644 --- a/src/Services/DevHive.Services/Services/PostService.cs +++ b/src/Services/DevHive.Services/Services/PostService.cs @@ -1,15 +1,16 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; -using AutoMapper; -using DevHive.Data.Models; -using DevHive.Services.Models.Post; using System.IdentityModel.Tokens.Jwt; +using System.Linq; using System.Security.Claims; -using DevHive.Services.Interfaces; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Data.Models; using DevHive.Data.Models.Relational; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.Post; namespace DevHive.Services.Services { @@ -34,7 +35,7 @@ namespace DevHive.Services.Services public async Task CreatePost(CreatePostServiceModel createPostServiceModel) { if (!await this._userRepository.DoesUserExistAsync(createPostServiceModel.CreatorId)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); Post post = this._postMapper.Map(createPostServiceModel); @@ -66,7 +67,7 @@ namespace DevHive.Services.Services public async Task GetPostById(Guid id) { Post post = await this._postRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); // This can't happen in repo, because of how time is usually compared post.Comments = post.Comments @@ -74,7 +75,7 @@ namespace DevHive.Services.Services .ToList(); User user = await this._userRepository.GetByIdAsync(post.Creator.Id) ?? - throw new ArgumentException("The user does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); int currentRating = 0; foreach (Rating rating in post.Ratings) @@ -100,7 +101,7 @@ namespace DevHive.Services.Services public async Task UpdatePost(UpdatePostServiceModel updatePostServiceModel) { if (!await this._postRepository.DoesPostExist(updatePostServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = this._postMapper.Map(updatePostServiceModel); @@ -111,11 +112,11 @@ namespace DevHive.Services.Services List fileUrlsToRemove = await this._postRepository.GetFileUrls(updatePostServiceModel.PostId); bool success = await _cloudService.RemoveFilesFromCloud(fileUrlsToRemove); if (!success) - throw new InvalidCastException("Could not delete files from the post!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } List fileUrls = await _cloudService.UploadFilesToCloud(updatePostServiceModel.Files) ?? - throw new ArgumentException("Unable to upload images to cloud!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); post.Attachments = GetPostAttachmentsFromUrls(post, fileUrls); } @@ -136,7 +137,7 @@ namespace DevHive.Services.Services public async Task DeletePost(Guid id) { if (!await this._postRepository.DoesPostExist(id)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = await this._postRepository.GetByIdAsync(id); @@ -145,7 +146,7 @@ namespace DevHive.Services.Services List fileUrls = await this._postRepository.GetFileUrls(id); bool success = await _cloudService.RemoveFilesFromCloud(fileUrls); if (!success) - throw new InvalidCastException("Could not delete files from the post. Please try again"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } return await this._postRepository.DeleteAsync(post); @@ -158,7 +159,7 @@ namespace DevHive.Services.Services /// public async Task ValidateJwtForCreating(Guid userId, string rawTokenData) { - User user = await this.GetUserForValidation(rawTokenData); + User user = await GetUserForValidation(rawTokenData); return user.Id == userId; } @@ -171,8 +172,8 @@ namespace DevHive.Services.Services public async Task ValidateJwtForPost(Guid postId, string rawTokenData) { Post post = await this._postRepository.GetByIdAsync(postId) ?? - throw new ArgumentException("Post does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); + User user = await GetUserForValidation(rawTokenData); //If user made the post if (post.Creator.Id == user.Id) @@ -192,8 +193,8 @@ namespace DevHive.Services.Services public async Task ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); + User user = await GetUserForValidation(rawTokenData); //If user made the comment if (comment.Creator.Id == user.Id) @@ -215,7 +216,7 @@ namespace DevHive.Services.Services Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs index 1de2114..cafa7cb 100644 --- a/src/Services/DevHive.Services/Services/ProfilePictureService.cs +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -33,14 +34,13 @@ namespace DevHive.Services.Services await ValidateUserExistsAsync(profilePictureServiceModel.UserId); User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); - // if (user.ProfilePicture.PictureURL != ProfilePicture.DefaultURL) if (user.ProfilePicture.Id != Guid.Empty) { List file = new() { user.ProfilePicture.PictureURL }; bool removed = await this._cloudinaryService.RemoveFilesFromCloud(file); if (!removed) - throw new ArgumentException("Cannot delete old picture"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); } return await SaveProfilePictureInDatabase(profilePictureServiceModel); @@ -49,16 +49,16 @@ namespace DevHive.Services.Services public async Task DeleteProfilePicture(Guid id) { ProfilePicture profilePic = await this._profilePictureRepository.GetByIdAsync(id) ?? - throw new ArgumentException("Such picture doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Picture)); bool removedFromDb = await this._profilePictureRepository.DeleteAsync(profilePic); if (!removedFromDb) - throw new ArgumentException("Cannot delete picture from database!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); List file = new() { profilePic.PictureURL }; bool removedFromCloud = await this._cloudinaryService.RemoveFilesFromCloud(file); if (!removedFromCloud) - throw new ArgumentException("Cannot delete picture from cloud!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); return true; } @@ -75,13 +75,13 @@ namespace DevHive.Services.Services bool success = await this._profilePictureRepository.AddAsync(profilePic); if (!success) - throw new ArgumentException("Unable to upload picture!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); user.ProfilePicture = profilePic; bool userProfilePicAlter = await this._userRepository.EditAsync(user.Id, user); if (!userProfilePicAlter) - throw new ArgumentException("Unable to alter user's profile picture"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, "user's profile picture")); return picUrl; } @@ -89,13 +89,13 @@ namespace DevHive.Services.Services private static void ValidateProfPic(IFormFile profilePictureFormFile) { if (profilePictureFormFile.Length == 0) - throw new ArgumentException("Picture cannot be null"); + throw new ArgumentNullException(nameof(profilePictureFormFile), string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); } private async Task ValidateUserExistsAsync(Guid userId) { if (!await this._userRepository.DoesUserExistAsync(userId)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); } } } diff --git a/src/Services/DevHive.Services/Services/RatingService.cs b/src/Services/DevHive.Services/Services/RatingService.cs index 9d8f4b0..d6b4299 100644 --- a/src/Services/DevHive.Services/Services/RatingService.cs +++ b/src/Services/DevHive.Services/Services/RatingService.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -19,6 +16,8 @@ namespace DevHive.Services.Services private readonly IRatingRepository _ratingRepository; private readonly IMapper _mapper; + private const string NotRated = "{0} has not rated" + ClassesConstants.Post; + public RatingService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper) { this._postRepository = postRepository; @@ -31,7 +30,7 @@ namespace DevHive.Services.Services public async Task RatePost(CreateRatingServiceModel createRatingServiceModel) { if (!await this._postRepository.DoesPostExist(createRatingServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); if (await this._ratingRepository.UserRatedPost(createRatingServiceModel.UserId, createRatingServiceModel.PostId)) throw new ArgumentException("User already rated the post!"); @@ -84,13 +83,13 @@ namespace DevHive.Services.Services public async Task UpdateRating(UpdateRatingServiceModel updateRatingServiceModel) { Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId) ?? - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId)) - throw new ArgumentException("User has not rated the post!"); + throw new ArgumentException(string.Format(NotRated, ClassesConstants.User)); rating.User = user; rating.IsLike = updateRatingServiceModel.IsLike; @@ -111,7 +110,7 @@ namespace DevHive.Services.Services public async Task DeleteRating(Guid ratingId) { if (!await this._ratingRepository.DoesRatingExist(ratingId)) - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); return await this._ratingRepository.DeleteAsync(rating); diff --git a/src/Services/DevHive.Services/Services/RoleService.cs b/src/Services/DevHive.Services/Services/RoleService.cs index a5da759..f61181a 100644 --- a/src/Services/DevHive.Services/Services/RoleService.cs +++ b/src/Services/DevHive.Services/Services/RoleService.cs @@ -1,6 +1,8 @@ using System; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -22,7 +24,7 @@ namespace DevHive.Services.Services public async Task CreateRole(CreateRoleServiceModel createRoleServiceModel) { if (await this._roleRepository.DoesNameExist(createRoleServiceModel.Name)) - throw new ArgumentException("Role already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map(createRoleServiceModel); bool success = await this._roleRepository.AddAsync(role); @@ -40,7 +42,7 @@ namespace DevHive.Services.Services public async Task GetRoleById(Guid id) { Role role = await this._roleRepository.GetByIdAsync(id) ?? - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); return this._roleMapper.Map(role); } @@ -48,10 +50,10 @@ namespace DevHive.Services.Services public async Task UpdateRole(UpdateRoleServiceModel updateRoleServiceModel) { if (!await this._roleRepository.DoesRoleExist(updateRoleServiceModel.Id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); if (await this._roleRepository.DoesNameExist(updateRoleServiceModel.Name)) - throw new ArgumentException("Role name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map(updateRoleServiceModel); return await this._roleRepository.EditAsync(updateRoleServiceModel.Id, role); @@ -60,7 +62,7 @@ namespace DevHive.Services.Services public async Task DeleteRole(Guid id) { if (!await this._roleRepository.DoesRoleExist(id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); Role role = await this._roleRepository.GetByIdAsync(id); return await this._roleRepository.DeleteAsync(role); diff --git a/src/Services/DevHive.Services/Services/TechnologyService.cs b/src/Services/DevHive.Services/Services/TechnologyService.cs index 09c4d20..4cf84c5 100644 --- a/src/Services/DevHive.Services/Services/TechnologyService.cs +++ b/src/Services/DevHive.Services/Services/TechnologyService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task CreateTechnology(CreateTechnologyServiceModel technologyServiceModel) { if (await this._technologyRepository.DoesTechnologyNameExistAsync(technologyServiceModel.Name)) - throw new ArgumentException("Technology already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map(technologyServiceModel); bool success = await this._technologyRepository.AddAsync(technology); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Technology technology = await this._technologyRepository.GetByIdAsync(id); if (technology == null) - throw new ArgumentException("The technology does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); return this._technologyMapper.Map(technology); } @@ -62,10 +64,10 @@ namespace DevHive.Services.Services public async Task UpdateTechnology(UpdateTechnologyServiceModel updateTechnologyServiceModel) { if (!await this._technologyRepository.DoesTechnologyExistAsync(updateTechnologyServiceModel.Id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); if (await this._technologyRepository.DoesTechnologyNameExistAsync(updateTechnologyServiceModel.Name)) - throw new ArgumentException("Technology name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map(updateTechnologyServiceModel); bool result = await this._technologyRepository.EditAsync(updateTechnologyServiceModel.Id, technology); @@ -78,7 +80,7 @@ namespace DevHive.Services.Services public async Task DeleteTechnology(Guid id) { if (!await this._technologyRepository.DoesTechnologyExistAsync(id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); Technology technology = await this._technologyRepository.GetByIdAsync(id); bool result = await this._technologyRepository.DeleteAsync(technology); diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs index d487de4..62576d4 100644 --- a/src/Services/DevHive.Services/Services/UserService.cs +++ b/src/Services/DevHive.Services/Services/UserService.cs @@ -1,15 +1,17 @@ -using AutoMapper; -using DevHive.Services.Models.User; -using System.Threading.Tasks; -using DevHive.Data.Models; using System; using System.Collections.Generic; -using DevHive.Common.Models.Identity; -using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; +using System.Data; +using System.IO; using System.Linq; -using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Common.Jwt.Interfaces; +using DevHive.Common.Models.Identity; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.User; namespace DevHive.Services.Services { @@ -20,15 +22,17 @@ namespace DevHive.Services.Services private readonly ILanguageRepository _languageRepository; private readonly ITechnologyRepository _technologyRepository; private readonly IMapper _userMapper; - private readonly ICloudService _cloudService; private readonly IJwtService _jwtService; + private const string NoYourselfAsFriend = "You cant add yourself as a friend(sry, bro)!"; + private const string Rant = "Can't promote shit in this country..."; + + public UserService(IUserRepository userRepository, ILanguageRepository languageRepository, IRoleRepository roleRepository, ITechnologyRepository technologyRepository, IMapper mapper, - ICloudService cloudService, IJwtService jwtService) { this._userRepository = userRepository; @@ -36,7 +40,6 @@ namespace DevHive.Services.Services this._userMapper = mapper; this._languageRepository = languageRepository; this._technologyRepository = technologyRepository; - this._cloudService = cloudService; this._jwtService = jwtService; } @@ -44,12 +47,12 @@ namespace DevHive.Services.Services public async Task LoginUser(LoginServiceModel loginModel) { if (!await this._userRepository.DoesUsernameExistAsync(loginModel.UserName)) - throw new ArgumentException("Invalid username!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Username)); User user = await this._userRepository.GetByUsernameAsync(loginModel.UserName); if (!await this._userRepository.VerifyPassword(user, loginModel.Password)) - throw new ArgumentException("Incorrect password!"); + throw new InvalidDataException(string.Format(ErrorMessages.IncorrectData, ClassesConstants.Password.ToLower())); List roleNames = user.Roles.Select(x => x.Name).ToList(); return new TokenModel(this._jwtService.GenerateJwtToken(user.Id, user.UserName, roleNames)); @@ -58,10 +61,11 @@ namespace DevHive.Services.Services public async Task RegisterUser(RegisterServiceModel registerModel) { if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username)); if (await this._userRepository.DoesEmailExistAsync(registerModel.Email)) - throw new ArgumentException("Email already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Email)); + User user = this._userMapper.Map(registerModel); @@ -69,9 +73,9 @@ namespace DevHive.Services.Services bool roleResult = await this._userRepository.AddRoleToUser(user, Role.DefaultRole); if (!userResult) - throw new ArgumentException("Unable to create a user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotCreate, ClassesConstants.User.ToLower())); if (!roleResult) - throw new ArgumentException("Unable to add role to user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotAdd, ClassesConstants.Role.ToLower())); User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName); @@ -84,7 +88,7 @@ namespace DevHive.Services.Services public async Task GetUserById(Guid id) { User user = await this._userRepository.GetByIdAsync(id) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map(user); } @@ -92,7 +96,7 @@ namespace DevHive.Services.Services public async Task GetUserByUsername(string username) { User user = await this._userRepository.GetByUsernameAsync(username) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map(user); } @@ -101,20 +105,20 @@ namespace DevHive.Services.Services #region Update public async Task UpdateUser(UpdateUserServiceModel updateUserServiceModel) { - await this.ValidateUserOnUpdate(updateUserServiceModel); + await ValidateUserOnUpdate(updateUserServiceModel); User user = await this._userRepository.GetByIdAsync(updateUserServiceModel.Id); - await this.PopulateUserModel(user, updateUserServiceModel); + await PopulateUserModel(user, updateUserServiceModel); if (updateUserServiceModel.Friends.Count > 0) - await this.CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); + await CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); else user.Friends.Clear(); bool result = await this._userRepository.EditAsync(user.Id, user); if (!result) - throw new InvalidOperationException("Unable to edit user!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower())); User newUser = await this._userRepository.GetByIdAsync(user.Id); return this._userMapper.Map(newUser); @@ -125,7 +129,7 @@ namespace DevHive.Services.Services public async Task DeleteUser(Guid id) { if (!await this._userRepository.DoesUserExistAsync(id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); User user = await this._userRepository.GetByIdAsync(id); return await this._userRepository.DeleteAsync(user); @@ -140,21 +144,21 @@ namespace DevHive.Services.Services private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel) { if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (updateUserServiceModel.Friends.Any(x => x.UserName == updateUserServiceModel.UserName)) - throw new ArgumentException("You cant add yourself as a friend(sry, bro)!"); + throw new InvalidOperationException(NoYourselfAsFriend); if (!await this._userRepository.DoesUserHaveThisUsernameAsync(updateUserServiceModel.Id, updateUserServiceModel.UserName) && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username.ToLower())); List usernames = new(); foreach (var friend in updateUserServiceModel.Friends) usernames.Add(friend.UserName); if (!await this._userRepository.ValidateFriendsCollectionAsync(usernames)) - throw new ArgumentException("One or more friends do not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.OneOrMoreFriends)); } #endregion @@ -162,7 +166,7 @@ namespace DevHive.Services.Services public async Task SuperSecretPromotionToAdmin(Guid userId) { User user = await this._userRepository.GetByIdAsync(userId) ?? - throw new ArgumentException("User does not exist! Can't promote shit in this country..."); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User) + " " + Rant); if (!await this._roleRepository.DoesNameExist(Role.AdminRole)) { @@ -202,7 +206,7 @@ namespace DevHive.Services.Services foreach (var role in updateUserServiceModel.Roles) { Role returnedRole = await this._roleRepository.GetByNameAsync(role.Name) ?? - throw new ArgumentException($"Role {role.Name} does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); roles.Add(returnedRole); } @@ -214,7 +218,7 @@ namespace DevHive.Services.Services for (int i = 0; i < languagesCount; i++) { Language language = await this._languageRepository.GetByNameAsync(updateUserServiceModel.Languages.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid language name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Language))); languages.Add(language); } @@ -226,7 +230,8 @@ namespace DevHive.Services.Services for (int i = 0; i < technologiesCount; i++) { Technology technology = await this._technologyRepository.GetByNameAsync(updateUserServiceModel.Technologies.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid technology name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Technology))); + technologies.Add(technology); } -- cgit v1.2.3