aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyndamia <kamen.d.mladenov@protonmail.com>2021-03-13 15:07:51 +0200
committerSyndamia <kamen.d.mladenov@protonmail.com>2021-03-13 15:07:51 +0200
commit75d57f305f2ed1ecf8b82bd62d4bb8f17c06303b (patch)
treeb721fe307d22a7a89f8ee13b3e557df4a2e2bbab
parent503a23c04355624b133161c9356b139f2e4500f6 (diff)
parent4add0831649f6e534d3883aa0e0e7f380d8042c7 (diff)
downloadDevHive-75d57f305f2ed1ecf8b82bd62d4bb8f17c06303b.tar
DevHive-75d57f305f2ed1ecf8b82bd62d4bb8f17c06303b.tar.gz
DevHive-75d57f305f2ed1ecf8b82bd62d4bb8f17c06303b.zip
Merge branch 'dev' of github.com:Team-Kaleidoscope/DevHive into unit_test_refactoring
-rw-r--r--src/.editorconfig9
-rw-r--r--src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj (renamed from src/Common/DevHive.Common.Models/DevHive.Common.csproj)2
-rw-r--r--src/Common/DevHive.Common/DevHive.Common.csproj11
-rw-r--r--src/Common/DevHive.Common/Jwt/Interfaces/IJwtService.cs28
-rw-r--r--src/Common/DevHive.Common/Jwt/JwtService.cs86
-rw-r--r--src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj2
-rw-r--r--src/Data/DevHive.Data.Models/Interfaces/IRating.cs7
-rw-r--r--src/Data/DevHive.Data.Models/Post.cs2
-rw-r--r--src/Data/DevHive.Data.Models/Rating.cs5
-rw-r--r--src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj6
-rw-r--r--src/Data/DevHive.Data/DevHive.Data.csproj2
-rw-r--r--src/Data/DevHive.Data/DevHiveContext.cs5
-rw-r--r--src/Data/DevHive.Data/Interfaces/IRatingRepository.cs6
-rw-r--r--src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs678
-rw-r--r--src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs139
-rw-r--r--src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs31
-rw-r--r--src/Data/DevHive.Data/Repositories/PostRepository.cs2
-rw-r--r--src/Data/DevHive.Data/Repositories/RatingRepository.cs28
-rw-r--r--src/DevHive.code-workspace10
-rw-r--r--src/DevHive.sln49
-rw-r--r--src/Dockerfile21
-rw-r--r--src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj5
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs (renamed from src/Services/DevHive.Services.Models/Post/Rating/RatePostServiceModel.cs)4
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs (renamed from src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs)6
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs3
-rw-r--r--src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj8
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs8
-rw-r--r--src/Services/DevHive.Services/DevHive.Services.csproj4
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRateService.cs14
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRatingService.cs22
-rw-r--r--src/Services/DevHive.Services/Interfaces/IUserService.cs49
-rw-r--r--src/Services/DevHive.Services/Options/JwtOptions.cs14
-rw-r--r--src/Services/DevHive.Services/Services/RateService.cs80
-rw-r--r--src/Services/DevHive.Services/Services/RatingService.cs125
-rw-r--r--src/Services/DevHive.Services/Services/UserService.cs125
-rw-r--r--src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj5
-rw-r--r--src/Web/DevHive.Web.Models/Post/ReadPostWebModel.cs2
-rw-r--r--src/Web/DevHive.Web.Models/Rating/CreateRatingWebModel.cs (renamed from src/Web/DevHive.Web.Models/Rating/RatePostWebModel.cs)4
-rw-r--r--src/Web/DevHive.Web.Models/Rating/ReadRatingWebModel.cs (renamed from src/Web/DevHive.Web.Models/Rating/ReadPostRatingWebModel.cs)6
-rw-r--r--src/Web/DevHive.Web.Models/Rating/UpdateRatingWebModel.cs17
-rw-r--r--src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj8
-rw-r--r--src/Web/DevHive.Web/Configurations/Extensions/ConfigureAutoMapper.cs3
-rw-r--r--src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs13
-rw-r--r--src/Web/DevHive.Web/Configurations/Extensions/ConfigureJwt.cs14
-rw-r--r--src/Web/DevHive.Web/Configurations/Extensions/ConfigureSwagger.cs54
-rw-r--r--src/Web/DevHive.Web/Configurations/Mapping/RatingMappings.cs6
-rw-r--r--src/Web/DevHive.Web/Controllers/CommentController.cs49
-rw-r--r--src/Web/DevHive.Web/Controllers/FeedController.cs15
-rw-r--r--src/Web/DevHive.Web/Controllers/LanguageController.cs32
-rw-r--r--src/Web/DevHive.Web/Controllers/PostController.cs44
-rw-r--r--src/Web/DevHive.Web/Controllers/ProfilePictureController.cs48
-rw-r--r--src/Web/DevHive.Web/Controllers/RateController.cs40
-rw-r--r--src/Web/DevHive.Web/Controllers/RatingController.cs99
-rw-r--r--src/Web/DevHive.Web/Controllers/RoleController.cs24
-rw-r--r--src/Web/DevHive.Web/Controllers/TechnologyController.cs28
-rw-r--r--src/Web/DevHive.Web/Controllers/UserController.cs79
-rw-r--r--src/Web/DevHive.Web/DevHive.Web.csproj14
-rw-r--r--src/Web/DevHive.Web/Startup.cs4
-rw-r--r--src/Web/DevHive.Web/appsettings.json26
60 files changed, 1824 insertions, 421 deletions
diff --git a/src/.editorconfig b/src/.editorconfig
index 757e49d..9f0e74b 100644
--- a/src/.editorconfig
+++ b/src/.editorconfig
@@ -44,11 +44,12 @@ dotnet_diagnostic.IDE0055.severity = warning
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = false
+
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = true:refactoring
dotnet_style_qualification_for_property = true:refactoring
-dotnet_style_qualification_for_method = true:refactoring
-dotnet_style_qualification_for_event = true:refactoring
+dotnet_style_qualification_for_method = false:refactoring
+dotnet_style_qualification_for_event = false:refactoring
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
@@ -143,6 +144,7 @@ dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}'
dotnet_diagnostic.RS2008.severity = none
+dotnet_diagnostic.CS1591.severity = none
# IDE0073: File header
dotnet_diagnostic.IDE0073.severity = warning
@@ -228,3 +230,6 @@ csharp_space_between_square_brackets = false
# Wrapping preferences
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
+
+[/Data/DevHive.Data/Migrations/**]
+dotnet_diagnostic.IDE0055.severity = none
diff --git a/src/Common/DevHive.Common.Models/DevHive.Common.csproj b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj
index f6d662c..a952c59 100644
--- a/src/Common/DevHive.Common.Models/DevHive.Common.csproj
+++ b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj
@@ -4,7 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
diff --git a/src/Common/DevHive.Common/DevHive.Common.csproj b/src/Common/DevHive.Common/DevHive.Common.csproj
new file mode 100644
index 0000000..cd60d85
--- /dev/null
+++ b/src/Common/DevHive.Common/DevHive.Common.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <ItemGroup>
+ <ProjectReference Include="..\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
+ </ItemGroup>
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0"/>
+ </ItemGroup>
+</Project>
diff --git a/src/Common/DevHive.Common/Jwt/Interfaces/IJwtService.cs b/src/Common/DevHive.Common/Jwt/Interfaces/IJwtService.cs
new file mode 100644
index 0000000..352a7d5
--- /dev/null
+++ b/src/Common/DevHive.Common/Jwt/Interfaces/IJwtService.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+namespace DevHive.Common.Jwt.Interfaces
+{
+ public interface IJwtService
+ {
+ /// <summary>
+ /// The generation of a JWT, when a new user registers or log ins
+ /// Tokens have an expiration time of 7 days.
+ /// </summary>
+ /// <param name="userId">User's Guid</param>
+ /// <param name="username">Users's username</param>
+ /// <param name="roleNames">List of user's roles</param>
+ /// <returns>Return a new JWT, containing the user id, username and roles.</returns>
+ string GenerateJwtToken(Guid userId, string username, List<string> roleNames);
+
+ /// <summary>
+ /// Checks whether the given user, gotten by the "id" property,
+ /// is the same user as the one in the token (unless the user in the token has the admin role)
+ /// and the roles in the token are the same as those in the user, gotten by the id in the token
+ /// </summary>
+ /// <param name="userId">Guid of the user being validated</param>
+ /// <param name="rawToken">The raw token coming from the request</param>
+ /// <returns>Bool result of is the user authenticated to do an action</returns>
+ bool ValidateToken(Guid userId, string rawToken);
+ }
+}
diff --git a/src/Common/DevHive.Common/Jwt/JwtService.cs b/src/Common/DevHive.Common/Jwt/JwtService.cs
new file mode 100644
index 0000000..9f316da
--- /dev/null
+++ b/src/Common/DevHive.Common/Jwt/JwtService.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Claims;
+using System.Security.Principal;
+using DevHive.Common.Jwt.Interfaces;
+using Microsoft.IdentityModel.Tokens;
+
+namespace DevHive.Common.Jwt
+{
+ public class JwtService : IJwtService
+ {
+ private readonly string _validationIssuer;
+ private readonly string _audience;
+ private readonly byte[] _signingKey;
+
+ public JwtService(byte[] signingKey, string validationIssuer, string audience)
+ {
+ this._signingKey = signingKey;
+ this._validationIssuer = validationIssuer;
+ this._audience = audience;
+ }
+
+ public string GenerateJwtToken(Guid userId, string username, List<string> roleNames)
+ {
+ var securityKey = new SymmetricSecurityKey(this._signingKey);
+ var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
+
+ HashSet<Claim> claims = new()
+ {
+ new Claim("ID", $"{userId}"),
+ new Claim("Username", username)
+ };
+
+ foreach (var roleName in roleNames)
+ claims.Add(new Claim(ClaimTypes.Role, roleName));
+
+ SecurityTokenDescriptor securityTokenDescriptor = new()
+ {
+ Issuer = this._validationIssuer,
+ Audience = this._audience,
+ Subject = new ClaimsIdentity(claims),
+ Expires = DateTime.Today.AddDays(7),
+ SigningCredentials = credentials,
+ };
+
+ JwtSecurityTokenHandler tokenHandler = new();
+ SecurityToken token = tokenHandler.CreateToken(securityTokenDescriptor);
+
+ return tokenHandler.WriteToken(token);
+ }
+
+ public bool ValidateToken(Guid userId, string rawToken)
+ {
+ var tokenHandler = new JwtSecurityTokenHandler();
+ var validationParameters = GetValidationParameters();
+ string actualToken = rawToken.Remove(0, 7);
+
+ IPrincipal principal = tokenHandler.ValidateToken(actualToken, validationParameters, out SecurityToken validatedToken);
+ JwtSecurityToken jwtToken = tokenHandler.ReadJwtToken(actualToken);
+
+ if (!principal.Identity.IsAuthenticated)
+ return false;
+ else if (principal.IsInRole("Admin"))
+ return true;
+ else if (jwtToken.Claims.FirstOrDefault(x => x.Type == "ID").Value != userId.ToString())
+ return false;
+ else
+ return true;
+ }
+
+ private TokenValidationParameters GetValidationParameters()
+ {
+ return new TokenValidationParameters()
+ {
+ ValidateLifetime = true,
+ ValidateAudience = true,
+ ValidateIssuer = true,
+ ValidIssuer = this._validationIssuer,
+ ValidAudience = this._audience,
+ IssuerSigningKey = new SymmetricSecurityKey(this._signingKey)
+ };
+ }
+ }
+}
diff --git a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj
index e9dc644..d249c77 100644
--- a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj
+++ b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj
@@ -5,6 +5,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/Data/DevHive.Data.Models/Interfaces/IRating.cs b/src/Data/DevHive.Data.Models/Interfaces/IRating.cs
index 1b081b0..f04f823 100644
--- a/src/Data/DevHive.Data.Models/Interfaces/IRating.cs
+++ b/src/Data/DevHive.Data.Models/Interfaces/IRating.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using DevHive.Data.Models;
@@ -5,10 +6,10 @@ namespace DevHive.Data.Models.Interfaces
{
public interface IRating : IModel
{
- // Post Post { get; set; }
+ bool IsLike { get; set; }
- int Rate { get; set; }
+ Post Post { get; set; }
- // HashSet<User> UsersThatRated { get; set; }
+ User User { get; set; }
}
}
diff --git a/src/Data/DevHive.Data.Models/Post.cs b/src/Data/DevHive.Data.Models/Post.cs
index 15b6b77..c95a8f1 100644
--- a/src/Data/DevHive.Data.Models/Post.cs
+++ b/src/Data/DevHive.Data.Models/Post.cs
@@ -19,7 +19,7 @@ namespace DevHive.Data.Models
public List<Comment> Comments { get; set; } = new();
- public Rating Rating { get; set; } = new();
+ public List<Rating> Ratings { get; set; }
public List<PostAttachments> Attachments { get; set; } = new();
}
diff --git a/src/Data/DevHive.Data.Models/Rating.cs b/src/Data/DevHive.Data.Models/Rating.cs
index 13fdbce..8743a3e 100644
--- a/src/Data/DevHive.Data.Models/Rating.cs
+++ b/src/Data/DevHive.Data.Models/Rating.cs
@@ -6,12 +6,13 @@ namespace DevHive.Data.Models
{
public class Rating : IRating
{
+ //if adding rating to comments change Post for intreface IRatable!
public Guid Id { get; set; }
- public Guid PostId { get; set; }
+ public User User { get; set; }
public Post Post { get; set; }
- public int Rate { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj
index 2af369f..25b2b39 100644
--- a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj
+++ b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj
@@ -5,11 +5,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.3"/>
- <PackageReference Include="Moq" Version="4.16.0"/>
+ <PackageReference Include="Moq" Version="4.16.1"/>
<PackageReference Include="NUnit" Version="3.13.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DevHive.Data\DevHive.Data.csproj"/>
diff --git a/src/Data/DevHive.Data/DevHive.Data.csproj b/src/Data/DevHive.Data/DevHive.Data.csproj
index 46928c6..fcdb7ae 100644
--- a/src/Data/DevHive.Data/DevHive.Data.csproj
+++ b/src/Data/DevHive.Data/DevHive.Data.csproj
@@ -12,7 +12,7 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0"/>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DevHive.Data.Models\DevHive.Data.Models.csproj"/>
diff --git a/src/Data/DevHive.Data/DevHiveContext.cs b/src/Data/DevHive.Data/DevHiveContext.cs
index ece3439..b0bbdc6 100644
--- a/src/Data/DevHive.Data/DevHiveContext.cs
+++ b/src/Data/DevHive.Data/DevHiveContext.cs
@@ -88,11 +88,10 @@ namespace DevHive.Data
builder.Entity<Rating>()
.HasOne(x => x.Post)
- .WithOne(x => x.Rating)
- .HasForeignKey<Rating>(x => x.PostId);
+ .WithMany(x => x.Ratings);
builder.Entity<Post>()
- .HasOne(x => x.Rating)
+ .HasMany(x => x.Ratings)
.WithOne(x => x.Post);
/* User Rated Posts */
diff --git a/src/Data/DevHive.Data/Interfaces/IRatingRepository.cs b/src/Data/DevHive.Data/Interfaces/IRatingRepository.cs
index b5aff88..db37d00 100644
--- a/src/Data/DevHive.Data/Interfaces/IRatingRepository.cs
+++ b/src/Data/DevHive.Data/Interfaces/IRatingRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using DevHive.Data.Models;
using DevHive.Data.Repositories.Interfaces;
@@ -7,7 +8,10 @@ namespace DevHive.Data.Interfaces
{
public interface IRatingRepository : IRepository<Rating>
{
- Task<Rating> GetRatingByPostId(Guid postId);
+ Task<List<Rating>> GetRatingsByPostId(Guid postId);
Task<bool> UserRatedPost(Guid userId, Guid postId);
+ Task<Rating> GetRatingByUserAndPostId(Guid userId, Guid postId);
+
+ Task<bool> DoesRatingExist(Guid id);
}
}
diff --git a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs
new file mode 100644
index 0000000..c0b67a6
--- /dev/null
+++ b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs
@@ -0,0 +1,678 @@
+// <auto-generated />
+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("20210225193352_rating_migration")]
+ partial class rating_migration
+ {
+ 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<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Language", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Languages");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("CreatorId")
+ .HasColumnType("uuid");
+
+ b.Property<int>("CurrentRating")
+ .HasColumnType("integer");
+
+ b.Property<string>("Message")
+ .HasColumnType("text");
+
+ b.Property<DateTime>("TimeCreated")
+ .HasColumnType("timestamp without time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CreatorId");
+
+ b.ToTable("Posts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("PictureURL")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId")
+ .IsUnique();
+
+ b.ToTable("ProfilePicture");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<bool>("IsLike")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("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<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("FileUrl")
+ .HasColumnType("text");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("PostAttachments");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("PostId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "PostId");
+
+ b.HasIndex("PostId");
+
+ b.ToTable("RatedPosts");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<bool>("Liked")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("PostId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PostId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("UserRates");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Role", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Technology", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Technologies");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.User", b =>
+ {
+ b.Property<Guid>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("uuid");
+
+ b.Property<int>("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property<string>("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property<string>("Email")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<bool>("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("FirstName")
+ .HasColumnType("text");
+
+ b.Property<string>("LastName")
+ .HasColumnType("text");
+
+ b.Property<bool>("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<DateTimeOffset?>("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property<string>("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property<string>("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property<string>("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property<bool>("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property<string>("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property<bool>("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("UserName")
+ .IsUnique();
+
+ b.ToTable("AspNetUsers");
+ });
+
+ modelBuilder.Entity("LanguageUser", b =>
+ {
+ b.Property<Guid>("LanguagesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LanguagesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("LanguageUser");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.Property<int>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer")
+ .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+ b.Property<string>("ClaimType")
+ .HasColumnType("text");
+
+ b.Property<string>("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property<string>("ProviderDisplayName")
+ .HasColumnType("text");
+
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("RoleId")
+ .HasColumnType("uuid");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.Property<Guid>("UserId")
+ .HasColumnType("uuid");
+
+ b.Property<string>("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property<string>("Name")
+ .HasColumnType("text");
+
+ b.Property<string>("Value")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens");
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.Property<Guid>("RolesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("RolesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("RoleUser");
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.Property<Guid>("TechnologiesId")
+ .HasColumnType("uuid");
+
+ b.Property<Guid>("UsersId")
+ .HasColumnType("uuid");
+
+ b.HasKey("TechnologiesId", "UsersId");
+
+ b.HasIndex("UsersId");
+
+ b.ToTable("TechnologyUser");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Comment", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Comments")
+ .HasForeignKey("CreatorId");
+
+ b.HasOne("DevHive.Data.Models.Post", "Post")
+ .WithMany("Comments")
+ .HasForeignKey("PostId");
+
+ b.Navigation("Creator");
+
+ b.Navigation("Post");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "Creator")
+ .WithMany("Posts")
+ .HasForeignKey("CreatorId");
+
+ b.Navigation("Creator");
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", "User")
+ .WithOne("ProfilePicture")
+ .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("DevHive.Data.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.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<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b =>
+ {
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("RoleUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Role", null)
+ .WithMany()
+ .HasForeignKey("RolesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("TechnologyUser", b =>
+ {
+ b.HasOne("DevHive.Data.Models.Technology", null)
+ .WithMany()
+ .HasForeignKey("TechnologiesId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("DevHive.Data.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("DevHive.Data.Models.Post", b =>
+ {
+ b.Navigation("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");
+
+ b.Navigation("RatedPosts");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs
new file mode 100644
index 0000000..da81cdc
--- /dev/null
+++ b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs
@@ -0,0 +1,139 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace DevHive.Data.Migrations
+{
+ public partial class rating_migration : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_Rating_Posts_PostId",
+ table: "Rating");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Rating_PostId",
+ table: "Rating");
+
+ migrationBuilder.DropColumn(
+ name: "Rate",
+ table: "Rating");
+
+ migrationBuilder.AlterColumn<Guid>(
+ name: "PostId",
+ table: "Rating",
+ type: "uuid",
+ nullable: true,
+ oldClrType: typeof(Guid),
+ oldType: "uuid");
+
+ migrationBuilder.AddColumn<bool>(
+ name: "IsLike",
+ table: "Rating",
+ type: "boolean",
+ nullable: false,
+ defaultValue: false);
+
+ migrationBuilder.AddColumn<Guid>(
+ name: "UserId",
+ table: "Rating",
+ type: "uuid",
+ nullable: true);
+
+ migrationBuilder.AddColumn<int>(
+ name: "CurrentRating",
+ table: "Posts",
+ type: "integer",
+ nullable: false,
+ defaultValue: 0);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Rating_PostId",
+ table: "Rating",
+ column: "PostId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Rating_UserId",
+ table: "Rating",
+ column: "UserId");
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Rating_AspNetUsers_UserId",
+ table: "Rating",
+ column: "UserId",
+ principalTable: "AspNetUsers",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Rating_Posts_PostId",
+ table: "Rating",
+ column: "PostId",
+ principalTable: "Posts",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Restrict);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropForeignKey(
+ name: "FK_Rating_AspNetUsers_UserId",
+ table: "Rating");
+
+ migrationBuilder.DropForeignKey(
+ name: "FK_Rating_Posts_PostId",
+ table: "Rating");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Rating_PostId",
+ table: "Rating");
+
+ migrationBuilder.DropIndex(
+ name: "IX_Rating_UserId",
+ table: "Rating");
+
+ migrationBuilder.DropColumn(
+ name: "IsLike",
+ table: "Rating");
+
+ migrationBuilder.DropColumn(
+ name: "UserId",
+ table: "Rating");
+
+ migrationBuilder.DropColumn(
+ name: "CurrentRating",
+ table: "Posts");
+
+ migrationBuilder.AlterColumn<Guid>(
+ name: "PostId",
+ table: "Rating",
+ type: "uuid",
+ nullable: false,
+ defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
+ oldClrType: typeof(Guid),
+ oldType: "uuid",
+ oldNullable: true);
+
+ migrationBuilder.AddColumn<int>(
+ name: "Rate",
+ table: "Rating",
+ type: "integer",
+ nullable: false,
+ defaultValue: 0);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_Rating_PostId",
+ table: "Rating",
+ column: "PostId",
+ unique: true);
+
+ migrationBuilder.AddForeignKey(
+ name: "FK_Rating_Posts_PostId",
+ table: "Rating",
+ column: "PostId",
+ principalTable: "Posts",
+ principalColumn: "Id",
+ onDelete: ReferentialAction.Cascade);
+ }
+ }
+}
diff --git a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
index 8db3abf..a722cb2 100644
--- a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
+++ b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs
@@ -69,6 +69,9 @@ namespace DevHive.Data.Migrations
b.Property<Guid?>("CreatorId")
.HasColumnType("uuid");
+ b.Property<int>("CurrentRating")
+ .HasColumnType("integer");
+
b.Property<string>("Message")
.HasColumnType("text");
@@ -108,16 +111,20 @@ namespace DevHive.Data.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
- b.Property<Guid>("PostId")
+ b.Property<bool>("IsLike")
+ .HasColumnType("boolean");
+
+ b.Property<Guid?>("PostId")
.HasColumnType("uuid");
- b.Property<int>("Rate")
- .HasColumnType("integer");
+ b.Property<Guid?>("UserId")
+ .HasColumnType("uuid");
b.HasKey("Id");
- b.HasIndex("PostId")
- .IsUnique();
+ b.HasIndex("PostId");
+
+ b.HasIndex("UserId");
b.ToTable("Rating");
});
@@ -484,12 +491,16 @@ namespace DevHive.Data.Migrations
modelBuilder.Entity("DevHive.Data.Models.Rating", b =>
{
b.HasOne("DevHive.Data.Models.Post", "Post")
- .WithOne("Rating")
- .HasForeignKey("DevHive.Data.Models.Rating", "PostId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
+ .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 =>
@@ -644,7 +655,7 @@ namespace DevHive.Data.Migrations
b.Navigation("Comments");
- b.Navigation("Rating");
+ b.Navigation("Ratings");
});
modelBuilder.Entity("DevHive.Data.Models.User", b =>
diff --git a/src/Data/DevHive.Data/Repositories/PostRepository.cs b/src/Data/DevHive.Data/Repositories/PostRepository.cs
index b6c5e37..0a88cf2 100644
--- a/src/Data/DevHive.Data/Repositories/PostRepository.cs
+++ b/src/Data/DevHive.Data/Repositories/PostRepository.cs
@@ -36,7 +36,7 @@ namespace DevHive.Data.Repositories
.Include(x => x.Comments)
.Include(x => x.Creator)
.Include(x => x.Attachments)
- // .Include(x => x.Rating)
+ .Include(x => x.Ratings)
.FirstOrDefaultAsync(x => x.Id == id);
}
diff --git a/src/Data/DevHive.Data/Repositories/RatingRepository.cs b/src/Data/DevHive.Data/Repositories/RatingRepository.cs
index b361693..9bb2368 100644
--- a/src/Data/DevHive.Data/Repositories/RatingRepository.cs
+++ b/src/Data/DevHive.Data/Repositories/RatingRepository.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DevHive.Data.Interfaces;
@@ -19,17 +20,36 @@ namespace DevHive.Data.Repositories
this._postRepository = postRepository;
}
- public async Task<Rating> GetRatingByPostId(Guid postId)
+ public override async Task<Rating> GetByIdAsync(Guid id)
{
return await this._context.Rating
- .FirstOrDefaultAsync(x => x.Post.Id == postId);
+ .Include(x => x.User)
+ .Include(x => x.Post)
+ .FirstOrDefaultAsync(x => x.Id == id);
+ }
+ public async Task<List<Rating>> GetRatingsByPostId(Guid postId)
+ {
+ return await this._context.Rating
+ .Where(x => x.Post.Id == postId).ToListAsync();
}
-
public async Task<bool> UserRatedPost(Guid userId, Guid postId)
{
- return await this._context.UserRate
+ return await this._context.Rating
.Where(x => x.Post.Id == postId)
.AnyAsync(x => x.User.Id == userId);
}
+ public async Task<Rating> GetRatingByUserAndPostId(Guid userId, Guid postId)
+ {
+ return await this._context.Rating
+ .FirstOrDefaultAsync(x => x.Post.Id == postId && x.User.Id == userId);
+ }
+
+ public async Task<bool> DoesRatingExist(Guid id)
+ {
+ return await this._context.Rating
+ .AsNoTracking()
+ .AnyAsync(r => r.Id == id);
+ }
}
}
+
diff --git a/src/DevHive.code-workspace b/src/DevHive.code-workspace
index 8511609..72c2301 100644
--- a/src/DevHive.code-workspace
+++ b/src/DevHive.code-workspace
@@ -15,7 +15,7 @@
{
"name": "Common",
"path": "./Common"
- },
+ }
],
"settings": {
"files.exclude": {
@@ -23,14 +23,14 @@
"**/bin": true,
"**/obj": true,
- ".gitignore" : true,
+ ".gitignore": true
},
"code-runner.fileDirectoryAsCwd": true,
"dotnet-test-explorer.runInParallel": true,
"dotnet-test-explorer.testProjectPath": "**/*.Tests.csproj",
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableRoslynAnalyzers": true,
- "prettier.useEditorConfig": true,
+ "prettier.useEditorConfig": true
},
"launch": {
"configurations": [
@@ -45,8 +45,8 @@
"stopAtEntry": false,
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
- },
- },
+ }
+ }
// {
// "name": "Launch Data Tests",
// "type": "coreclr",
diff --git a/src/DevHive.sln b/src/DevHive.sln
index 05bdcda..a202180 100644
--- a/src/DevHive.sln
+++ b/src/DevHive.sln
@@ -11,10 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Data.Models", "Data
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Data.Tests", "Data\DevHive.Data.Tests\DevHive.Data.Tests.csproj", "{F056B3F1-B72D-4935-87EA-F7BFEA96AFB0}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{F2864A9D-70F1-452F-AAAC-AAFD8102ABAD}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Common", "Common\DevHive.Common.Models\DevHive.Common.csproj", "{5C3DFE9B-9690-475E-A0AE-D62315D38337}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{7CA79114-C359-4871-BFA7-0EA898B50AE4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Services", "Services\DevHive.Services\DevHive.Services.csproj", "{B5F22590-E3CE-4595-BE48-AA7F1797A6B8}"
@@ -31,6 +27,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Web.Models", "Web\D
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Web.Tests", "Web\DevHive.Web.Tests\DevHive.Web.Tests.csproj", "{608273FF-01ED-48B3-B912-66CCDBF5572E}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{49B4EAF5-8F45-493F-A25A-7F37DAAE6B1E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Common", "Common\DevHive.Common\DevHive.Common.csproj", "{AAEC0516-A943-449E-A1E8-E0628BFFAA2E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevHive.Common.Models", "Common\DevHive.Common.Models\DevHive.Common.Models.csproj", "{3D63C965-A734-45D6-B75D-AFDCAB511293}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -80,18 +82,6 @@ Global
{F056B3F1-B72D-4935-87EA-F7BFEA96AFB0}.Release|x64.Build.0 = Release|Any CPU
{F056B3F1-B72D-4935-87EA-F7BFEA96AFB0}.Release|x86.ActiveCfg = Release|Any CPU
{F056B3F1-B72D-4935-87EA-F7BFEA96AFB0}.Release|x86.Build.0 = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|x64.Build.0 = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Debug|x86.Build.0 = Debug|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|Any CPU.Build.0 = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|x64.ActiveCfg = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|x64.Build.0 = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|x86.ActiveCfg = Release|Any CPU
- {5C3DFE9B-9690-475E-A0AE-D62315D38337}.Release|x86.Build.0 = Release|Any CPU
{B5F22590-E3CE-4595-BE48-AA7F1797A6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5F22590-E3CE-4595-BE48-AA7F1797A6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5F22590-E3CE-4595-BE48-AA7F1797A6B8}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -164,17 +154,42 @@ Global
{608273FF-01ED-48B3-B912-66CCDBF5572E}.Release|x64.Build.0 = Release|Any CPU
{608273FF-01ED-48B3-B912-66CCDBF5572E}.Release|x86.ActiveCfg = Release|Any CPU
{608273FF-01ED-48B3-B912-66CCDBF5572E}.Release|x86.Build.0 = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|x64.Build.0 = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Debug|x86.Build.0 = Debug|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|x64.ActiveCfg = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|x64.Build.0 = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|x86.ActiveCfg = Release|Any CPU
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E}.Release|x86.Build.0 = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|x64.Build.0 = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Debug|x86.Build.0 = Debug|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|x64.ActiveCfg = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|x64.Build.0 = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|x86.ActiveCfg = Release|Any CPU
+ {3D63C965-A734-45D6-B75D-AFDCAB511293}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{70D0903D-C65F-4600-B6F8-F7BD00500A51} = {0C2AC7A9-AC68-4668-B88E-9370C596F498}
{56F85916-3955-4558-8809-376D20902B94} = {0C2AC7A9-AC68-4668-B88E-9370C596F498}
{F056B3F1-B72D-4935-87EA-F7BFEA96AFB0} = {0C2AC7A9-AC68-4668-B88E-9370C596F498}
- {5C3DFE9B-9690-475E-A0AE-D62315D38337} = {F2864A9D-70F1-452F-AAAC-AAFD8102ABAD}
{B5F22590-E3CE-4595-BE48-AA7F1797A6B8} = {7CA79114-C359-4871-BFA7-0EA898B50AE4}
{2FFF985B-A26F-443D-A159-62ED2FD5A2BC} = {7CA79114-C359-4871-BFA7-0EA898B50AE4}
{6E58003B-E5E8-4AA4-8F70-A9442BBFC110} = {7CA79114-C359-4871-BFA7-0EA898B50AE4}
{A6D35BD9-A2A4-4937-89A8-DCB0D610B04A} = {768A592D-58EA-4CD3-A053-2E8F2DC7708A}
{D8C898F7-A0DE-4939-8708-3D4A5C383EFC} = {768A592D-58EA-4CD3-A053-2E8F2DC7708A}
{608273FF-01ED-48B3-B912-66CCDBF5572E} = {768A592D-58EA-4CD3-A053-2E8F2DC7708A}
+ {AAEC0516-A943-449E-A1E8-E0628BFFAA2E} = {49B4EAF5-8F45-493F-A25A-7F37DAAE6B1E}
+ {3D63C965-A734-45D6-B75D-AFDCAB511293} = {49B4EAF5-8F45-493F-A25A-7F37DAAE6B1E}
EndGlobalSection
EndGlobal
diff --git a/src/Dockerfile b/src/Dockerfile
index f99804c..0491463 100644
--- a/src/Dockerfile
+++ b/src/Dockerfile
@@ -1,16 +1,11 @@
-FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
-FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
-EXPOSE 80
+FROM mcr.microsoft.com/dotnet/sdk:5.0 AS sdk
-COPY . /app
-WORKDIR /app
+COPY . ./Build
+WORKDIR /Build
+RUN [ "dotnet", "publish", "-f", "net5.0", "-c", "Release", "Web/DevHive.Web/DevHive.Web.csproj", "-o", "/Out"]
-RUN dotnet restore
-RUN dotnet build -c Release -o /app/build
+FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime
+COPY --from=sdk /Out /App
-FROM build AS publish
-RUN dotnet publish "DevHive.sln" -c Release -o /app/publish
-
-FROM base AS final
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "DevHive.Web.dll"]
+WORKDIR /App
+ENTRYPOINT [ "dotnet", "DevHive.Web.dll" ]
diff --git a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
index 914efe0..a55972a 100644
--- a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
+++ b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
@@ -4,9 +4,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/Services/DevHive.Services.Models/Post/Rating/RatePostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs
index d4eb7bd..aaeab73 100644
--- a/src/Services/DevHive.Services.Models/Post/Rating/RatePostServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs
@@ -2,12 +2,12 @@ using System;
namespace DevHive.Services.Models.Post.Rating
{
- public class RatePostServiceModel
+ public class CreateRatingServiceModel
{
public Guid UserId { get; set; }
public Guid PostId { get; set; }
- public bool Liked { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs
index 8c73aaf..86b4957 100644
--- a/src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs
@@ -2,14 +2,14 @@ using System;
namespace DevHive.Services.Models.Post.Rating
{
- public class ReadPostRatingServiceModel
+ public class ReadRatingServiceModel
{
public Guid Id { get; set; }
public Guid PostId { get; set; }
- public int Likes { get; set; }
+ public Guid UserId { get; set; }
- public int Dislikes { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs
new file mode 100644
index 0000000..1ea8d8f
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevHive.Services.Models.Post.Rating
+{
+ public class UpdateRatingServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public Guid UserId { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public bool IsLike { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
index a7aa882..33d6520 100644
--- a/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
@@ -21,6 +21,7 @@ namespace DevHive.Services.Models.Post
public List<IdModel> Comments { get; set; } = new();
public List<string> FileUrls { get; set; }
- // public List<FileContentResult> Files { get; set; } = new();
+
+ public int CurrentRating { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
index bdfb2bb..d85eea2 100644
--- a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
+++ b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
@@ -5,14 +5,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.3"/>
- <PackageReference Include="Moq" Version="4.16.0"/>
+ <PackageReference Include="Moq" Version="4.16.1"/>
<PackageReference Include="NUnit" Version="3.13.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DevHive.Services\DevHive.Services.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
</ItemGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
index fefa6d8..4534511 100644
--- a/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
+++ b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
@@ -8,6 +8,14 @@ namespace DevHive.Services.Configurations.Mapping
{
public RatingMappings()
{
+ CreateMap<CreateRatingServiceModel, Rating>()
+ .ForMember(dest => dest.User, src => src.Ignore())
+ .ForMember(dest => dest.Post, src => src.Ignore())
+ .ForMember(dest => dest.Id, src => src.Ignore());
+
+ CreateMap<Rating, ReadRatingServiceModel>();
+
+ CreateMap<UpdateRatingServiceModel, Rating>();
}
}
}
diff --git a/src/Services/DevHive.Services/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj
index 650a304..f51c1b6 100644
--- a/src/Services/DevHive.Services/DevHive.Services.csproj
+++ b/src/Services/DevHive.Services/DevHive.Services.csproj
@@ -12,11 +12,13 @@
<PackageReference Include="AutoMapper" Version="10.1.1"/>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/>
<PackageReference Include="CloudinaryDotNet" Version="1.14.0"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Data\DevHive.Data\DevHive.Data.csproj"/>
<ProjectReference Include="..\DevHive.Services.Models\DevHive.Services.Models.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
</ItemGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
diff --git a/src/Services/DevHive.Services/Interfaces/IRateService.cs b/src/Services/DevHive.Services/Interfaces/IRateService.cs
deleted file mode 100644
index 359ef55..0000000
--- a/src/Services/DevHive.Services/Interfaces/IRateService.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using DevHive.Data.Models;
-using DevHive.Services.Models.Post.Rating;
-
-namespace DevHive.Services.Interfaces
-{
- public interface IRateService
- {
- Task<ReadPostRatingServiceModel> RatePost(RatePostServiceModel ratePostServiceModel);
-
- bool HasUserRatedThisPost(User user, Post post);
- }
-}
diff --git a/src/Services/DevHive.Services/Interfaces/IRatingService.cs b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
new file mode 100644
index 0000000..beea821
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Post.Rating;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IRatingService
+ {
+ Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel);
+
+ Task<ReadRatingServiceModel> GetRatingById(Guid ratingId);
+ Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId);
+
+
+ Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel);
+
+ Task<bool> DeleteRating(Guid ratingId);
+
+ Task<bool> HasUserRatedThisPost(Guid userId, Guid postId);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs
index 4a9ffc8..a55f9dd 100644
--- a/src/Services/DevHive.Services/Interfaces/IUserService.cs
+++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs
@@ -7,19 +7,64 @@ namespace DevHive.Services.Interfaces
{
public interface IUserService
{
+ /// <summary>
+ /// Log ins an existing user and gives him/her a JWT Token for further authorization
+ /// </summary>
+ /// <param name="loginModel">Login service model, conaining user's username and password</param>
+ /// <returns>A JWT Token for authorization</returns>
Task<TokenModel> LoginUser(LoginServiceModel loginModel);
+
+ /// <summary>
+ /// Registers a new user and gives him/her a JWT Token for further authorization
+ /// </summary>
+ /// <param name="registerModel">Register service model, containing the new user's data</param>
+ /// <returns>A JWT Token for authorization</returns>
Task<TokenModel> RegisterUser(RegisterServiceModel registerModel);
+ /// <summary>
+ /// Get a user by his username. Used for querying profiles without provided authentication
+ /// </summary>
+ /// <param name="username">User's username, who's to be queried</param>
+ /// <returns>The queried user or null, if non existant</returns>
Task<UserServiceModel> GetUserByUsername(string username);
+
+ /// <summary>
+ /// Get a user by his Guid. Used for querying full user's profile
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="id">User's username, who's to be queried</param>
+ /// <returns>The queried user or null, if non existant</returns>
Task<UserServiceModel> GetUserById(Guid id);
+ /// <summary>
+ /// Updates a user's data, provided a full model with new details
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="updateUserServiceModel">Full update user model for updating</param>
+ /// <returns>Read model of the new user</returns>
Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel);
+
+ /// <summary>
+ /// Uploads the given picture and assigns it's link to the user in the database
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="updateProfilePictureServiceModel">Contains User's Guid and the new picture to be updated</param>
+ /// <returns>The new picture's URL</returns>
Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel);
+ /// <summary>
+ /// Deletes a user from the database and removes his data entirely
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="id">The user's Guid, who's to be deleted</param>
+ /// <returns>True if successfull, false otherwise</returns>
Task<bool> DeleteUser(Guid id);
- Task<bool> ValidJWT(Guid id, string rawTokenData);
-
+ /// <summary>
+ /// We don't talk about that!
+ /// </summary>
+ /// <param name="userId"></param>
+ /// <returns></returns>
Task<TokenModel> SuperSecretPromotionToAdmin(Guid userId);
}
}
diff --git a/src/Services/DevHive.Services/Options/JwtOptions.cs b/src/Services/DevHive.Services/Options/JwtOptions.cs
deleted file mode 100644
index d973f45..0000000
--- a/src/Services/DevHive.Services/Options/JwtOptions.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.Extensions.Options;
-
-namespace DevHive.Services.Options
-{
- public class JwtOptions
- {
- public JwtOptions(string secret)
- {
- this.Secret = secret;
- }
-
- public string Secret { get; init; }
- }
-}
diff --git a/src/Services/DevHive.Services/Services/RateService.cs b/src/Services/DevHive.Services/Services/RateService.cs
deleted file mode 100644
index caf4b80..0000000
--- a/src/Services/DevHive.Services/Services/RateService.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using AutoMapper;
-using DevHive.Data.Interfaces;
-using DevHive.Data.Models;
-using DevHive.Services.Interfaces;
-using DevHive.Services.Models.Post.Rating;
-
-namespace DevHive.Services.Services
-{
- public class RateService : IRateService
- {
- private readonly IPostRepository _postRepository;
- private readonly IUserRepository _userRepository;
- private readonly IRatingRepository _ratingRepository;
- private readonly IMapper _mapper;
-
- public RateService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper)
- {
- this._postRepository = postRepository;
- this._ratingRepository = ratingRepository;
- this._userRepository = userRepository;
- this._mapper = mapper;
- }
-
- public async Task<ReadPostRatingServiceModel> RatePost(RatePostServiceModel ratePostServiceModel)
- {
- throw new NotImplementedException();
- // if (!await this._postRepository.DoesPostExist(ratePostServiceModel.PostId))
- // throw new ArgumentException("Post does not exist!");
-
- // if (!await this._userRepository.DoesUserExistAsync(ratePostServiceModel.UserId))
- // throw new ArgumentException("User does not exist!");
-
- // Post post = await this._postRepository.GetByIdAsync(ratePostServiceModel.PostId);
- // User user = await this._userRepository.GetByIdAsync(ratePostServiceModel.UserId);
-
- // if (this.HasUserRatedThisPost(user, post))
- // throw new ArgumentException("You can't rate the same post more then one(duh, amigo)");
-
- // this.Rate(user, post, ratePostServiceModel.Liked);
-
- // bool success = await this._ratingRepository.EditAsync(post.Rating.Id, post.Rating);
- // if (!success)
- // throw new InvalidOperationException("Unable to rate the post!");
-
- // Rating newRating = await this._ratingRepository.GetByIdAsync(post.Rating.Id);
- // return this._mapper.Map<ReadPostRatingServiceModel>(newRating);
- }
-
- public async Task<ReadPostRatingServiceModel> RemoveUserRateFromPost(Guid userId, Guid postId)
- {
- throw new NotImplementedException();
- // Post post = await this._postRepository.GetByIdAsync(postId);
- // User user = await this._userRepository.GetByIdAsync(userId);
-
- // if (!this.HasUserRatedThisPost(user, post))
- // throw new ArgumentException("You haven't rated this post, lmao!");
- }
-
- public bool HasUserRatedThisPost(User user, Post post)
- {
- throw new NotImplementedException();
- // return post.Rating.UsersThatRated
- // .Any(x => x.Id == user.Id);
- }
-
- private void Rate(User user, Post post, bool liked)
- {
- throw new NotImplementedException();
- // if (liked)
- // post.Rating.Rate++;
- // else
- // post.Rating.Rate--;
-
- // post.Rating.UsersThatRated.Add(user);
- }
- }
-}
diff --git a/src/Services/DevHive.Services/Services/RatingService.cs b/src/Services/DevHive.Services/Services/RatingService.cs
new file mode 100644
index 0000000..6ddba1c
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/RatingService.cs
@@ -0,0 +1,125 @@
+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.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Post.Rating;
+
+namespace DevHive.Services.Services
+{
+ public class RatingService : IRatingService
+ {
+ private readonly IPostRepository _postRepository;
+ private readonly IUserRepository _userRepository;
+ private readonly IRatingRepository _ratingRepository;
+ private readonly IMapper _mapper;
+
+ public RatingService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper)
+ {
+ this._postRepository = postRepository;
+ this._ratingRepository = ratingRepository;
+ this._userRepository = userRepository;
+ this._mapper = mapper;
+ }
+
+ #region Create
+ public async Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel)
+ {
+ if (!await this._postRepository.DoesPostExist(createRatingServiceModel.PostId))
+ throw new ArgumentException("Post does not exist!");
+
+ if (await this._ratingRepository.UserRatedPost(createRatingServiceModel.UserId, createRatingServiceModel.PostId))
+ throw new ArgumentException("User already rated the post!");
+
+ Rating rating = this._mapper.Map<Rating>(createRatingServiceModel);
+
+ rating.User = await this._userRepository.GetByIdAsync(createRatingServiceModel.UserId);
+ rating.Post = await this._postRepository.GetByIdAsync(createRatingServiceModel.PostId);
+
+ bool success = await this._ratingRepository.AddAsync(rating);
+
+ if (success)
+ {
+ Rating newRating = await this._ratingRepository.GetRatingByUserAndPostId(rating.User.Id, rating.Post.Id);
+
+ return newRating.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadRatingServiceModel> GetRatingById(Guid ratingId)
+ {
+ Rating rating = await this._ratingRepository.GetByIdAsync(ratingId) ??
+ throw new ArgumentException("The rating does not exist");
+
+ ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating);
+ readRatingServiceModel.UserId = rating.User.Id;
+
+ return readRatingServiceModel;
+ }
+
+ public async Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId)
+ {
+ Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId) ??
+ throw new ArgumentException("The rating does not exist");
+
+ ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating);
+ readRatingServiceModel.UserId = rating.User.Id;
+
+ return readRatingServiceModel;
+ }
+ #endregion
+
+ #region Update
+ public async Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel)
+ {
+ Rating rating = await this._ratingRepository.GetByIdAsync(updateRatingServiceModel.Id) ??
+ throw new ArgumentException("Rating does not exist!");
+
+ User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ??
+ throw new ArgumentException("User does not exist!");
+
+ if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId))
+ throw new ArgumentException("User has not rated the post!");
+
+ rating.User = user;
+ rating.IsLike = updateRatingServiceModel.IsLike;
+
+ bool result = await this._ratingRepository.EditAsync(updateRatingServiceModel.Id, rating);
+
+ if (result)
+ {
+ ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating);
+ return readRatingServiceModel;
+ }
+ else
+ return null;
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteRating(Guid ratingId)
+ {
+ if (!await this._ratingRepository.DoesRatingExist(ratingId))
+ throw new ArgumentException("Rating does not exist!");
+
+ Rating rating = await this._ratingRepository.GetByIdAsync(ratingId);
+ return await this._ratingRepository.DeleteAsync(rating);
+ }
+ #endregion
+
+ public async Task<bool> HasUserRatedThisPost(Guid userId, Guid postId)
+ {
+ return await this._ratingRepository
+ .UserRatedPost(userId, postId);
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs
index dfd45cc..4f74b06 100644
--- a/src/Services/DevHive.Services/Services/UserService.cs
+++ b/src/Services/DevHive.Services/Services/UserService.cs
@@ -1,21 +1,15 @@
using AutoMapper;
-using DevHive.Services.Options;
using DevHive.Services.Models.User;
using System.Threading.Tasks;
using DevHive.Data.Models;
using System;
-using System.IdentityModel.Tokens.Jwt;
-using System.Security.Claims;
-using Microsoft.IdentityModel.Tokens;
-using System.Text;
using System.Collections.Generic;
using DevHive.Common.Models.Identity;
using DevHive.Services.Interfaces;
using DevHive.Data.Interfaces;
using System.Linq;
-using DevHive.Common.Models.Misc;
using Microsoft.AspNetCore.Http;
-using Newtonsoft.Json;
+using DevHive.Common.Jwt.Interfaces;
namespace DevHive.Services.Services
{
@@ -26,31 +20,27 @@ namespace DevHive.Services.Services
private readonly ILanguageRepository _languageRepository;
private readonly ITechnologyRepository _technologyRepository;
private readonly IMapper _userMapper;
- private readonly JwtOptions _jwtOptions;
private readonly ICloudService _cloudService;
+ private readonly IJwtService _jwtService;
public UserService(IUserRepository userRepository,
ILanguageRepository languageRepository,
IRoleRepository roleRepository,
ITechnologyRepository technologyRepository,
IMapper mapper,
- JwtOptions jwtOptions,
- ICloudService cloudService)
+ ICloudService cloudService,
+ IJwtService jwtService)
{
this._userRepository = userRepository;
this._roleRepository = roleRepository;
this._userMapper = mapper;
- this._jwtOptions = jwtOptions;
this._languageRepository = languageRepository;
this._technologyRepository = technologyRepository;
this._cloudService = cloudService;
+ this._jwtService = jwtService;
}
#region Authentication
- /// <summary>
- /// Adds a new user to the database with the values from the given model.
- /// Returns a JSON Web Token (that can be used for authorization)
- /// </summary>
public async Task<TokenModel> LoginUser(LoginServiceModel loginModel)
{
if (!await this._userRepository.DoesUsernameExistAsync(loginModel.UserName))
@@ -61,12 +51,10 @@ namespace DevHive.Services.Services
if (!await this._userRepository.VerifyPassword(user, loginModel.Password))
throw new ArgumentException("Incorrect password!");
- return new TokenModel(WriteJWTSecurityToken(user.Id, user.UserName, user.Roles));
+ List<string> roleNames = user.Roles.Select(x => x.Name).ToList();
+ return new TokenModel(this._jwtService.GenerateJwtToken(user.Id, user.UserName, roleNames));
}
- /// <summary>
- /// Returns a new JSON Web Token (that can be used for authorization) for the given user
- /// </summary>
public async Task<TokenModel> RegisterUser(RegisterServiceModel registerModel)
{
if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName))
@@ -86,7 +74,9 @@ namespace DevHive.Services.Services
throw new ArgumentException("Unable to add role to user");
User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName);
- return new TokenModel(WriteJWTSecurityToken(createdUser.Id, createdUser.UserName, createdUser.Roles));
+
+ List<string> roleNames = createdUser.Roles.Select(x => x.Name).ToList();
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
}
#endregion
@@ -130,9 +120,6 @@ namespace DevHive.Services.Services
return this._userMapper.Map<UserServiceModel>(newUser);
}
- /// <summary>
- /// Uploads the given picture and assigns it's link to the user in the database
- /// </summary>
public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel)
{
User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId);
@@ -169,57 +156,7 @@ namespace DevHive.Services.Services
#region Validations
/// <summary>
- /// Checks whether the given user, gotten by the "id" property,
- /// is the same user as the one in the token (unless the user in the token has the admin role)
- /// and the roles in the token are the same as those in the user, gotten by the id in the token
- /// </summary>
- public async Task<bool> ValidJWT(Guid id, string rawTokenData)
- {
- // There is authorization name in the beginning, i.e. "Bearer eyJh..."
- var jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7));
-
- Guid jwtUserID = new(UserService.GetClaimTypeValues("ID", jwt.Claims).First());
- List<string> jwtRoleNames = UserService.GetClaimTypeValues("role", jwt.Claims);
-
- User user = await this._userRepository.GetByIdAsync(jwtUserID)
- ?? throw new ArgumentException("User does not exist!");
-
- /* Check if he is an admin */
- if (user.Roles.Any(x => x.Name == Role.AdminRole))
- return true;
-
- if (!jwtRoleNames.Contains(Role.AdminRole) && user.Id != id)
- return false;
-
- // Check if jwt contains all user roles (if it doesn't, jwt is either old or tampered with)
- foreach (var role in user.Roles)
- if (!jwtRoleNames.Contains(role.Name))
- return false;
-
- // Check if jwt contains only roles of user
- if (jwtRoleNames.Count != user.Roles.Count)
- return false;
-
- return true;
- }
-
- /// <summary>
- /// Returns all values from a given claim type
- /// </summary>
- private static List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims)
- {
- List<string> toReturn = new();
-
- foreach (var claim in claims)
- if (claim.Type == type)
- toReturn.Add(claim.Value);
-
- return toReturn;
- }
-
- /// <summary>
- /// Checks whether the user in the model exists
- /// and whether the username in the model is already taken.
+ /// Checks whether the user in the model exists and whether the username in the model is already taken.
/// If the check fails (is false), it throws an exception, otherwise nothing happens
/// </summary>
private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel)
@@ -241,38 +178,6 @@ namespace DevHive.Services.Services
if (!await this._userRepository.ValidateFriendsCollectionAsync(usernames))
throw new ArgumentException("One or more friends do not exist!");
}
-
- /// <summary>
- /// Return a new JSON Web Token, containing the user id, username and roles.
- /// Tokens have an expiration time of 7 days.
- /// </summary>
- private string WriteJWTSecurityToken(Guid userId, string username, HashSet<Role> roles)
- {
- byte[] signingKey = Encoding.ASCII.GetBytes(_jwtOptions.Secret);
- HashSet<Claim> claims = new()
- {
- new Claim("ID", $"{userId}"),
- new Claim("Username", username)
- };
-
- foreach (var role in roles)
- {
- claims.Add(new Claim(ClaimTypes.Role, role.Name));
- }
-
- SecurityTokenDescriptor tokenDescriptor = new()
- {
- Subject = new ClaimsIdentity(claims),
- Expires = DateTime.Today.AddDays(7),
- SigningCredentials = new SigningCredentials(
- new SymmetricSecurityKey(signingKey),
- SecurityAlgorithms.HmacSha512Signature)
- };
-
- JwtSecurityTokenHandler tokenHandler = new();
- SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
- return tokenHandler.WriteToken(token);
- }
#endregion
#region Misc
@@ -294,9 +199,13 @@ namespace DevHive.Services.Services
user.Roles.Add(admin);
await this._userRepository.EditAsync(user.Id, user);
- User newUser = await this._userRepository.GetByIdAsync(userId);
+ User createdUser = await this._userRepository.GetByIdAsync(userId);
+ List<string> roleNames = createdUser
+ .Roles
+ .Select(x => x.Name)
+ .ToList();
- return new TokenModel(WriteJWTSecurityToken(newUser.Id, newUser.UserName, newUser.Roles));
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
}
private async Task PopulateUserModel(User user, UpdateUserServiceModel updateUserServiceModel)
diff --git a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj
index 64d0bd0..9d62eee 100644
--- a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj
+++ b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj
@@ -3,10 +3,11 @@
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
- <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/Web/DevHive.Web.Models/Post/ReadPostWebModel.cs b/src/Web/DevHive.Web.Models/Post/ReadPostWebModel.cs
index 3ae93aa..d6ea1f4 100644
--- a/src/Web/DevHive.Web.Models/Post/ReadPostWebModel.cs
+++ b/src/Web/DevHive.Web.Models/Post/ReadPostWebModel.cs
@@ -21,5 +21,7 @@ namespace DevHive.Web.Models.Post
public List<IdModel> Comments { get; set; }
public List<string> FileUrls { get; set; }
+
+ public int CurrentRating { get; set; }
}
}
diff --git a/src/Web/DevHive.Web.Models/Rating/RatePostWebModel.cs b/src/Web/DevHive.Web.Models/Rating/CreateRatingWebModel.cs
index cbba4ab..abbb702 100644
--- a/src/Web/DevHive.Web.Models/Rating/RatePostWebModel.cs
+++ b/src/Web/DevHive.Web.Models/Rating/CreateRatingWebModel.cs
@@ -2,10 +2,10 @@ using System;
namespace DevHive.Web.Models.Rating
{
- public class RatePostWebModel
+ public class CreateRatingWebModel
{
public Guid PostId { get; set; }
- public bool Liked { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Web/DevHive.Web.Models/Rating/ReadPostRatingWebModel.cs b/src/Web/DevHive.Web.Models/Rating/ReadRatingWebModel.cs
index 8afd57e..40f4c6f 100644
--- a/src/Web/DevHive.Web.Models/Rating/ReadPostRatingWebModel.cs
+++ b/src/Web/DevHive.Web.Models/Rating/ReadRatingWebModel.cs
@@ -2,14 +2,14 @@ using System;
namespace DevHive.Web.Models.Rating
{
- public class ReadPostRatingWebModel
+ public class ReadRatingWebModel
{
public Guid Id { get; set; }
public Guid PostId { get; set; }
- public int Likes { get; set; }
+ public Guid UserId { get; set; }
- public int Dislikes { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Web/DevHive.Web.Models/Rating/UpdateRatingWebModel.cs b/src/Web/DevHive.Web.Models/Rating/UpdateRatingWebModel.cs
new file mode 100644
index 0000000..425c3e1
--- /dev/null
+++ b/src/Web/DevHive.Web.Models/Rating/UpdateRatingWebModel.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DevHive.Web.Models.Rating
+{
+ public class UpdateRatingWebModel
+ {
+ public Guid Id { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public bool IsLike { get; set; }
+ }
+}
diff --git a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj
index 465698c..5099119 100644
--- a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj
+++ b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj
@@ -4,14 +4,16 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Moq" Version="4.16.0"/>
+ <PackageReference Include="Moq" Version="4.16.1"/>
<PackageReference Include="NUnit" Version="3.13.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/>
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DevHive.Web\DevHive.Web.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
</ItemGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureAutoMapper.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureAutoMapper.cs
index 0b8194e..cd5679f 100644
--- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureAutoMapper.cs
+++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureAutoMapper.cs
@@ -1,4 +1,7 @@
using System;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
using AutoMapper;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs
index c547951..a0d0979 100644
--- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs
+++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs
@@ -1,3 +1,6 @@
+using System.Text;
+using DevHive.Common.Jwt;
+using DevHive.Common.Jwt.Interfaces;
using DevHive.Data.Interfaces;
using DevHive.Data.Repositories;
using DevHive.Services.Interfaces;
@@ -27,12 +30,20 @@ namespace DevHive.Web.Configurations.Extensions
services.AddTransient<IPostService, PostService>();
services.AddTransient<ICommentService, CommentService>();
services.AddTransient<IFeedService, FeedService>();
+ services.AddTransient<IRatingService, RatingService>();
+
services.AddTransient<ICloudService, CloudinaryService>(options =>
new CloudinaryService(
cloudName: configuration.GetSection("Cloud").GetSection("cloudName").Value,
apiKey: configuration.GetSection("Cloud").GetSection("apiKey").Value,
apiSecret: configuration.GetSection("Cloud").GetSection("apiSecret").Value));
- services.AddTransient<IRateService, RateService>();
+
+ services.AddSingleton<IJwtService, JwtService>(options =>
+ new JwtService(
+ 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<IRatingService, RatingService>();
}
}
}
diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureJwt.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureJwt.cs
index 8d387bd..18127bc 100644
--- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureJwt.cs
+++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureJwt.cs
@@ -1,6 +1,5 @@
using System.Text;
using System.Threading.Tasks;
-using DevHive.Services.Options;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -12,15 +11,10 @@ namespace DevHive.Web.Configurations.Extensions
{
public static void JWTConfiguration(this IServiceCollection services, IConfiguration configuration)
{
- services.AddSingleton(new JwtOptions(configuration
- .GetSection("AppSettings")
- .GetSection("Secret")
- .Value));
-
// Get key from appsettings.json
- var key = Encoding.ASCII.GetBytes(configuration
- .GetSection("AppSettings")
- .GetSection("Secret")
+ var signingKey = Encoding.ASCII.GetBytes(configuration
+ .GetSection("Jwt")
+ .GetSection("signingKey")
.Value);
// Setup Jwt Authentication
@@ -42,7 +36,7 @@ namespace DevHive.Web.Configurations.Extensions
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
- IssuerSigningKey = new SymmetricSecurityKey(key),
+ IssuerSigningKey = new SymmetricSecurityKey(signingKey),
ValidateIssuer = false,
ValidateAudience = false
};
diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureSwagger.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureSwagger.cs
index a0641ab..9387561 100644
--- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureSwagger.cs
+++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureSwagger.cs
@@ -1,23 +1,65 @@
+using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.OpenApi.Models;
+using NSwag;
+using NSwag.Generation.Processors.Security;
namespace DevHive.Web.Configurations.Extensions
{
public static class SwaggerExtensions
{
+#pragma warning disable S1075
+ private const string LicenseName = "GPL-3.0 License";
+ private const string LicenseUri = "https://github.com/Team-Kaleidoscope/DevHive/blob/main/LICENSE";
+ private const string TermsOfServiceUri = "https://example.com/terms";
+#pragma warning restore S1075
+
public static void SwaggerConfiguration(this IServiceCollection services)
{
- services.AddSwaggerGen(c =>
+ services.AddOpenApiDocument(c =>
{
- c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
+ c.GenerateXmlObjects = true;
+ c.UseControllerSummaryAsTagDescription = true;
+
+ c.AllowNullableBodyParameters = false;
+ c.Description = "DevHive Social Media's API Endpoints";
+
+ c.PostProcess = doc =>
+ {
+ doc.Info.Version = "v0.1";
+ doc.Info.Title = "API";
+ doc.Info.Description = "DevHive Social Media's first official API release";
+ doc.Info.TermsOfService = TermsOfServiceUri;
+ doc.Info.License = new NSwag.OpenApiLicense
+ {
+ Name = LicenseName,
+ Url = LicenseUri
+ };
+ };
+
+ c.AddSecurity("Bearer", Enumerable.Empty<string>(), new OpenApiSecurityScheme
+ {
+ Type = OpenApiSecuritySchemeType.ApiKey,
+ Name = "Authorization",
+ In = OpenApiSecurityApiKeyLocation.Header,
+ Description = "Type into the textbox: Bearer {your JWT token}."
+ });
+ c.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("Bearer"));
});
}
public static void UseSwaggerConfiguration(this IApplicationBuilder app)
{
- app.UseSwagger();
- app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"));
+ app.UseOpenApi(c =>
+ {
+ c.DocumentName = "v0.1";
+ });
+ app.UseSwaggerUi3(c =>
+ {
+ c.DocumentTitle = "DevHive API";
+ c.EnableTryItOut = false;
+ c.DocExpansion = "list";
+ });
}
}
-} \ No newline at end of file
+}
diff --git a/src/Web/DevHive.Web/Configurations/Mapping/RatingMappings.cs b/src/Web/DevHive.Web/Configurations/Mapping/RatingMappings.cs
index a29e06c..23c3eeb 100644
--- a/src/Web/DevHive.Web/Configurations/Mapping/RatingMappings.cs
+++ b/src/Web/DevHive.Web/Configurations/Mapping/RatingMappings.cs
@@ -8,9 +8,11 @@ namespace DevHive.Web.Configurations.Mapping
{
public RatingMappings()
{
- CreateMap<RatePostWebModel, RatePostServiceModel>();
+ CreateMap<CreateRatingWebModel, CreateRatingServiceModel>();
- CreateMap<ReadPostRatingServiceModel, ReadPostRatingWebModel>();
+ CreateMap<ReadRatingServiceModel, ReadRatingWebModel>();
+
+ CreateMap<UpdateRatingWebModel, UpdateRatingServiceModel>();
}
}
}
diff --git a/src/Web/DevHive.Web/Controllers/CommentController.cs b/src/Web/DevHive.Web/Controllers/CommentController.cs
index c38e300..8fa3577 100644
--- a/src/Web/DevHive.Web/Controllers/CommentController.cs
+++ b/src/Web/DevHive.Web/Controllers/CommentController.cs
@@ -6,9 +6,13 @@ using DevHive.Web.Models.Comment;
using DevHive.Services.Models.Comment;
using Microsoft.AspNetCore.Authorization;
using DevHive.Services.Interfaces;
+using DevHive.Common.Jwt.Interfaces;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the comments layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
[Authorize(Roles = "User,Admin")]
@@ -16,16 +20,28 @@ namespace DevHive.Web.Controllers
{
private readonly ICommentService _commentService;
private readonly IMapper _commentMapper;
+ private readonly IJwtService _jwtService;
- public CommentController(ICommentService commentService, IMapper commentMapper)
+ public CommentController(ICommentService commentService, IMapper commentMapper, IJwtService jwtService)
{
this._commentService = commentService;
this._commentMapper = commentMapper;
+ this._jwtService = jwtService;
}
+ /// <summary>
+ /// Create a comment and attach it to a post
+ /// </summary>
+ /// <param name="userId">The useer's Id</param>
+ /// <param name="createCommentWebModel">The new comment's parametars</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>The comment's Id</returns>
[HttpPost]
public async Task<IActionResult> AddComment(Guid userId, [FromBody] CreateCommentWebModel createCommentWebModel, [FromHeader] string authorization)
{
+ if (!this._jwtService.ValidateToken(userId, authorization))
+ return new UnauthorizedResult();
+
if (!await this._commentService.ValidateJwtForCreating(userId, authorization))
return new UnauthorizedResult();
@@ -40,20 +56,32 @@ namespace DevHive.Web.Controllers
new OkObjectResult(new { Id = id });
}
+ /// <summary>
+ /// Query comment's data by it's Id
+ /// </summary>
+ /// <param name="commentId">The comment's Id</param>
+ /// <returns>Full data model of the comment</returns>
[HttpGet]
[AllowAnonymous]
- public async Task<IActionResult> GetCommentById(Guid id)
+ public async Task<IActionResult> GetCommentById(Guid commentId)
{
- ReadCommentServiceModel readCommentServiceModel = await this._commentService.GetCommentById(id);
+ ReadCommentServiceModel readCommentServiceModel = await this._commentService.GetCommentById(commentId);
ReadCommentWebModel readCommentWebModel = this._commentMapper.Map<ReadCommentWebModel>(readCommentServiceModel);
return new OkObjectResult(readCommentWebModel);
}
+ /// <summary>
+ /// Update comment's parametars. Comment creator only!
+ /// </summary>
+ /// <param name="userId">The comment creator's Id</param>
+ /// <param name="updateCommentWebModel">New comment's parametars</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>Ok result</returns>
[HttpPut]
public async Task<IActionResult> UpdateComment(Guid userId, [FromBody] UpdateCommentWebModel updateCommentWebModel, [FromHeader] string authorization)
{
- if (!await this._commentService.ValidateJwtForComment(updateCommentWebModel.CommentId, authorization))
+ if (!this._jwtService.ValidateToken(userId, authorization))
return new UnauthorizedResult();
UpdateCommentServiceModel updateCommentServiceModel =
@@ -67,17 +95,22 @@ namespace DevHive.Web.Controllers
new OkObjectResult(new { Id = id });
}
+ /// <summary>
+ /// Delete a comment. Comment creator only!
+ /// </summary>
+ /// <param name="commentId">Comment's Id</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>Ok result</returns>
[HttpDelete]
- public async Task<IActionResult> DeleteComment(Guid id, [FromHeader] string authorization)
+ public async Task<IActionResult> DeleteComment(Guid commentId, [FromHeader] string authorization)
{
- if (!await this._commentService.ValidateJwtForComment(id, authorization))
+ if (!await this._commentService.ValidateJwtForComment(commentId, authorization))
return new UnauthorizedResult();
- return await this._commentService.DeleteComment(id) ?
+ return await this._commentService.DeleteComment(commentId) ?
new OkResult() :
new BadRequestObjectResult("Could not delete Comment");
}
-
}
}
diff --git a/src/Web/DevHive.Web/Controllers/FeedController.cs b/src/Web/DevHive.Web/Controllers/FeedController.cs
index abca3e4..37532a9 100644
--- a/src/Web/DevHive.Web/Controllers/FeedController.cs
+++ b/src/Web/DevHive.Web/Controllers/FeedController.cs
@@ -10,6 +10,9 @@ using Microsoft.AspNetCore.Mvc;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the feed layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
[Authorize(Roles = "User,Admin")]
@@ -24,6 +27,12 @@ namespace DevHive.Web.Controllers
this._mapper = mapper;
}
+ /// <summary>
+ /// Query posts for user's feed
+ /// </summary>
+ /// <param name="userId">The user's Id, whose feed is begin queried</param>
+ /// <param name="getPageWebModel">Page parametars</param>
+ /// <returns>A page of the feed</returns>
[HttpPost]
[Route("GetPosts")]
public async Task<IActionResult> GetPosts(Guid userId, [FromBody] GetPageWebModel getPageWebModel)
@@ -37,6 +46,12 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(readPageWebModel);
}
+ /// <summary>
+ /// Query a user profile's posts
+ /// </summary>
+ /// <param name="username">The user's username, whose posts are being queried</param>
+ /// <param name="getPageWebModel">Page parametars</param>
+ /// <returns>A page of the user's posts</returns>
[HttpPost]
[Route("GetUserPosts")]
[AllowAnonymous]
diff --git a/src/Web/DevHive.Web/Controllers/LanguageController.cs b/src/Web/DevHive.Web/Controllers/LanguageController.cs
index 5b0d5de..665fb66 100644
--- a/src/Web/DevHive.Web/Controllers/LanguageController.cs
+++ b/src/Web/DevHive.Web/Controllers/LanguageController.cs
@@ -10,6 +10,9 @@ using Microsoft.AspNetCore.Mvc;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the language layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
public class LanguageController
@@ -23,6 +26,11 @@ namespace DevHive.Web.Controllers
this._languageMapper = mapper;
}
+ /// <summary>
+ /// Create a new language, so users can have a choice. Admin only!
+ /// </summary>
+ /// <param name="createLanguageWebModel">The new language's parametars</param>
+ /// <returns>The new language's Id</returns>
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create([FromBody] CreateLanguageWebModel createLanguageWebModel)
@@ -36,6 +44,11 @@ namespace DevHive.Web.Controllers
new OkObjectResult(new { Id = id });
}
+ /// <summary>
+ /// Query full language data by Id
+ /// </summary>
+ /// <param name="id">The language's Id</param>
+ /// <returns>Full language data</returns>
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> GetById(Guid id)
@@ -46,6 +59,10 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(languageWebModel);
}
+ /// <summary>
+ /// Query all languages in the database
+ /// </summary>
+ /// <returns>All languages in the database</returns>
[HttpGet]
[Route("GetLanguages")]
[Authorize(Roles = "User,Admin")]
@@ -57,6 +74,12 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(languageWebModels);
}
+ /// <summary>
+ /// Alter language's properties. Admin only!
+ /// </summary>
+ /// <param name="id">The language's Id</param>
+ /// <param name="updateModel">The langauge's new parametars</param>
+ /// <returns>Ok result</returns>
[HttpPut]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, [FromBody] UpdateLanguageWebModel updateModel)
@@ -72,11 +95,16 @@ namespace DevHive.Web.Controllers
return new OkResult();
}
+ /// <summary>
+ /// Delete a language. Admin only!
+ /// </summary>
+ /// <param name="langaugeId">The language's Id</param>
+ /// <returns>Ok result</returns>
[HttpDelete]
[Authorize(Roles = "Admin")]
- public async Task<IActionResult> Delete(Guid id)
+ public async Task<IActionResult> Delete(Guid langaugeId)
{
- bool result = await this._languageService.DeleteLanguage(id);
+ bool result = await this._languageService.DeleteLanguage(langaugeId);
if (!result)
return new BadRequestObjectResult("Could not delete Language");
diff --git a/src/Web/DevHive.Web/Controllers/PostController.cs b/src/Web/DevHive.Web/Controllers/PostController.cs
index d3fdbf6..44b291d 100644
--- a/src/Web/DevHive.Web/Controllers/PostController.cs
+++ b/src/Web/DevHive.Web/Controllers/PostController.cs
@@ -6,9 +6,13 @@ using DevHive.Web.Models.Post;
using DevHive.Services.Models.Post;
using Microsoft.AspNetCore.Authorization;
using DevHive.Services.Interfaces;
+using DevHive.Common.Jwt.Interfaces;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the post layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
[Authorize(Roles = "User,Admin")]
@@ -16,18 +20,27 @@ namespace DevHive.Web.Controllers
{
private readonly IPostService _postService;
private readonly IMapper _postMapper;
+ private readonly IJwtService _jwtService;
- public PostController(IPostService postService, IMapper postMapper)
+ public PostController(IPostService postService, IMapper postMapper, IJwtService jwtService)
{
this._postService = postService;
this._postMapper = postMapper;
+ this._jwtService = jwtService;
}
#region Create
+ /// <summary>
+ /// Create a new post
+ /// </summary>
+ /// <param name="userId">The user's Id</param>
+ /// <param name="createPostWebModel">The new post's data</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>New post's Id</returns>
[HttpPost]
public async Task<IActionResult> Create(Guid userId, [FromForm] CreatePostWebModel createPostWebModel, [FromHeader] string authorization)
{
- if (!await this._postService.ValidateJwtForCreating(userId, authorization))
+ if (!this._jwtService.ValidateToken(userId, authorization))
return new UnauthorizedResult();
CreatePostServiceModel createPostServiceModel =
@@ -43,6 +56,11 @@ namespace DevHive.Web.Controllers
#endregion
#region Read
+ /// <summary>
+ /// Query full post's data by it's Id
+ /// </summary>
+ /// <param name="id">The post's Id</param>
+ /// <returns>Full data model of the post</returns>
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> GetById(Guid id)
@@ -55,9 +73,19 @@ namespace DevHive.Web.Controllers
#endregion
#region Update
+ /// <summary>
+ /// Update post's data. Creator only!
+ /// </summary>
+ /// <param name="userId">The post creator's Id</param>
+ /// <param name="updatePostWebModel">The new params of the post</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>The post's Id</returns>
[HttpPut]
public async Task<IActionResult> Update(Guid userId, [FromForm] UpdatePostWebModel updatePostWebModel, [FromHeader] string authorization)
{
+ if (!this._jwtService.ValidateToken(userId, authorization))
+ return new UnauthorizedResult();
+
if (!await this._postService.ValidateJwtForPost(updatePostWebModel.PostId, authorization))
return new UnauthorizedResult();
@@ -74,13 +102,19 @@ namespace DevHive.Web.Controllers
#endregion
#region Delete
+ /// <summary>
+ /// Delete a post. Creator only!
+ /// </summary>
+ /// <param name="postId">Post's Id</param>
+ /// <param name="authorization">JWT Bearer token</param>
+ /// <returns>Ok result</returns>
[HttpDelete]
- public async Task<IActionResult> Delete(Guid id, [FromHeader] string authorization)
+ public async Task<IActionResult> Delete(Guid postId, [FromHeader] string authorization)
{
- if (!await this._postService.ValidateJwtForPost(id, authorization))
+ if (!await this._postService.ValidateJwtForPost(postId, authorization))
return new UnauthorizedResult();
- return await this._postService.DeletePost(id) ?
+ return await this._postService.DeletePost(postId) ?
new OkResult() :
new BadRequestObjectResult("Could not delete Post");
}
diff --git a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs
new file mode 100644
index 0000000..2eec99e
--- /dev/null
+++ b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Web.Models.User;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DevHive.Web.Controllers
+{
+ /// <summary>
+ /// All endpoints for interacting with the profile picture layer
+ /// </summary>
+ [ApiController]
+ [Route("api/[controller]")]
+ public class ProfilePictureController
+ {
+ // private readonly ProfilePictureService _profilePictureService;
+
+ // public ProfilePictureController(ProfilePictureService profilePictureService)
+ // {
+ // this._profilePictureService = profilePictureService;
+ // }
+
+ /// <summary>
+ /// Alter the profile picture of a user
+ /// </summary>
+ /// <param name="userId">The user's Id</param>
+ /// <param name="updateProfilePictureWebModel">The new profile picture</param>
+ /// <param name="authorization">JWT Bearer Token</param>
+ /// <returns>???</returns>
+ [HttpPut]
+ [Route("ProfilePicture")]
+ [Authorize(Roles = "User,Admin")]
+ public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization)
+ {
+ throw new NotImplementedException();
+ // if (!await this._userService.ValidJWT(userId, authorization))
+ // return new UnauthorizedResult();
+
+ // UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map<UpdateProfilePictureServiceModel>(updateProfilePictureWebModel);
+ // updateProfilePictureServiceModel.UserId = userId;
+
+ // ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel);
+ // ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map<ProfilePictureWebModel>(profilePictureServiceModel);
+
+ // return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel);
+ }
+ }
+}
diff --git a/src/Web/DevHive.Web/Controllers/RateController.cs b/src/Web/DevHive.Web/Controllers/RateController.cs
deleted file mode 100644
index 72eb932..0000000
--- a/src/Web/DevHive.Web/Controllers/RateController.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using AutoMapper;
-using DevHive.Services.Interfaces;
-using DevHive.Services.Models.Post.Rating;
-using DevHive.Web.Models.Rating;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Mvc;
-
-namespace DevHive.Web.Controllers
-{
- [ApiController]
- [Route("api/[controller]")]
- public class RateController
- {
- private readonly IRateService _rateService;
- private readonly IUserService _userService;
- private readonly IMapper _mapper;
-
- public RateController(IRateService rateService, IUserService userService, IMapper mapper)
- {
- this._rateService = rateService;
- this._userService = userService;
- this._mapper = mapper;
- }
-
- [HttpPost]
- [Authorize(Roles = "Admin,User")]
- public async Task<IActionResult> RatePost(Guid userId, [FromBody] RatePostWebModel ratePostWebModel, [FromHeader] string authorization)
- {
- RatePostServiceModel ratePostServiceModel = this._mapper.Map<RatePostServiceModel>(ratePostWebModel);
- ratePostServiceModel.UserId = userId;
-
- ReadPostRatingServiceModel readPostRatingServiceModel = await this._rateService.RatePost(ratePostServiceModel);
- ReadPostRatingWebModel readPostRatingWebModel = this._mapper.Map<ReadPostRatingWebModel>(readPostRatingServiceModel);
-
- return new OkObjectResult(readPostRatingWebModel);
- }
- }
-}
diff --git a/src/Web/DevHive.Web/Controllers/RatingController.cs b/src/Web/DevHive.Web/Controllers/RatingController.cs
new file mode 100644
index 0000000..5716b85
--- /dev/null
+++ b/src/Web/DevHive.Web/Controllers/RatingController.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Common.Jwt.Interfaces;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Post.Rating;
+using DevHive.Web.Models.Rating;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DevHive.Web.Controllers
+{
+ [ApiController]
+ //[Authorize(Roles = "Admin,User")]
+ [Route("api/[controller]")]
+ public class RatingController
+ {
+ private readonly IRatingService _rateService;
+ private readonly IUserService _userService;
+ private readonly IMapper _mapper;
+ private readonly IJwtService _jwtService;
+
+ public RatingController(IRatingService rateService, IUserService userService, IMapper mapper, IJwtService jwtService)
+ {
+ this._rateService = rateService;
+ this._userService = userService;
+ this._mapper = mapper;
+ this._jwtService = jwtService;
+ }
+
+ [HttpPost]
+ public async Task<IActionResult> RatePost(Guid userId, [FromBody] CreateRatingWebModel createRatingWebModel, [FromHeader] string authorization)
+ {
+ if (!this._jwtService.ValidateToken(userId, authorization))
+ return new UnauthorizedResult();
+
+ CreateRatingServiceModel ratePostServiceModel = this._mapper.Map<CreateRatingServiceModel>(createRatingWebModel);
+ ratePostServiceModel.UserId = userId;
+
+ Guid id = await this._rateService.RatePost(ratePostServiceModel);
+
+ if (Guid.Empty == id)
+ return new BadRequestResult();
+
+ return new OkObjectResult(new { Id = id });
+ }
+
+ [HttpGet]
+ public async Task<IActionResult> GetRatingById(Guid id)
+ {
+ ReadRatingServiceModel readRatingServiceModel = await this._rateService.GetRatingById(id);
+ ReadRatingWebModel readPostRatingWebModel = this._mapper.Map<ReadRatingWebModel>(readRatingServiceModel);
+
+ return new OkObjectResult(readPostRatingWebModel);
+ }
+
+ [HttpGet]
+ [Route("GetByUserAndPost")]
+ public async Task<IActionResult> GetRatingByUserAndPost(Guid userId, Guid postId)
+ {
+ ReadRatingServiceModel readRatingServiceModel = await this._rateService.GetRatingByPostAndUser(userId, postId);
+ ReadRatingWebModel readPostRatingWebModel = this._mapper.Map<ReadRatingWebModel>(readRatingServiceModel);
+
+ return new OkObjectResult(readPostRatingWebModel);
+ }
+
+ [HttpPut]
+ public async Task<IActionResult> UpdateRating(Guid userId, [FromBody] UpdateRatingWebModel updateRatingWebModel, [FromHeader] string authorization)
+ {
+ if (!this._jwtService.ValidateToken(userId, authorization))
+ return new UnauthorizedResult();
+
+ UpdateRatingServiceModel updateRatingServiceModel =
+ this._mapper.Map<UpdateRatingServiceModel>(updateRatingWebModel);
+ updateRatingServiceModel.UserId = userId;
+
+ ReadRatingServiceModel readRatingServiceModel = await this._rateService.UpdateRating(updateRatingServiceModel);
+
+ if (readRatingServiceModel == null)
+ return new BadRequestResult();
+ else
+ {
+ ReadRatingWebModel readRatingWebModel = this._mapper.Map<ReadRatingWebModel>(readRatingServiceModel);
+ return new OkObjectResult(readRatingWebModel);
+ }
+ }
+
+ [HttpDelete]
+ public async Task<IActionResult> DeleteTating(Guid userId, Guid ratingId, [FromHeader] string authorization)
+ {
+ if (!this._jwtService.ValidateToken(userId, authorization))
+ return new UnauthorizedResult();
+
+ return await this._rateService.DeleteRating(ratingId) ?
+ new OkResult() :
+ new BadRequestObjectResult("Could not delete Rating");
+ }
+ }
+}
diff --git a/src/Web/DevHive.Web/Controllers/RoleController.cs b/src/Web/DevHive.Web/Controllers/RoleController.cs
index 1465795..ebb305e 100644
--- a/src/Web/DevHive.Web/Controllers/RoleController.cs
+++ b/src/Web/DevHive.Web/Controllers/RoleController.cs
@@ -9,6 +9,9 @@ using Microsoft.AspNetCore.Authorization;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the roles layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
public class RoleController
@@ -22,6 +25,11 @@ namespace DevHive.Web.Controllers
this._roleMapper = mapper;
}
+ /// <summary>
+ /// Create a new role for the roles hierarchy. Admin only!
+ /// </summary>
+ /// <param name="createRoleWebModel">The new role's parametars</param>
+ /// <returns>The new role's Id</returns>
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create([FromBody] CreateRoleWebModel createRoleWebModel)
@@ -36,6 +44,11 @@ namespace DevHive.Web.Controllers
new OkObjectResult(new { Id = id });
}
+ /// <summary>
+ /// Get a role's full data, querying it by it's Id
+ /// </summary>
+ /// <param name="id">The role's Id</param>
+ /// <returns>Full info of the role</returns>
[HttpGet]
[Authorize(Roles = "User,Admin")]
public async Task<IActionResult> GetById(Guid id)
@@ -46,6 +59,12 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(roleWebModel);
}
+ /// <summary>
+ /// Update a role's parametars. Admin only!
+ /// </summary>
+ /// <param name="id">The role's Id</param>
+ /// <param name="updateRoleWebModel">The new parametrats for that role</param>
+ /// <returns>Ok result</returns>
[HttpPut]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, [FromBody] UpdateRoleWebModel updateRoleWebModel)
@@ -62,6 +81,11 @@ namespace DevHive.Web.Controllers
return new OkResult();
}
+ /// <summary>
+ /// Delete a role. Admin only!
+ /// </summary>
+ /// <param name="id">The role's Id</param>
+ /// <returns>Ok result</returns>
[HttpDelete]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
diff --git a/src/Web/DevHive.Web/Controllers/TechnologyController.cs b/src/Web/DevHive.Web/Controllers/TechnologyController.cs
index e507899..ecf2bd7 100644
--- a/src/Web/DevHive.Web/Controllers/TechnologyController.cs
+++ b/src/Web/DevHive.Web/Controllers/TechnologyController.cs
@@ -10,6 +10,9 @@ using Microsoft.AspNetCore.Mvc;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for interacting with the technology layer
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
public class TechnologyController
@@ -23,6 +26,11 @@ namespace DevHive.Web.Controllers
this._technologyMapper = technologyMapper;
}
+ /// <summary>
+ /// Create a new technology, so users can have a choice. Admin only!
+ /// </summary>
+ /// <param name="createTechnologyWebModel">Data for the new technology</param>
+ /// <returns>The new technology's Id</returns>
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create([FromBody] CreateTechnologyWebModel createTechnologyWebModel)
@@ -36,6 +44,11 @@ namespace DevHive.Web.Controllers
new OkObjectResult(new { Id = id });
}
+ /// <summary>
+ /// Get technology's data by it's Id
+ /// </summary>
+ /// <param name="id">The technology's Id</param>
+ /// <returns>The technology's full data</returns>
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> GetById(Guid id)
@@ -46,6 +59,10 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(readTechnologyWebModel);
}
+ /// <summary>
+ /// Get all technologies from our database
+ /// </summary>
+ /// <returns>All technologies</returns>
[HttpGet]
[Route("GetTechnologies")]
[Authorize(Roles = "User,Admin")]
@@ -57,6 +74,12 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(languageWebModels);
}
+ /// <summary>
+ /// Alter a technology's parameters. Admin only!
+ /// </summary>
+ /// <param name="id">Technology's Id</param>
+ /// <param name="updateModel">The new parametars</param>
+ /// <returns>Ok result</returns>
[HttpPut]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, [FromBody] UpdateTechnologyWebModel updateModel)
@@ -72,6 +95,11 @@ namespace DevHive.Web.Controllers
return new OkResult();
}
+ /// <summary>
+ /// Delete a etchnology from the database. Admin only!
+ /// </summary>
+ /// <param name="id">The technology's Id</param>
+ /// <returns>Ok result</returns>
[HttpDelete]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
diff --git a/src/Web/DevHive.Web/Controllers/UserController.cs b/src/Web/DevHive.Web/Controllers/UserController.cs
index 214fba7..4d01447 100644
--- a/src/Web/DevHive.Web/Controllers/UserController.cs
+++ b/src/Web/DevHive.Web/Controllers/UserController.cs
@@ -7,26 +7,40 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using DevHive.Common.Models.Identity;
using DevHive.Services.Interfaces;
+using DevHive.Common.Jwt.Interfaces;
+using NSwag.Annotations;
namespace DevHive.Web.Controllers
{
+ /// <summary>
+ /// All endpoints for integration with the User
+ /// </summary>
[ApiController]
[Route("/api/[controller]")]
+ [OpenApiController("User Controller")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
private readonly IMapper _userMapper;
+ private readonly IJwtService _jwtService;
- public UserController(IUserService userService, IMapper mapper)
+ public UserController(IUserService userService, IMapper mapper, IJwtService jwtService)
{
this._userService = userService;
this._userMapper = mapper;
+ this._jwtService = jwtService;
}
#region Authentication
+ /// <summary>
+ /// Login endpoint for the DevHive Social Platform
+ /// </summary>
+ /// <param name="loginModel">Login model with username and password</param>
+ /// <returns>A JWT Token for further validation</returns>
[HttpPost]
- [Route("Login")]
[AllowAnonymous]
+ [Route("Login")]
+ [OpenApiTags("Authorization")]
public async Task<IActionResult> Login([FromBody] LoginWebModel loginModel)
{
LoginServiceModel loginServiceModel = this._userMapper.Map<LoginServiceModel>(loginModel);
@@ -37,9 +51,15 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(tokenWebModel);
}
+ /// <summary>
+ /// Register a new User in the DevHive Social Platform
+ /// </summary>
+ /// <param name="registerModel">Register model with the new data to provide</param>
+ /// <returns>A JWT Token for further validation</returns>
[HttpPost]
- [Route("Register")]
[AllowAnonymous]
+ [Route("Register")]
+ [OpenApiTag("Authorization")]
public async Task<IActionResult> Register([FromBody] RegisterWebModel registerModel)
{
RegisterServiceModel registerServiceModel = this._userMapper.Map<RegisterServiceModel>(registerModel);
@@ -52,11 +72,17 @@ namespace DevHive.Web.Controllers
#endregion
#region Read
+ /// <summary>
+ /// Get a User's information using the Guid
+ /// </summary>
+ /// <param name="id">User's Id</param>
+ /// <param name="authorization">The JWT Token, contained in the header and used for validation</param>
+ /// <returns>A full User's read model</returns>
[HttpGet]
[Authorize(Roles = "User,Admin")]
public async Task<IActionResult> GetById(Guid id, [FromHeader] string authorization)
{
- if (!await this._userService.ValidJWT(id, authorization))
+ if (!this._jwtService.ValidateToken(id, authorization))
return new UnauthorizedResult();
UserServiceModel userServiceModel = await this._userService.GetUserById(id);
@@ -65,6 +91,11 @@ namespace DevHive.Web.Controllers
return new OkObjectResult(userWebModel);
}
+ /// <summary>
+ /// Get a User's profile using his username. Does NOT require authorization
+ /// </summary>
+ /// <param name="username">User's username</param>
+ /// <returns>A trimmed version of the full User's read model</returns>
[HttpGet]
[Route("GetUser")]
[AllowAnonymous]
@@ -78,11 +109,18 @@ namespace DevHive.Web.Controllers
#endregion
#region Update
+ /// <summary>
+ /// Full update on User's data. A PUSTINQK can only edit his account
+ /// </summary>
+ /// <param name="id">The User's Id</param>
+ /// <param name="updateUserWebModel">A full User update model</param>
+ /// <param name="authorization">The JWT Token, contained in the header and used for validation</param>
+ /// <returns>A full User's read model</returns>
[HttpPut]
[Authorize(Roles = "User,Admin")]
public async Task<IActionResult> Update(Guid id, [FromBody] UpdateUserWebModel updateUserWebModel, [FromHeader] string authorization)
{
- if (!await this._userService.ValidJWT(id, authorization))
+ if (!this._jwtService.ValidateToken(id, authorization))
return new UnauthorizedResult();
UpdateUserServiceModel updateUserServiceModel = this._userMapper.Map<UpdateUserServiceModel>(updateUserWebModel);
@@ -93,31 +131,20 @@ namespace DevHive.Web.Controllers
return new AcceptedResult("UpdateUser", userWebModel);
}
-
- [HttpPut]
- [Route("ProfilePicture")]
- [Authorize(Roles = "User,Admin")]
- public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization)
- {
- if (!await this._userService.ValidJWT(userId, authorization))
- return new UnauthorizedResult();
-
- UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map<UpdateProfilePictureServiceModel>(updateProfilePictureWebModel);
- updateProfilePictureServiceModel.UserId = userId;
-
- ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel);
- ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map<ProfilePictureWebModel>(profilePictureServiceModel);
-
- return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel);
- }
#endregion
#region Delete
+ /// <summary>
+ /// Delete a User with his Id. A PUSTINQK can only delete his account. An Admin can delete all accounts
+ /// </summary>
+ /// <param name="id">The User's Id</param>
+ /// <param name="authorization">The JWT Token, contained in the header and used for validation</param>
+ /// <returns>Ok, BadRequest or Unauthorized</returns>
[HttpDelete]
[Authorize(Roles = "User,Admin")]
public async Task<IActionResult> Delete(Guid id, [FromHeader] string authorization)
{
- if (!await this._userService.ValidJWT(id, authorization))
+ if (!this._jwtService.ValidateToken(id, authorization))
return new UnauthorizedResult();
bool result = await this._userService.DeleteUser(id);
@@ -128,7 +155,13 @@ namespace DevHive.Web.Controllers
}
#endregion
+ /// <summary>
+ /// We don't talk about that, NIGGA!
+ /// </summary>
+ /// <param name="userId"></param>
+ /// <returns></returns>
[HttpPost]
+ [OpenApiIgnore]
[Authorize(Roles = "User,Admin")]
[Route("SuperSecretPromotionToAdmin")]
public async Task<IActionResult> SuperSecretPromotionToAdmin(Guid userId)
diff --git a/src/Web/DevHive.Web/DevHive.Web.csproj b/src/Web/DevHive.Web/DevHive.Web.csproj
index 6511c37..39322ae 100644
--- a/src/Web/DevHive.Web/DevHive.Web.csproj
+++ b/src/Web/DevHive.Web/DevHive.Web.csproj
@@ -5,6 +5,8 @@
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest</AnalysisLevel>
+ <GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <AllowUntrustedCertificate>true</AllowUntrustedCertificate>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.3" NoWarn="NU1605"/>
@@ -14,15 +16,23 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/>
- <PackageReference Include="Swashbuckle.AspNetCore" Version="6.0.5"/>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/>
<PackageReference Include="AutoMapper" Version="10.1.1"/>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
+ <PackageReference Include="NSwag.AspNetCore" Version="13.10.7"/>
+ <PackageReference Include="NSwag.Generation.AspNetCore" Version="13.10.7"/>
+ <PackageReference Include="NSwag.Annotations" Version="13.10.7"/>
+ <PackageReference Include="NSwag.Core" Version="13.10.7"/>
+ <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.1.0"/>
+ <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.1.0"/>
+ <PackageReference Include="NSwag.SwaggerGeneration.WebApi" Version="12.3.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DevHive.Web.Models\DevHive.Web.Models.csproj"/>
<ProjectReference Include="..\..\Services\DevHive.Services\DevHive.Services.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/Web/DevHive.Web/Startup.cs b/src/Web/DevHive.Web/Startup.cs
index dbcf131..ebd091e 100644
--- a/src/Web/DevHive.Web/Startup.cs
+++ b/src/Web/DevHive.Web/Startup.cs
@@ -29,11 +29,11 @@ namespace DevHive.Web
x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
+ services.DependencyInjectionConfiguration(this.Configuration);
services.DatabaseConfiguration(Configuration);
services.SwaggerConfiguration();
services.JWTConfiguration(Configuration);
services.AutoMapperConfiguration();
- services.DependencyInjectionConfiguration(this.Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -48,7 +48,6 @@ namespace DevHive.Web
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
- app.UseSwaggerConfiguration();
}
else
{
@@ -56,6 +55,7 @@ namespace DevHive.Web
app.UseExceptionHandlerMiddlewareConfiguration();
}
+ app.UseSwaggerConfiguration();
app.UseDatabaseConfiguration();
app.UseAutoMapperConfiguration();
diff --git a/src/Web/DevHive.Web/appsettings.json b/src/Web/DevHive.Web/appsettings.json
index bcdcae7..fcf9805 100644
--- a/src/Web/DevHive.Web/appsettings.json
+++ b/src/Web/DevHive.Web/appsettings.json
@@ -1,20 +1,22 @@
{
- "AppSettings": {
- "Secret": "gXfQlU6qpDleFWyimscjYcT3tgFsQg3yoFjcvSLxG56n1Vu2yptdIUq254wlJWjm"
- },
- "ConnectionStrings": {
- "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=;"
+ "Jwt": {
+ "signingKey": "",
+ "validationIssuer": "",
+ "audience": ""
+ },
+ "ConnectionStrings": {
+ "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=;"
},
"Cloud": {
"cloudName": "devhive",
"apiKey": "488664116365813",
"apiSecret": ""
},
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
- }
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
}