From f43b9134f161b0b21390fef2dc33b3c37d9e3476 Mon Sep 17 00:00:00 2001 From: TheHunteR Date: Sat, 10 Dec 2022 22:24:18 +0200 Subject: [PATCH 1/8] Created Articles --- GdscBackend/Controllers/v1/AuthController.cs | 2 + GdscBackend/Database/AppDbContext.cs | 2 + .../Features/Articles/ArticleController.cs | 73 ++ GdscBackend/Features/Articles/ArticleModel.cs | 13 + .../Features/Articles/ArticleRequest.cs | 12 + .../Features/Articles/ArticleResponse.cs | 14 + .../20221210192538_articles.Designer.cs | 663 +++++++++++++++++ .../Migrations/20221210192538_articles.cs | 22 + ...20221210193205_ArticlesForReal.Designer.cs | 701 ++++++++++++++++++ .../20221210193205_ArticlesForReal.cs | 48 ++ .../Migrations/AppDbContextModelSnapshot.cs | 40 +- 11 files changed, 1589 insertions(+), 1 deletion(-) create mode 100644 GdscBackend/Features/Articles/ArticleController.cs create mode 100644 GdscBackend/Features/Articles/ArticleModel.cs create mode 100644 GdscBackend/Features/Articles/ArticleRequest.cs create mode 100644 GdscBackend/Features/Articles/ArticleResponse.cs create mode 100644 GdscBackend/Migrations/20221210192538_articles.Designer.cs create mode 100644 GdscBackend/Migrations/20221210192538_articles.cs create mode 100644 GdscBackend/Migrations/20221210193205_ArticlesForReal.Designer.cs create mode 100644 GdscBackend/Migrations/20221210193205_ArticlesForReal.cs diff --git a/GdscBackend/Controllers/v1/AuthController.cs b/GdscBackend/Controllers/v1/AuthController.cs index ee81a84..bcb7d93 100644 --- a/GdscBackend/Controllers/v1/AuthController.cs +++ b/GdscBackend/Controllers/v1/AuthController.cs @@ -65,6 +65,8 @@ public async Task> Login(LoginViewModel model) [HttpPost] [Route("register")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> Register(RegisterViewModel model) { var rolesDoesNotExist = !await _roleManager.RoleExistsAsync("admin"); diff --git a/GdscBackend/Database/AppDbContext.cs b/GdscBackend/Database/AppDbContext.cs index 90e5173..e2d0a97 100644 --- a/GdscBackend/Database/AppDbContext.cs +++ b/GdscBackend/Database/AppDbContext.cs @@ -1,4 +1,5 @@ using GdscBackend.Auth; +using GdscBackend.Features.Articles; using GdscBackend.Features.Redirects; using GdscBackend.Models; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; @@ -30,4 +31,5 @@ protected override void OnModelCreating(ModelBuilder builder) public DbSet Technologies { get; set; } public DbSet Files { get; set; } public DbSet Redirects { get; set; } + public DbSet Articles { get; set; } } \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleController.cs b/GdscBackend/Features/Articles/ArticleController.cs new file mode 100644 index 0000000..aac62a4 --- /dev/null +++ b/GdscBackend/Features/Articles/ArticleController.cs @@ -0,0 +1,73 @@ +using GdscBackend.Auth; +using GdscBackend.Database; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace GdscBackend.Features.Articles; + +[ApiController] +[ApiVersion("1")] +[Authorize(Roles = "admin")] +[Route("v1/Articles")] + +public class ArticleController : ControllerBase +{ + private readonly AppDbContext _dbContext; + + public ArticleController(AppDbContext appDbContext) + { + _dbContext = appDbContext; + } + + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> Post(ArticleRequest request) + { + var author = await _dbContext.Users.FirstOrDefaultAsync(entity => entity.Id == request.AuthorId); + if (author is null) + { + return NotFound("User not found!"); + } + + var article = new ArticleModel + { + Id = Guid.NewGuid().ToString(), + Created = DateTime.UtcNow, + Updated = DateTime.UtcNow, + Title = request.Title, + Content = request.Content, + Author = author + }; + + var result = await _dbContext.Articles.AddAsync(article); + await _dbContext.SaveChangesAsync(); + + return Created("v1/Articles", result); + } + + [HttpGet] + [AllowAnonymous] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task>> Get() + { + var result = _dbContext.Articles.Include(a => a.Author).Select( + article => new ArticleResponse + { + Created = article.Created, + Title = article.Title, + Content = article.Content, + Author = new UserViewModel + { + Id = article.Author.Id, + UserName = article.Author.UserName, + Email = article.Author.Email + } + }).ToList(); + + return Ok(result); + } +} \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleModel.cs b/GdscBackend/Features/Articles/ArticleModel.cs new file mode 100644 index 0000000..92c7552 --- /dev/null +++ b/GdscBackend/Features/Articles/ArticleModel.cs @@ -0,0 +1,13 @@ +using GdscBackend.Auth; +using GdscBackend.Models; + +namespace GdscBackend.Features.Articles; + +public class ArticleModel : Model +{ + public string Title { get; set; } + + public string Content { get; set; } + + public User? Author { get; set; } +} \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleRequest.cs b/GdscBackend/Features/Articles/ArticleRequest.cs new file mode 100644 index 0000000..bb14bfb --- /dev/null +++ b/GdscBackend/Features/Articles/ArticleRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace GdscBackend.Features.Articles; + +public class ArticleRequest +{ + [Required]public string Title { get; set; } + + public string Content { get; set; } + + [Required]public string AuthorId { get; set; } +} \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleResponse.cs b/GdscBackend/Features/Articles/ArticleResponse.cs new file mode 100644 index 0000000..9439783 --- /dev/null +++ b/GdscBackend/Features/Articles/ArticleResponse.cs @@ -0,0 +1,14 @@ +using GdscBackend.Auth; + +namespace GdscBackend.Features.Articles; + +public class ArticleResponse +{ + public DateTime Created { get; set; } + + public string Title { get; set; } + + public string Content { get; set; } + + public UserViewModel Author { get; set; } +} \ No newline at end of file diff --git a/GdscBackend/Migrations/20221210192538_articles.Designer.cs b/GdscBackend/Migrations/20221210192538_articles.Designer.cs new file mode 100644 index 0000000..cd5b4d9 --- /dev/null +++ b/GdscBackend/Migrations/20221210192538_articles.Designer.cs @@ -0,0 +1,663 @@ +// +using System; +using GdscBackend.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20221210192538_articles")] + partial class articles + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("GdscBackend.Auth.Role", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Auth.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("RedirectTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("Redirects"); + }); + + modelBuilder.Entity("GdscBackend.Models.ContactModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("GdscBackend.Models.EventModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("End") + .HasColumnType("timestamp with time zone"); + + b.Property("ImageId") + .HasColumnType("text"); + + b.Property("Start") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("GdscBackend.Models.ExampleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Examples"); + }); + + modelBuilder.Entity("GdscBackend.Models.FaqModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Question") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Faqs"); + }); + + modelBuilder.Entity("GdscBackend.Models.FileModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Extension") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("GdscBackend.Models.MemberModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Members"); + }); + + modelBuilder.Entity("GdscBackend.Models.MenuItemModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MenuItems"); + }); + + modelBuilder.Entity("GdscBackend.Models.PageModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("isPublished") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Pages"); + }); + + modelBuilder.Entity("GdscBackend.Models.SettingModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("GdscBackend.Models.TeamModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("GdscBackend.Models.TechnologyModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Icon") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.Property("MembersId") + .HasColumnType("text"); + + b.Property("TeamsId") + .HasColumnType("text"); + + b.HasKey("MembersId", "TeamsId"); + + b.HasIndex("TeamsId"); + + b.ToTable("MemberModelTeamModel"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Models.EventModel", b => + { + b.HasOne("GdscBackend.Models.FileModel", "Image") + .WithMany() + .HasForeignKey("ImageId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.HasOne("GdscBackend.Models.MemberModel", null) + .WithMany() + .HasForeignKey("MembersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GdscBackend.Models.TeamModel", null) + .WithMany() + .HasForeignKey("TeamsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("GdscBackend.Auth.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("GdscBackend.Auth.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GdscBackend/Migrations/20221210192538_articles.cs b/GdscBackend/Migrations/20221210192538_articles.cs new file mode 100644 index 0000000..92e23de --- /dev/null +++ b/GdscBackend/Migrations/20221210192538_articles.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + /// + public partial class articles : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/GdscBackend/Migrations/20221210193205_ArticlesForReal.Designer.cs b/GdscBackend/Migrations/20221210193205_ArticlesForReal.Designer.cs new file mode 100644 index 0000000..344a82d --- /dev/null +++ b/GdscBackend/Migrations/20221210193205_ArticlesForReal.Designer.cs @@ -0,0 +1,701 @@ +// +using System; +using GdscBackend.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20221210193205_ArticlesForReal")] + partial class ArticlesForReal + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("GdscBackend.Auth.Role", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Auth.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AuthorId") + .HasColumnType("text"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("RedirectTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("Redirects"); + }); + + modelBuilder.Entity("GdscBackend.Models.ContactModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("GdscBackend.Models.EventModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("End") + .HasColumnType("timestamp with time zone"); + + b.Property("ImageId") + .HasColumnType("text"); + + b.Property("Start") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("GdscBackend.Models.ExampleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Examples"); + }); + + modelBuilder.Entity("GdscBackend.Models.FaqModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Question") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Faqs"); + }); + + modelBuilder.Entity("GdscBackend.Models.FileModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Extension") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("GdscBackend.Models.MemberModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Members"); + }); + + modelBuilder.Entity("GdscBackend.Models.MenuItemModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MenuItems"); + }); + + modelBuilder.Entity("GdscBackend.Models.PageModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("isPublished") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Pages"); + }); + + modelBuilder.Entity("GdscBackend.Models.SettingModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("GdscBackend.Models.TeamModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("GdscBackend.Models.TechnologyModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Icon") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.Property("MembersId") + .HasColumnType("text"); + + b.Property("TeamsId") + .HasColumnType("text"); + + b.HasKey("MembersId", "TeamsId"); + + b.HasIndex("TeamsId"); + + b.ToTable("MemberModelTeamModel"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => + { + b.HasOne("GdscBackend.Auth.User", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("GdscBackend.Models.EventModel", b => + { + b.HasOne("GdscBackend.Models.FileModel", "Image") + .WithMany() + .HasForeignKey("ImageId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.HasOne("GdscBackend.Models.MemberModel", null) + .WithMany() + .HasForeignKey("MembersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GdscBackend.Models.TeamModel", null) + .WithMany() + .HasForeignKey("TeamsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("GdscBackend.Auth.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("GdscBackend.Auth.Role", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("GdscBackend.Auth.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GdscBackend/Migrations/20221210193205_ArticlesForReal.cs b/GdscBackend/Migrations/20221210193205_ArticlesForReal.cs new file mode 100644 index 0000000..c592d10 --- /dev/null +++ b/GdscBackend/Migrations/20221210193205_ArticlesForReal.cs @@ -0,0 +1,48 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + /// + public partial class ArticlesForReal : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Articles", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + Title = table.Column(type: "text", nullable: false), + Content = table.Column(type: "text", nullable: false), + AuthorId = table.Column(type: "text", nullable: true), + Created = table.Column(type: "timestamp with time zone", nullable: false), + Updated = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Articles", x => x.Id); + table.ForeignKey( + name: "FK_Articles_AspNetUsers_AuthorId", + column: x => x.AuthorId, + principalTable: "AspNetUsers", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Articles_AuthorId", + table: "Articles", + column: "AuthorId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Articles"); + } + } +} diff --git a/GdscBackend/Migrations/AppDbContextModelSnapshot.cs b/GdscBackend/Migrations/AppDbContextModelSnapshot.cs index 4d1f0f6..c5266d5 100644 --- a/GdscBackend/Migrations/AppDbContextModelSnapshot.cs +++ b/GdscBackend/Migrations/AppDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.10") + .HasAnnotation("ProductVersion", "7.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -112,6 +112,35 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetUsers", (string)null); }); + modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AuthorId") + .HasColumnType("text"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.ToTable("Articles"); + }); + modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => { b.Property("Id") @@ -580,6 +609,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AspNetUserTokens", (string)null); }); + modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => + { + b.HasOne("GdscBackend.Auth.User", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.Navigation("Author"); + }); + modelBuilder.Entity("GdscBackend.Models.EventModel", b => { b.HasOne("GdscBackend.Models.FileModel", "Image") From 1dda672b80167e8aa11e523f8b1e3a230aa753dc Mon Sep 17 00:00:00 2001 From: Vali Date: Sat, 10 Dec 2022 23:38:04 +0200 Subject: [PATCH 2/8] Article: Added Delete and Update methods --- .../Features/Articles/ArticleController.cs | 121 +++++++++++++++++- .../Features/Articles/ArticleResponse.cs | 1 + 2 files changed, 121 insertions(+), 1 deletion(-) diff --git a/GdscBackend/Features/Articles/ArticleController.cs b/GdscBackend/Features/Articles/ArticleController.cs index aac62a4..edf1f13 100644 --- a/GdscBackend/Features/Articles/ArticleController.cs +++ b/GdscBackend/Features/Articles/ArticleController.cs @@ -1,6 +1,7 @@ using GdscBackend.Auth; using GdscBackend.Database; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -45,7 +46,7 @@ public async Task> Post(ArticleRequest request) var result = await _dbContext.Articles.AddAsync(article); await _dbContext.SaveChangesAsync(); - return Created("v1/Articles", result); + return Created("v1/Articles", result.Entity); } [HttpGet] @@ -57,6 +58,7 @@ public async Task>> Get() var result = _dbContext.Articles.Include(a => a.Author).Select( article => new ArticleResponse { + Id = article.Id, Created = article.Created, Title = article.Title, Content = article.Content, @@ -70,4 +72,121 @@ public async Task>> Get() return Ok(result); } + + [HttpDelete("{id}")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> Delete([FromRoute] string id) + { + var articol = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); + if (articol is null) + { + return NotFound("Article not found!"); + } + + var result = _dbContext.Articles.Remove(articol); + await _dbContext.SaveChangesAsync(); + return Ok(result.Entity); + } + + [HttpPatch("Change author/{id}")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> ChangeAuthor([FromRoute] string id, [FromBody] string authorid) + { + var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) + { + return NotFound("Article not found!"); + } + + var author = await _dbContext.Users.FirstOrDefaultAsync(entity => entity.Id == authorid); + if (author is null) + { + return NotFound("Author not found!"); + } + + article.Author = author; + article.Updated = DateTime.UtcNow; + await _dbContext.SaveChangesAsync(); + return Ok(new ArticleResponse + { + Id = article.Id, + Created = article.Created, + Title = article.Title, + Content = article.Content, + Author = new UserViewModel + { + Id = article.Author.Id, + UserName = article.Author.UserName, + Email = article.Author.Email + } + }); + } + + [HttpPatch("Change content/{id}")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> ChangeContent([FromRoute] string id, [FromBody] string content) + { + var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) + { + return NotFound("Article not found!"); + } + + article.Content = content; + article.Updated = DateTime.UtcNow; + await _dbContext.SaveChangesAsync(); + return Ok(new ArticleResponse + { + Id = article.Id, + Created = article.Created, + Title = article.Title, + Content = article.Content, + Author = new UserViewModel + { + Id = article.Author.Id, + UserName = article.Author.UserName, + Email = article.Author.Email + } + }); + } + + [HttpPatch("Change title/{id}")] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + public async Task> ChangeTitle([FromRoute] string id, [FromBody] string title) + { + var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) + { + return NotFound("Article not found!"); + } + + article.Title = title; + article.Updated = DateTime.UtcNow; + await _dbContext.SaveChangesAsync(); + return Ok(new ArticleResponse + { + Id = article.Id, + Created = article.Created, + Title = article.Title, + Content = article.Content, + Author = new UserViewModel + { + Id = article.Author.Id, + UserName = article.Author.UserName, + Email = article.Author.Email + } + }); + } } \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleResponse.cs b/GdscBackend/Features/Articles/ArticleResponse.cs index 9439783..ae54769 100644 --- a/GdscBackend/Features/Articles/ArticleResponse.cs +++ b/GdscBackend/Features/Articles/ArticleResponse.cs @@ -4,6 +4,7 @@ namespace GdscBackend.Features.Articles; public class ArticleResponse { + public string Id { get; set; } public DateTime Created { get; set; } public string Title { get; set; } From 7a94aa6a24f690d39e7717be07040d1b9956a4f8 Mon Sep 17 00:00:00 2001 From: Vali Date: Sat, 10 Dec 2022 23:57:13 +0200 Subject: [PATCH 3/8] Adjusted Namespaces --- GdscBackend.Tests/AuthTests.cs | 1 - GdscBackend.Tests/ContactControllerTests.cs | 4 +--- GdscBackend.Tests/EventsControllerTests.cs | 5 ++--- GdscBackend.Tests/ExampleTests.cs | 4 +--- GdscBackend.Tests/FilesControllerTests.cs | 3 +-- GdscBackend.Tests/MembersControllerTests.cs | 4 +--- GdscBackend.Tests/MenuItemsControllerTests.cs | 5 +---- GdscBackend.Tests/Mocks/TestDbContext.cs | 2 +- GdscBackend.Tests/Mocks/TestWebhookService.cs | 2 +- GdscBackend.Tests/SettingsControllerTests.cs | 5 +---- GdscBackend.Tests/TeamsControllerTests.cs | 5 ++--- GdscBackend.Tests/TechnologiesControllerTests.cs | 4 +--- .../{Controllers/v1 => Auth}/AuthController.cs | 3 +-- .../{Controllers/v1 => Auth}/UserController.cs | 3 +-- GdscBackend/{ => Common}/Models/IModel.cs | 2 +- GdscBackend/{ => Common}/Models/Model.cs | 2 +- GdscBackend/Common/RequestModels/Request.cs | 5 +++++ GdscBackend/Database/AppDbContext.cs | 12 +++++++++++- GdscBackend/Database/IRepository.cs | 2 +- GdscBackend/Database/Repository.cs | 2 +- GdscBackend/Features/Articles/ArticleModel.cs | 2 +- .../v1 => Features/Contacts}/ContactController.cs | 4 +--- .../{Models => Features/Contacts}/ContactModel.cs | 4 +++- .../Contacts}/ContactRequest.cs | 4 +++- .../{Models => Features/Events}/EventModel.cs | 5 ++++- .../Events}/EventRequest.cs | 4 +++- .../v1 => Features/Events}/EventsController.cs | 5 ++--- .../{Models => Features/Examples}/ExampleModel.cs | 4 ++-- .../Enums => Features/Examples}/ExampleTypeEnum.cs | 2 +- .../v1 => Features/Examples}/ExamplesController.cs | 3 +-- GdscBackend/{Models => Features/FIles}/FileModel.cs | 4 +++- .../v1 => Features/FIles}/FilesController.cs | 3 +-- GdscBackend/{Models => Features/Faqs}/FaqModel.cs | 4 +++- .../{RequestModels => Features/Faqs}/FaqRequest.cs | 4 +++- .../v1 => Features/Faqs}/FaqsController.cs | 4 +--- .../{Models => Features/Members}/MemberModel.cs | 5 ++++- .../Members}/MemberRequest.cs | 4 +++- .../v1 => Features/Members}/MembersController.cs | 4 +--- .../{Models => Features/MenuItems}/MenuItemModel.cs | 4 ++-- .../MenuItems}/MenuItemRequest.cs | 4 ++-- .../Enums => Features/MenuItems}/MenuItemTypeEnum.cs | 2 +- .../v1 => Features/MenuItems}/MenuItemsController.cs | 4 +--- GdscBackend/{Models => Features/Pages}/PageModel.cs | 4 +++- .../{RequestModels => Features/Pages}/PageRequest.cs | 4 +++- .../v1 => Features/Pages}/PagesController.cs | 4 +--- GdscBackend/Features/Redirects/RedirectModel.cs | 2 +- GdscBackend/Features/Redirects/RedirectRequest.cs | 4 +++- .../Features/Redirects/RedirectsController.cs | 1 - .../{Models => Features/Settings}/SettingModel.cs | 4 ++-- .../Settings}/SettingRequest.cs | 4 ++-- .../Enums => Features/Settings}/SettingTypeEnum.cs | 2 +- .../v1 => Features/Settings}/SettingsController.cs | 4 +--- GdscBackend/{Models => Features/Teams}/TeamModel.cs | 5 ++++- GdscBackend/Features/Teams/TeamRequest.cs | 8 ++++++++ .../v1 => Features/Teams}/TeamsController.cs | 4 +--- .../Technologies}/TechnologiesController.cs | 4 +--- .../Technologies}/TechnologyModel.cs | 4 +++- .../Technologies}/TechnologyRequest.cs | 4 +++- GdscBackend/GdscBackend.csproj | 4 ++++ GdscBackend/RequestModels/Request.cs | 5 ----- GdscBackend/RequestModels/TeamRequest.cs | 6 ------ GdscBackend/Utils/Mappers/MappingProfiles.cs | 11 +++++++++-- GdscBackend/Utils/Services/IWebhookService.cs | 2 +- GdscBackend/Utils/Services/WebhookService.cs | 2 +- 64 files changed, 133 insertions(+), 117 deletions(-) rename GdscBackend/{Controllers/v1 => Auth}/AuthController.cs (98%) rename GdscBackend/{Controllers/v1 => Auth}/UserController.cs (97%) rename GdscBackend/{ => Common}/Models/IModel.cs (77%) rename GdscBackend/{ => Common}/Models/Model.cs (81%) create mode 100644 GdscBackend/Common/RequestModels/Request.cs rename GdscBackend/{Controllers/v1 => Features/Contacts}/ContactController.cs (96%) rename GdscBackend/{Models => Features/Contacts}/ContactModel.cs (71%) rename GdscBackend/{RequestModels => Features/Contacts}/ContactRequest.cs (70%) rename GdscBackend/{Models => Features/Events}/EventModel.cs (68%) rename GdscBackend/{RequestModels => Features/Events}/EventRequest.cs (75%) rename GdscBackend/{Controllers/v1 => Features/Events}/EventsController.cs (96%) rename GdscBackend/{Models => Features/Examples}/ExampleModel.cs (80%) rename GdscBackend/{Models/Enums => Features/Examples}/ExampleTypeEnum.cs (67%) rename GdscBackend/{Controllers/v1 => Features/Examples}/ExamplesController.cs (97%) rename GdscBackend/{Models => Features/FIles}/FileModel.cs (71%) rename GdscBackend/{Controllers/v1 => Features/FIles}/FilesController.cs (96%) rename GdscBackend/{Models => Features/Faqs}/FaqModel.cs (60%) rename GdscBackend/{RequestModels => Features/Faqs}/FaqRequest.cs (60%) rename GdscBackend/{Controllers/v1 => Features/Faqs}/FaqsController.cs (96%) rename GdscBackend/{Models => Features/Members}/MemberModel.cs (60%) rename GdscBackend/{RequestModels => Features/Members}/MemberRequest.cs (66%) rename GdscBackend/{Controllers/v1 => Features/Members}/MembersController.cs (96%) rename GdscBackend/{Models => Features/MenuItems}/MenuItemModel.cs (68%) rename GdscBackend/{RequestModels => Features/MenuItems}/MenuItemRequest.cs (66%) rename GdscBackend/{Models/Enums => Features/MenuItems}/MenuItemTypeEnum.cs (80%) rename GdscBackend/{Controllers/v1 => Features/MenuItems}/MenuItemsController.cs (96%) rename GdscBackend/{Models => Features/Pages}/PageModel.cs (78%) rename GdscBackend/{RequestModels => Features/Pages}/PageRequest.cs (77%) rename GdscBackend/{Controllers/v1 => Features/Pages}/PagesController.cs (96%) rename GdscBackend/{Models => Features/Settings}/SettingModel.cs (75%) rename GdscBackend/{RequestModels => Features/Settings}/SettingRequest.cs (74%) rename GdscBackend/{Models/Enums => Features/Settings}/SettingTypeEnum.cs (59%) rename GdscBackend/{Controllers/v1 => Features/Settings}/SettingsController.cs (97%) rename GdscBackend/{Models => Features/Teams}/TeamModel.cs (53%) create mode 100644 GdscBackend/Features/Teams/TeamRequest.cs rename GdscBackend/{Controllers/v1 => Features/Teams}/TeamsController.cs (96%) rename GdscBackend/{Controllers/v1 => Features/Technologies}/TechnologiesController.cs (95%) rename GdscBackend/{Models => Features/Technologies}/TechnologyModel.cs (65%) rename GdscBackend/{RequestModels => Features/Technologies}/TechnologyRequest.cs (65%) delete mode 100644 GdscBackend/RequestModels/Request.cs delete mode 100644 GdscBackend/RequestModels/TeamRequest.cs diff --git a/GdscBackend.Tests/AuthTests.cs b/GdscBackend.Tests/AuthTests.cs index 6c4ee0a..670296e 100644 --- a/GdscBackend.Tests/AuthTests.cs +++ b/GdscBackend.Tests/AuthTests.cs @@ -1,6 +1,5 @@ using System.Text; using GdscBackend.Auth; -using GdscBackend.Controllers.v1; using GdscBackend.Database; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; diff --git a/GdscBackend.Tests/ContactControllerTests.cs b/GdscBackend.Tests/ContactControllerTests.cs index 7d462a4..dcab576 100644 --- a/GdscBackend.Tests/ContactControllerTests.cs +++ b/GdscBackend.Tests/ContactControllerTests.cs @@ -3,10 +3,8 @@ using System.Linq; using AutoMapper; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Contacts; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using GdscBackend.Utils.Services; diff --git a/GdscBackend.Tests/EventsControllerTests.cs b/GdscBackend.Tests/EventsControllerTests.cs index 9b34cd7..7b4169b 100644 --- a/GdscBackend.Tests/EventsControllerTests.cs +++ b/GdscBackend.Tests/EventsControllerTests.cs @@ -3,10 +3,9 @@ using System.Linq; using AutoMapper; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Events; +using GdscBackend.Features.FIles; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend.Tests/ExampleTests.cs b/GdscBackend.Tests/ExampleTests.cs index 96ecfa0..4fb9acb 100644 --- a/GdscBackend.Tests/ExampleTests.cs +++ b/GdscBackend.Tests/ExampleTests.cs @@ -2,10 +2,8 @@ using System.Linq; using FactoryBot; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.Models.Enums; +using GdscBackend.Features.Examples; using GdscBackend.Tests.Mocks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/GdscBackend.Tests/FilesControllerTests.cs b/GdscBackend.Tests/FilesControllerTests.cs index 285781e..6ca8884 100644 --- a/GdscBackend.Tests/FilesControllerTests.cs +++ b/GdscBackend.Tests/FilesControllerTests.cs @@ -2,9 +2,8 @@ using System.IO; using System.Linq; using System.Text; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; +using GdscBackend.Features.FIles; using GdscBackend.Tests.Mocks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/GdscBackend.Tests/MembersControllerTests.cs b/GdscBackend.Tests/MembersControllerTests.cs index 77cce02..49c75bc 100644 --- a/GdscBackend.Tests/MembersControllerTests.cs +++ b/GdscBackend.Tests/MembersControllerTests.cs @@ -3,10 +3,8 @@ using AutoMapper; using FactoryBot; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Members; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend.Tests/MenuItemsControllerTests.cs b/GdscBackend.Tests/MenuItemsControllerTests.cs index 51ba158..9ecc0c8 100644 --- a/GdscBackend.Tests/MenuItemsControllerTests.cs +++ b/GdscBackend.Tests/MenuItemsControllerTests.cs @@ -3,11 +3,8 @@ using AutoMapper; using FactoryBot; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.Models.Enums; -using GdscBackend.RequestModels; +using GdscBackend.Features.MenuItems; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend.Tests/Mocks/TestDbContext.cs b/GdscBackend.Tests/Mocks/TestDbContext.cs index 1d89ad4..cd432c1 100644 --- a/GdscBackend.Tests/Mocks/TestDbContext.cs +++ b/GdscBackend.Tests/Mocks/TestDbContext.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; +using GdscBackend.Common.Models; using GdscBackend.Database; -using GdscBackend.Models; using Microsoft.EntityFrameworkCore; namespace GdscBackend.Tests.Mocks; diff --git a/GdscBackend.Tests/Mocks/TestWebhookService.cs b/GdscBackend.Tests/Mocks/TestWebhookService.cs index 5c3ec78..6624986 100644 --- a/GdscBackend.Tests/Mocks/TestWebhookService.cs +++ b/GdscBackend.Tests/Mocks/TestWebhookService.cs @@ -1,4 +1,4 @@ -using GdscBackend.Models; +using GdscBackend.Features.Contacts; using GdscBackend.Utils.Services; using Xunit.Abstractions; diff --git a/GdscBackend.Tests/SettingsControllerTests.cs b/GdscBackend.Tests/SettingsControllerTests.cs index 7f9c6d6..cbe1f23 100644 --- a/GdscBackend.Tests/SettingsControllerTests.cs +++ b/GdscBackend.Tests/SettingsControllerTests.cs @@ -3,11 +3,8 @@ using AutoMapper; using FactoryBot; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.Models.Enums; -using GdscBackend.RequestModels; +using GdscBackend.Features.Settings; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend.Tests/TeamsControllerTests.cs b/GdscBackend.Tests/TeamsControllerTests.cs index 63d6225..c9a2e16 100644 --- a/GdscBackend.Tests/TeamsControllerTests.cs +++ b/GdscBackend.Tests/TeamsControllerTests.cs @@ -4,10 +4,9 @@ using AutoMapper; using FactoryBot; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Members; +using GdscBackend.Features.Teams; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend.Tests/TechnologiesControllerTests.cs b/GdscBackend.Tests/TechnologiesControllerTests.cs index 9fc4cb1..1f82f48 100644 --- a/GdscBackend.Tests/TechnologiesControllerTests.cs +++ b/GdscBackend.Tests/TechnologiesControllerTests.cs @@ -3,10 +3,8 @@ using System.Linq; using AutoMapper; using Faker; -using GdscBackend.Controllers.v1; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Technologies; using GdscBackend.Tests.Mocks; using GdscBackend.Utils.Mappers; using Microsoft.AspNetCore.Http; diff --git a/GdscBackend/Controllers/v1/AuthController.cs b/GdscBackend/Auth/AuthController.cs similarity index 98% rename from GdscBackend/Controllers/v1/AuthController.cs rename to GdscBackend/Auth/AuthController.cs index bcb7d93..665a34c 100644 --- a/GdscBackend/Controllers/v1/AuthController.cs +++ b/GdscBackend/Auth/AuthController.cs @@ -1,12 +1,11 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; -using GdscBackend.Auth; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Auth; [ApiController] [Route("v1/auth")] diff --git a/GdscBackend/Controllers/v1/UserController.cs b/GdscBackend/Auth/UserController.cs similarity index 97% rename from GdscBackend/Controllers/v1/UserController.cs rename to GdscBackend/Auth/UserController.cs index c43004c..5e9bbcf 100644 --- a/GdscBackend/Controllers/v1/UserController.cs +++ b/GdscBackend/Auth/UserController.cs @@ -1,10 +1,9 @@ using System.Net.Mime; -using GdscBackend.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Auth; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/IModel.cs b/GdscBackend/Common/Models/IModel.cs similarity index 77% rename from GdscBackend/Models/IModel.cs rename to GdscBackend/Common/Models/IModel.cs index 123428c..807626d 100644 --- a/GdscBackend/Models/IModel.cs +++ b/GdscBackend/Common/Models/IModel.cs @@ -1,4 +1,4 @@ -namespace GdscBackend.Models; +namespace GdscBackend.Common.Models; public interface IModel { diff --git a/GdscBackend/Models/Model.cs b/GdscBackend/Common/Models/Model.cs similarity index 81% rename from GdscBackend/Models/Model.cs rename to GdscBackend/Common/Models/Model.cs index 85a7870..d69ff7c 100644 --- a/GdscBackend/Models/Model.cs +++ b/GdscBackend/Common/Models/Model.cs @@ -1,4 +1,4 @@ -namespace GdscBackend.Models; +namespace GdscBackend.Common.Models; public abstract class Model : IModel { diff --git a/GdscBackend/Common/RequestModels/Request.cs b/GdscBackend/Common/RequestModels/Request.cs new file mode 100644 index 0000000..6377592 --- /dev/null +++ b/GdscBackend/Common/RequestModels/Request.cs @@ -0,0 +1,5 @@ +namespace GdscBackend.Common.RequestModels; + +public class Request +{ +} \ No newline at end of file diff --git a/GdscBackend/Database/AppDbContext.cs b/GdscBackend/Database/AppDbContext.cs index e2d0a97..deceaf2 100644 --- a/GdscBackend/Database/AppDbContext.cs +++ b/GdscBackend/Database/AppDbContext.cs @@ -1,7 +1,17 @@ using GdscBackend.Auth; using GdscBackend.Features.Articles; +using GdscBackend.Features.Contacts; +using GdscBackend.Features.Events; +using GdscBackend.Features.Examples; +using GdscBackend.Features.Faqs; +using GdscBackend.Features.FIles; +using GdscBackend.Features.Members; +using GdscBackend.Features.MenuItems; +using GdscBackend.Features.Pages; using GdscBackend.Features.Redirects; -using GdscBackend.Models; +using GdscBackend.Features.Settings; +using GdscBackend.Features.Teams; +using GdscBackend.Features.Technologies; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; diff --git a/GdscBackend/Database/IRepository.cs b/GdscBackend/Database/IRepository.cs index 9abb08e..e2476a2 100644 --- a/GdscBackend/Database/IRepository.cs +++ b/GdscBackend/Database/IRepository.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using GdscBackend.Models; +using GdscBackend.Common.Models; using Microsoft.EntityFrameworkCore; namespace GdscBackend.Database; diff --git a/GdscBackend/Database/Repository.cs b/GdscBackend/Database/Repository.cs index 819a223..98da45c 100644 --- a/GdscBackend/Database/Repository.cs +++ b/GdscBackend/Database/Repository.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using GdscBackend.Models; +using GdscBackend.Common.Models; using Microsoft.EntityFrameworkCore; namespace GdscBackend.Database; diff --git a/GdscBackend/Features/Articles/ArticleModel.cs b/GdscBackend/Features/Articles/ArticleModel.cs index 92c7552..3923aa4 100644 --- a/GdscBackend/Features/Articles/ArticleModel.cs +++ b/GdscBackend/Features/Articles/ArticleModel.cs @@ -1,5 +1,5 @@ using GdscBackend.Auth; -using GdscBackend.Models; +using GdscBackend.Common.Models; namespace GdscBackend.Features.Articles; diff --git a/GdscBackend/Controllers/v1/ContactController.cs b/GdscBackend/Features/Contacts/ContactController.cs similarity index 96% rename from GdscBackend/Controllers/v1/ContactController.cs rename to GdscBackend/Features/Contacts/ContactController.cs index 35ef6fb..4bb8188 100644 --- a/GdscBackend/Controllers/v1/ContactController.cs +++ b/GdscBackend/Features/Contacts/ContactController.cs @@ -1,15 +1,13 @@ using System.ComponentModel.DataAnnotations; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using GdscBackend.Utils; using GdscBackend.Utils.Services; using GdscBackend.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Contacts; [ApiController] [Authorize(Roles = "admin")] diff --git a/GdscBackend/Models/ContactModel.cs b/GdscBackend/Features/Contacts/ContactModel.cs similarity index 71% rename from GdscBackend/Models/ContactModel.cs rename to GdscBackend/Features/Contacts/ContactModel.cs index 748f97a..cd245a7 100644 --- a/GdscBackend/Models/ContactModel.cs +++ b/GdscBackend/Features/Contacts/ContactModel.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; + +namespace GdscBackend.Features.Contacts; public class ContactModel : Model { diff --git a/GdscBackend/RequestModels/ContactRequest.cs b/GdscBackend/Features/Contacts/ContactRequest.cs similarity index 70% rename from GdscBackend/RequestModels/ContactRequest.cs rename to GdscBackend/Features/Contacts/ContactRequest.cs index b3f0b0b..16c610e 100644 --- a/GdscBackend/RequestModels/ContactRequest.cs +++ b/GdscBackend/Features/Contacts/ContactRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Contacts; public class ContactRequest : Request { diff --git a/GdscBackend/Models/EventModel.cs b/GdscBackend/Features/Events/EventModel.cs similarity index 68% rename from GdscBackend/Models/EventModel.cs rename to GdscBackend/Features/Events/EventModel.cs index d7933d7..06c2729 100644 --- a/GdscBackend/Models/EventModel.cs +++ b/GdscBackend/Features/Events/EventModel.cs @@ -1,4 +1,7 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; +using GdscBackend.Features.FIles; + +namespace GdscBackend.Features.Events; public class EventModel : Model { diff --git a/GdscBackend/RequestModels/EventRequest.cs b/GdscBackend/Features/Events/EventRequest.cs similarity index 75% rename from GdscBackend/RequestModels/EventRequest.cs rename to GdscBackend/Features/Events/EventRequest.cs index ab25bdb..79cbe87 100644 --- a/GdscBackend/RequestModels/EventRequest.cs +++ b/GdscBackend/Features/Events/EventRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Events; public class EventRequest : Request { diff --git a/GdscBackend/Controllers/v1/EventsController.cs b/GdscBackend/Features/Events/EventsController.cs similarity index 96% rename from GdscBackend/Controllers/v1/EventsController.cs rename to GdscBackend/Features/Events/EventsController.cs index 3ef06f1..2474f99 100644 --- a/GdscBackend/Controllers/v1/EventsController.cs +++ b/GdscBackend/Features/Events/EventsController.cs @@ -1,12 +1,11 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.FIles; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Events; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/ExampleModel.cs b/GdscBackend/Features/Examples/ExampleModel.cs similarity index 80% rename from GdscBackend/Models/ExampleModel.cs rename to GdscBackend/Features/Examples/ExampleModel.cs index a2b034e..53c2a17 100644 --- a/GdscBackend/Models/ExampleModel.cs +++ b/GdscBackend/Features/Examples/ExampleModel.cs @@ -1,8 +1,8 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using GdscBackend.Models.Enums; +using GdscBackend.Common.Models; -namespace GdscBackend.Models; +namespace GdscBackend.Features.Examples; public class ExampleModel : Model { diff --git a/GdscBackend/Models/Enums/ExampleTypeEnum.cs b/GdscBackend/Features/Examples/ExampleTypeEnum.cs similarity index 67% rename from GdscBackend/Models/Enums/ExampleTypeEnum.cs rename to GdscBackend/Features/Examples/ExampleTypeEnum.cs index 45e0091..b464d2f 100644 --- a/GdscBackend/Models/Enums/ExampleTypeEnum.cs +++ b/GdscBackend/Features/Examples/ExampleTypeEnum.cs @@ -1,4 +1,4 @@ -namespace GdscBackend.Models.Enums; +namespace GdscBackend.Features.Examples; public enum ExampleTypeEnum { diff --git a/GdscBackend/Controllers/v1/ExamplesController.cs b/GdscBackend/Features/Examples/ExamplesController.cs similarity index 97% rename from GdscBackend/Controllers/v1/ExamplesController.cs rename to GdscBackend/Features/Examples/ExamplesController.cs index 251d669..e99a31c 100644 --- a/GdscBackend/Controllers/v1/ExamplesController.cs +++ b/GdscBackend/Features/Examples/ExamplesController.cs @@ -1,9 +1,8 @@ using System.Net.Mime; using GdscBackend.Database; -using GdscBackend.Models; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Examples; // This marks this controller as a public one that can be called from the internet [ApiController] diff --git a/GdscBackend/Models/FileModel.cs b/GdscBackend/Features/FIles/FileModel.cs similarity index 71% rename from GdscBackend/Models/FileModel.cs rename to GdscBackend/Features/FIles/FileModel.cs index 9c316d9..4ba5d3b 100644 --- a/GdscBackend/Models/FileModel.cs +++ b/GdscBackend/Features/FIles/FileModel.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; + +namespace GdscBackend.Features.FIles; public class FileModel : Model { diff --git a/GdscBackend/Controllers/v1/FilesController.cs b/GdscBackend/Features/FIles/FilesController.cs similarity index 96% rename from GdscBackend/Controllers/v1/FilesController.cs rename to GdscBackend/Features/FIles/FilesController.cs index 545323d..204d7c5 100644 --- a/GdscBackend/Controllers/v1/FilesController.cs +++ b/GdscBackend/Features/FIles/FilesController.cs @@ -1,9 +1,8 @@ using GdscBackend.Database; -using GdscBackend.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.FIles; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/FaqModel.cs b/GdscBackend/Features/Faqs/FaqModel.cs similarity index 60% rename from GdscBackend/Models/FaqModel.cs rename to GdscBackend/Features/Faqs/FaqModel.cs index 86ba373..25fe77d 100644 --- a/GdscBackend/Models/FaqModel.cs +++ b/GdscBackend/Features/Faqs/FaqModel.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; + +namespace GdscBackend.Features.Faqs; public class FaqModel : Model { diff --git a/GdscBackend/RequestModels/FaqRequest.cs b/GdscBackend/Features/Faqs/FaqRequest.cs similarity index 60% rename from GdscBackend/RequestModels/FaqRequest.cs rename to GdscBackend/Features/Faqs/FaqRequest.cs index b4d7ff2..aa8120f 100644 --- a/GdscBackend/RequestModels/FaqRequest.cs +++ b/GdscBackend/Features/Faqs/FaqRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Faqs; public class FaqRequest : Request { diff --git a/GdscBackend/Controllers/v1/FaqsController.cs b/GdscBackend/Features/Faqs/FaqsController.cs similarity index 96% rename from GdscBackend/Controllers/v1/FaqsController.cs rename to GdscBackend/Features/Faqs/FaqsController.cs index be37504..ee4b34c 100644 --- a/GdscBackend/Controllers/v1/FaqsController.cs +++ b/GdscBackend/Features/Faqs/FaqsController.cs @@ -1,12 +1,10 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Faqs; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/MemberModel.cs b/GdscBackend/Features/Members/MemberModel.cs similarity index 60% rename from GdscBackend/Models/MemberModel.cs rename to GdscBackend/Features/Members/MemberModel.cs index bc007d5..e79f1f1 100644 --- a/GdscBackend/Models/MemberModel.cs +++ b/GdscBackend/Features/Members/MemberModel.cs @@ -1,4 +1,7 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; +using GdscBackend.Features.Teams; + +namespace GdscBackend.Features.Members; public class MemberModel : Model { diff --git a/GdscBackend/RequestModels/MemberRequest.cs b/GdscBackend/Features/Members/MemberRequest.cs similarity index 66% rename from GdscBackend/RequestModels/MemberRequest.cs rename to GdscBackend/Features/Members/MemberRequest.cs index 939a7f7..042022e 100644 --- a/GdscBackend/RequestModels/MemberRequest.cs +++ b/GdscBackend/Features/Members/MemberRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Members; public class MemberRequest : Request { diff --git a/GdscBackend/Controllers/v1/MembersController.cs b/GdscBackend/Features/Members/MembersController.cs similarity index 96% rename from GdscBackend/Controllers/v1/MembersController.cs rename to GdscBackend/Features/Members/MembersController.cs index 02413b3..500e931 100644 --- a/GdscBackend/Controllers/v1/MembersController.cs +++ b/GdscBackend/Features/Members/MembersController.cs @@ -1,13 +1,11 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using GdscBackend.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Members; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/MenuItemModel.cs b/GdscBackend/Features/MenuItems/MenuItemModel.cs similarity index 68% rename from GdscBackend/Models/MenuItemModel.cs rename to GdscBackend/Features/MenuItems/MenuItemModel.cs index d8bfbce..c19240d 100644 --- a/GdscBackend/Models/MenuItemModel.cs +++ b/GdscBackend/Features/MenuItems/MenuItemModel.cs @@ -1,6 +1,6 @@ -using GdscBackend.Models.Enums; +using GdscBackend.Common.Models; -namespace GdscBackend.Models; +namespace GdscBackend.Features.MenuItems; public class MenuItemModel : Model { diff --git a/GdscBackend/RequestModels/MenuItemRequest.cs b/GdscBackend/Features/MenuItems/MenuItemRequest.cs similarity index 66% rename from GdscBackend/RequestModels/MenuItemRequest.cs rename to GdscBackend/Features/MenuItems/MenuItemRequest.cs index 99d4bd9..0fc45af 100644 --- a/GdscBackend/RequestModels/MenuItemRequest.cs +++ b/GdscBackend/Features/MenuItems/MenuItemRequest.cs @@ -1,6 +1,6 @@ -using GdscBackend.Models.Enums; +using GdscBackend.Common.RequestModels; -namespace GdscBackend.RequestModels; +namespace GdscBackend.Features.MenuItems; public class MenuItemRequest : Request { diff --git a/GdscBackend/Models/Enums/MenuItemTypeEnum.cs b/GdscBackend/Features/MenuItems/MenuItemTypeEnum.cs similarity index 80% rename from GdscBackend/Models/Enums/MenuItemTypeEnum.cs rename to GdscBackend/Features/MenuItems/MenuItemTypeEnum.cs index 1205db3..14a2e13 100644 --- a/GdscBackend/Models/Enums/MenuItemTypeEnum.cs +++ b/GdscBackend/Features/MenuItems/MenuItemTypeEnum.cs @@ -1,6 +1,6 @@ using System.Runtime.Serialization; -namespace GdscBackend.Models.Enums; +namespace GdscBackend.Features.MenuItems; public enum MenuItemTypeEnum { diff --git a/GdscBackend/Controllers/v1/MenuItemsController.cs b/GdscBackend/Features/MenuItems/MenuItemsController.cs similarity index 96% rename from GdscBackend/Controllers/v1/MenuItemsController.cs rename to GdscBackend/Features/MenuItems/MenuItemsController.cs index 385c6f4..5506dfd 100644 --- a/GdscBackend/Controllers/v1/MenuItemsController.cs +++ b/GdscBackend/Features/MenuItems/MenuItemsController.cs @@ -1,12 +1,10 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.MenuItems; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/PageModel.cs b/GdscBackend/Features/Pages/PageModel.cs similarity index 78% rename from GdscBackend/Models/PageModel.cs rename to GdscBackend/Features/Pages/PageModel.cs index 4a46c36..5bd929e 100644 --- a/GdscBackend/Models/PageModel.cs +++ b/GdscBackend/Features/Pages/PageModel.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; + +namespace GdscBackend.Features.Pages; public class PageModel : Model { diff --git a/GdscBackend/RequestModels/PageRequest.cs b/GdscBackend/Features/Pages/PageRequest.cs similarity index 77% rename from GdscBackend/RequestModels/PageRequest.cs rename to GdscBackend/Features/Pages/PageRequest.cs index 3bc9f8b..e04cb3c 100644 --- a/GdscBackend/RequestModels/PageRequest.cs +++ b/GdscBackend/Features/Pages/PageRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Pages; public class PageRequest : Request { diff --git a/GdscBackend/Controllers/v1/PagesController.cs b/GdscBackend/Features/Pages/PagesController.cs similarity index 96% rename from GdscBackend/Controllers/v1/PagesController.cs rename to GdscBackend/Features/Pages/PagesController.cs index 2c42f77..07ab488 100644 --- a/GdscBackend/Controllers/v1/PagesController.cs +++ b/GdscBackend/Features/Pages/PagesController.cs @@ -1,12 +1,10 @@ using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using GdscBackend.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Pages; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Features/Redirects/RedirectModel.cs b/GdscBackend/Features/Redirects/RedirectModel.cs index 8e1ef1c..aaffbbe 100644 --- a/GdscBackend/Features/Redirects/RedirectModel.cs +++ b/GdscBackend/Features/Redirects/RedirectModel.cs @@ -1,4 +1,4 @@ -using GdscBackend.Models; +using GdscBackend.Common.Models; namespace GdscBackend.Features.Redirects; diff --git a/GdscBackend/Features/Redirects/RedirectRequest.cs b/GdscBackend/Features/Redirects/RedirectRequest.cs index c6a97af..79da157 100644 --- a/GdscBackend/Features/Redirects/RedirectRequest.cs +++ b/GdscBackend/Features/Redirects/RedirectRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Redirects; public class RedirectRequest : Request { diff --git a/GdscBackend/Features/Redirects/RedirectsController.cs b/GdscBackend/Features/Redirects/RedirectsController.cs index 14c10d5..d5e20b1 100644 --- a/GdscBackend/Features/Redirects/RedirectsController.cs +++ b/GdscBackend/Features/Redirects/RedirectsController.cs @@ -1,7 +1,6 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; diff --git a/GdscBackend/Models/SettingModel.cs b/GdscBackend/Features/Settings/SettingModel.cs similarity index 75% rename from GdscBackend/Models/SettingModel.cs rename to GdscBackend/Features/Settings/SettingModel.cs index f79f991..d10766d 100644 --- a/GdscBackend/Models/SettingModel.cs +++ b/GdscBackend/Features/Settings/SettingModel.cs @@ -1,6 +1,6 @@ -using GdscBackend.Models.Enums; +using GdscBackend.Common.Models; -namespace GdscBackend.Models; +namespace GdscBackend.Features.Settings; public class SettingModel : Model { diff --git a/GdscBackend/RequestModels/SettingRequest.cs b/GdscBackend/Features/Settings/SettingRequest.cs similarity index 74% rename from GdscBackend/RequestModels/SettingRequest.cs rename to GdscBackend/Features/Settings/SettingRequest.cs index 7cab3a5..659b325 100644 --- a/GdscBackend/RequestModels/SettingRequest.cs +++ b/GdscBackend/Features/Settings/SettingRequest.cs @@ -1,6 +1,6 @@ -using GdscBackend.Models.Enums; +using GdscBackend.Common.RequestModels; -namespace GdscBackend.RequestModels; +namespace GdscBackend.Features.Settings; public class SettingRequest : Request { diff --git a/GdscBackend/Models/Enums/SettingTypeEnum.cs b/GdscBackend/Features/Settings/SettingTypeEnum.cs similarity index 59% rename from GdscBackend/Models/Enums/SettingTypeEnum.cs rename to GdscBackend/Features/Settings/SettingTypeEnum.cs index 730d8b1..bf91f7e 100644 --- a/GdscBackend/Models/Enums/SettingTypeEnum.cs +++ b/GdscBackend/Features/Settings/SettingTypeEnum.cs @@ -1,4 +1,4 @@ -namespace GdscBackend.Models.Enums; +namespace GdscBackend.Features.Settings; public enum SettingTypeEnum { diff --git a/GdscBackend/Controllers/v1/SettingsController.cs b/GdscBackend/Features/Settings/SettingsController.cs similarity index 97% rename from GdscBackend/Controllers/v1/SettingsController.cs rename to GdscBackend/Features/Settings/SettingsController.cs index d9624db..9e3217b 100644 --- a/GdscBackend/Controllers/v1/SettingsController.cs +++ b/GdscBackend/Features/Settings/SettingsController.cs @@ -1,12 +1,10 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Settings; // This marks this controller as a public one that can be called from the internet [ApiController] diff --git a/GdscBackend/Models/TeamModel.cs b/GdscBackend/Features/Teams/TeamModel.cs similarity index 53% rename from GdscBackend/Models/TeamModel.cs rename to GdscBackend/Features/Teams/TeamModel.cs index c942098..ff60f76 100644 --- a/GdscBackend/Models/TeamModel.cs +++ b/GdscBackend/Features/Teams/TeamModel.cs @@ -1,4 +1,7 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; +using GdscBackend.Features.Members; + +namespace GdscBackend.Features.Teams; public class TeamModel : Model { diff --git a/GdscBackend/Features/Teams/TeamRequest.cs b/GdscBackend/Features/Teams/TeamRequest.cs new file mode 100644 index 0000000..cab6655 --- /dev/null +++ b/GdscBackend/Features/Teams/TeamRequest.cs @@ -0,0 +1,8 @@ +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Teams; + +public class TeamRequest : Request +{ + public string Name { get; set; } +} \ No newline at end of file diff --git a/GdscBackend/Controllers/v1/TeamsController.cs b/GdscBackend/Features/Teams/TeamsController.cs similarity index 96% rename from GdscBackend/Controllers/v1/TeamsController.cs rename to GdscBackend/Features/Teams/TeamsController.cs index 245938e..6a7739d 100644 --- a/GdscBackend/Controllers/v1/TeamsController.cs +++ b/GdscBackend/Features/Teams/TeamsController.cs @@ -1,12 +1,10 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Teams; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Controllers/v1/TechnologiesController.cs b/GdscBackend/Features/Technologies/TechnologiesController.cs similarity index 95% rename from GdscBackend/Controllers/v1/TechnologiesController.cs rename to GdscBackend/Features/Technologies/TechnologiesController.cs index 03737f3..02f4df4 100644 --- a/GdscBackend/Controllers/v1/TechnologiesController.cs +++ b/GdscBackend/Features/Technologies/TechnologiesController.cs @@ -1,12 +1,10 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; -using GdscBackend.Models; -using GdscBackend.RequestModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace GdscBackend.Controllers.v1; +namespace GdscBackend.Features.Technologies; [ApiController] [ApiVersion("1")] diff --git a/GdscBackend/Models/TechnologyModel.cs b/GdscBackend/Features/Technologies/TechnologyModel.cs similarity index 65% rename from GdscBackend/Models/TechnologyModel.cs rename to GdscBackend/Features/Technologies/TechnologyModel.cs index 964672d..cfaa6d2 100644 --- a/GdscBackend/Models/TechnologyModel.cs +++ b/GdscBackend/Features/Technologies/TechnologyModel.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.Models; +using GdscBackend.Common.Models; + +namespace GdscBackend.Features.Technologies; public class TechnologyModel : Model { diff --git a/GdscBackend/RequestModels/TechnologyRequest.cs b/GdscBackend/Features/Technologies/TechnologyRequest.cs similarity index 65% rename from GdscBackend/RequestModels/TechnologyRequest.cs rename to GdscBackend/Features/Technologies/TechnologyRequest.cs index dab04e2..8b622b5 100644 --- a/GdscBackend/RequestModels/TechnologyRequest.cs +++ b/GdscBackend/Features/Technologies/TechnologyRequest.cs @@ -1,4 +1,6 @@ -namespace GdscBackend.RequestModels; +using GdscBackend.Common.RequestModels; + +namespace GdscBackend.Features.Technologies; public class TechnologyRequest : Request { diff --git a/GdscBackend/GdscBackend.csproj b/GdscBackend/GdscBackend.csproj index 4add348..6898e8b 100644 --- a/GdscBackend/GdscBackend.csproj +++ b/GdscBackend/GdscBackend.csproj @@ -24,4 +24,8 @@ + + + + diff --git a/GdscBackend/RequestModels/Request.cs b/GdscBackend/RequestModels/Request.cs deleted file mode 100644 index 4bbfc53..0000000 --- a/GdscBackend/RequestModels/Request.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace GdscBackend.RequestModels; - -public class Request -{ -} \ No newline at end of file diff --git a/GdscBackend/RequestModels/TeamRequest.cs b/GdscBackend/RequestModels/TeamRequest.cs deleted file mode 100644 index dd3f6bf..0000000 --- a/GdscBackend/RequestModels/TeamRequest.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace GdscBackend.RequestModels; - -public class TeamRequest : Request -{ - public string Name { get; set; } -} \ No newline at end of file diff --git a/GdscBackend/Utils/Mappers/MappingProfiles.cs b/GdscBackend/Utils/Mappers/MappingProfiles.cs index bc69081..ae8ac63 100644 --- a/GdscBackend/Utils/Mappers/MappingProfiles.cs +++ b/GdscBackend/Utils/Mappers/MappingProfiles.cs @@ -1,7 +1,14 @@ using AutoMapper; +using GdscBackend.Features.Contacts; +using GdscBackend.Features.Events; +using GdscBackend.Features.Faqs; +using GdscBackend.Features.Members; +using GdscBackend.Features.MenuItems; +using GdscBackend.Features.Pages; using GdscBackend.Features.Redirects; -using GdscBackend.Models; -using GdscBackend.RequestModels; +using GdscBackend.Features.Settings; +using GdscBackend.Features.Teams; +using GdscBackend.Features.Technologies; namespace GdscBackend.Utils.Mappers; diff --git a/GdscBackend/Utils/Services/IWebhookService.cs b/GdscBackend/Utils/Services/IWebhookService.cs index 2cf13b6..f288cf2 100644 --- a/GdscBackend/Utils/Services/IWebhookService.cs +++ b/GdscBackend/Utils/Services/IWebhookService.cs @@ -1,4 +1,4 @@ -using GdscBackend.Models; +using GdscBackend.Features.Contacts; namespace GdscBackend.Utils.Services; diff --git a/GdscBackend/Utils/Services/WebhookService.cs b/GdscBackend/Utils/Services/WebhookService.cs index ce3b85a..f6e55bd 100644 --- a/GdscBackend/Utils/Services/WebhookService.cs +++ b/GdscBackend/Utils/Services/WebhookService.cs @@ -1,4 +1,4 @@ -using GdscBackend.Models; +using GdscBackend.Features.Contacts; namespace GdscBackend.Utils.Services; From 8765c804628f732a0df700a2d3122d33fca33424 Mon Sep 17 00:00:00 2001 From: Andrei Dobre <92524605+ad0bre@users.noreply.github.com> Date: Sun, 11 Dec 2022 00:07:29 +0200 Subject: [PATCH 4/8] Update CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6c862d7..037754a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,4 +6,4 @@ # review when someone opens a pull request. -* @danpercic86 +* @ad0bre From 331dd4958c41074d907462ff11aec9815d7762b2 Mon Sep 17 00:00:00 2001 From: Balan Veniamin Date: Sun, 29 Oct 2023 17:40:01 +0200 Subject: [PATCH 5/8] added keycloak --- Dockerfile | 2 +- GdscBackend.Tests/AuthTests.cs | 127 ----- GdscBackend/Auth/AuthController.cs | 120 ----- GdscBackend/Auth/LoginResponse.cs | 7 - GdscBackend/Auth/LoginViewModel.cs | 12 - GdscBackend/Auth/RegisterViewModel.cs | 16 - GdscBackend/Auth/Role.cs | 7 - GdscBackend/Auth/User.cs | 7 - GdscBackend/Auth/UserController.cs | 74 --- GdscBackend/Auth/UserViewModel.cs | 9 - GdscBackend/Database/AppDbContext.cs | 3 +- .../Features/Articles/ArticleController.cs | 88 ++-- GdscBackend/Features/Articles/ArticleModel.cs | 5 +- .../Features/Articles/ArticleResponse.cs | 6 +- GdscBackend/GdscBackend.csproj | 25 +- .../20231029144626_keycloak.Designer.cs | 444 ++++++++++++++++++ .../Migrations/20231029144626_keycloak.cs | 261 ++++++++++ .../Migrations/AppDbContextModelSnapshot.cs | 377 +++------------ GdscBackend/Program.cs | 54 +-- .../Swagger/ConfigureSwaggerOptions.cs | 30 +- GdscBackend/Swagger/SwaggerConfiguration.cs | 51 +- GdscBackend/appsettings.json | 8 + 22 files changed, 887 insertions(+), 846 deletions(-) delete mode 100644 GdscBackend.Tests/AuthTests.cs delete mode 100644 GdscBackend/Auth/AuthController.cs delete mode 100644 GdscBackend/Auth/LoginResponse.cs delete mode 100644 GdscBackend/Auth/LoginViewModel.cs delete mode 100644 GdscBackend/Auth/RegisterViewModel.cs delete mode 100644 GdscBackend/Auth/Role.cs delete mode 100644 GdscBackend/Auth/User.cs delete mode 100644 GdscBackend/Auth/UserController.cs delete mode 100644 GdscBackend/Auth/UserViewModel.cs create mode 100644 GdscBackend/Migrations/20231029144626_keycloak.Designer.cs create mode 100644 GdscBackend/Migrations/20231029144626_keycloak.cs diff --git a/Dockerfile b/Dockerfile index 83fca82..b49c948 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ COPY --from=build-env /app/out . COPY docker-entrypoint.sh /usr/bin/docker-entrypoint.sh RUN chmod +x /usr/bin/docker-entrypoint.sh -ENTRYPOINT ["docker-entrypoint.sh"] +ENTRYPOINT ["docker-entrypoint.sh"] # Link image with github repo LABEL org.opencontainers.image.source=https://github.com/dsc-upt/gdsc-backend diff --git a/GdscBackend.Tests/AuthTests.cs b/GdscBackend.Tests/AuthTests.cs deleted file mode 100644 index 670296e..0000000 --- a/GdscBackend.Tests/AuthTests.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Text; -using GdscBackend.Auth; -using GdscBackend.Database; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features.Authentication; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Tokens; -using Xunit; -using Xunit.Abstractions; - -namespace GdscBackend.Tests; - -public class AuthTests : TestingBase -{ - private readonly IConfiguration _configuration; - private readonly RoleManager _roleManager; - private readonly UserManager _userManager; - - public AuthTests(ITestOutputHelper outputHelper) : base(outputHelper) - { - var builder = WebApplication.CreateBuilder(); - var services = builder.Services; - services.AddDbContext(options => options.UseInMemoryDatabase("TestDb")); - services.AddIdentity(options => - { - options.Password.RequireDigit = false; - options.Password.RequiredLength = 8; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.SaveToken = true; - options.RequireHttpsMetadata = false; - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidateAudience = true, - ValidAudience = "http://localhost:5000", - ValidIssuer = "http://localhost:5000", - IssuerSigningKey = - new SymmetricSecurityKey(Encoding.UTF8.GetBytes("somerandomsecretherefortesting")) - }; - }); - - // Taken from https://github.com/aspnet/MusicStore/blob/dev/test/MusicStore.Test/ManageControllerTest.cs (and modified) - // IHttpContextAccessor is required for SignInManager, and UserManager - var context = new DefaultHttpContext(); - context.Features.Set(new HttpAuthenticationFeature()); - services.AddSingleton(_ => new HttpContextAccessor { HttpContext = context }); - var serviceProvider = services.BuildServiceProvider(); - _userManager = serviceProvider.GetService>(); - _roleManager = serviceProvider.GetService>(); - _configuration = serviceProvider.GetService(); - } - - [Fact] - public async void Register() - { - // Arrange - var user = new RegisterViewModel - { - Username = "UserForTesting", - Email = "testuser@dscupt.tech", - Password = "sometestpasswordhere" - }; - - var controller = new AuthController(_userManager, _roleManager, _configuration); - - // Act - var added = await controller.Register(user); - - // Assert - var actionResult = Assert.IsType>(added); - Assert.NotNull(actionResult); - var createdResult = Assert.IsType(actionResult.Result); - Assert.NotNull(createdResult); - var entity = Assert.IsType(createdResult.Value); - - Assert.NotNull(entity); - Assert.NotNull(entity.UserName); - Assert.Equal(StatusCodes.Status201Created, createdResult.StatusCode); - Assert.Equal(user.Username, entity.UserName); - Assert.Equal(user.Email, entity.Email); - } - - [Fact] - public async void Login() - { - // Arrange - var controller = new AuthController(_userManager, _roleManager, _configuration); - - var userToRegister = new User { UserName = "basicUsername", Email = "basicEmail" }; - - await _userManager.CreateAsync(userToRegister, "basicPassword"); - - var userToLogin = new LoginViewModel - { - Username = "basicUsername", - Password = "basicPassword" - }; - - // Act - var added = await controller.Login(userToLogin); - - // Assert - Assert.NotNull(added); - var actionResult = Assert.IsType>(added); - var okResult = Assert.IsType(actionResult.Result); - var result = Assert.IsType(okResult.Value); - Assert.NotNull(result.Token); - } -} diff --git a/GdscBackend/Auth/AuthController.cs b/GdscBackend/Auth/AuthController.cs deleted file mode 100644 index 665a34c..0000000 --- a/GdscBackend/Auth/AuthController.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Text; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Microsoft.IdentityModel.Tokens; - -namespace GdscBackend.Auth; - -[ApiController] -[Route("v1/auth")] -public class AuthController : ControllerBase -{ - private readonly IConfiguration _configuration; - private readonly RoleManager _roleManager; - private readonly UserManager _userModel; - - public AuthController(UserManager userModel, RoleManager roleManager, - IConfiguration configuration) - { - _userModel = userModel; - _roleManager = roleManager; - _configuration = configuration; - } - - [HttpPost] - [Route("login")] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] - public async Task> Login(LoginViewModel model) - { - var user = await _userModel.FindByNameAsync(model.Username); - var wrongPassword = !await _userModel.CheckPasswordAsync(user, model.Password); - if (user == null || wrongPassword) - { - return Unauthorized(); - } - - var userRoles = await _userModel.GetRolesAsync(user); - - var authClaims = new List - { - new("name", user.UserName), - new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) - }; - - authClaims.AddRange(userRoles.Select(userRole => new Claim("roles", userRole))); - - var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"])); - - var token = new JwtSecurityToken( - _configuration["JWT:ValidIssuer"], - _configuration["JWT:ValidAudience"], - expires: DateTime.Now.AddHours(5), - claims: authClaims, - signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) - ); - - return Ok(new LoginResponse - { - Token = new JwtSecurityTokenHandler().WriteToken(token), - Expiration = token.ValidTo - }); - } - - [HttpPost] - [Route("register")] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task> Register(RegisterViewModel model) - { - var rolesDoesNotExist = !await _roleManager.RoleExistsAsync("admin"); - var admins = await _userModel.GetUsersInRoleAsync("admin"); - - if (rolesDoesNotExist || admins.Count == 0) - { - await AddRoles(); - return await AddUser(model, true); - } - - var userWithSameName = await _userModel.FindByNameAsync(model.Username); - var userWithSameEmail = await _userModel.FindByEmailAsync(model.Email); - var userExists = userWithSameEmail is not null || userWithSameName is not null; - if (userExists) - { - return BadRequest("User already exists, please login"); - } - - return await AddUser(model, false); - } - - private async Task AddRoles() - { - var role = new Role { Id = Guid.NewGuid().ToString(), Name = "admin" }; - var result = await _roleManager.CreateAsync(role); - if (!result.Succeeded) - { - Console.WriteLine(result.Errors); - } - } - - private async Task> AddUser(RegisterViewModel model, bool makeAdmin) - { - var puser = new User { UserName = model.Username, Email = model.Email }; - - var result = await _userModel.CreateAsync(puser, model.Password); - if (!result.Succeeded) - { - var errors = result.Errors.Select(error => error.Description); - return new UserViewModel { Errors = errors }; - } - - var user = await _userModel.FindByNameAsync(puser.UserName); - if (makeAdmin) - { - await _userModel.AddToRoleAsync(user, "admin"); - } - - return Created("", new UserViewModel { Id = user.Id, Email = user.Email, UserName = user.UserName }); - } -} diff --git a/GdscBackend/Auth/LoginResponse.cs b/GdscBackend/Auth/LoginResponse.cs deleted file mode 100644 index 418bf2b..0000000 --- a/GdscBackend/Auth/LoginResponse.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GdscBackend.Auth; - -public class LoginResponse -{ - public string Token { get; set; } - public DateTime Expiration { get; set; } -} diff --git a/GdscBackend/Auth/LoginViewModel.cs b/GdscBackend/Auth/LoginViewModel.cs deleted file mode 100644 index ee132c2..0000000 --- a/GdscBackend/Auth/LoginViewModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace GdscBackend.Auth; - -public class LoginViewModel -{ - [Required(ErrorMessage = "User Name is required")] - public string Username { get; set; } - - [Required(ErrorMessage = "Password is required")] - public string Password { get; set; } -} \ No newline at end of file diff --git a/GdscBackend/Auth/RegisterViewModel.cs b/GdscBackend/Auth/RegisterViewModel.cs deleted file mode 100644 index 9a39a7b..0000000 --- a/GdscBackend/Auth/RegisterViewModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace GdscBackend.Auth; - -public class RegisterViewModel -{ - [Required(ErrorMessage = "User Name is required")] - public string Username { get; set; } - - [EmailAddress] - [Required(ErrorMessage = "Email is required")] - public string Email { get; set; } - - [Required(ErrorMessage = "Password is required")] - public string Password { get; set; } -} \ No newline at end of file diff --git a/GdscBackend/Auth/Role.cs b/GdscBackend/Auth/Role.cs deleted file mode 100644 index 703f84c..0000000 --- a/GdscBackend/Auth/Role.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Microsoft.AspNetCore.Identity; - -namespace GdscBackend.Auth; - -public class Role : IdentityRole -{ -} \ No newline at end of file diff --git a/GdscBackend/Auth/User.cs b/GdscBackend/Auth/User.cs deleted file mode 100644 index bc23e7e..0000000 --- a/GdscBackend/Auth/User.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Microsoft.AspNetCore.Identity; - -namespace GdscBackend.Auth; - -public class User : IdentityUser -{ -} \ No newline at end of file diff --git a/GdscBackend/Auth/UserController.cs b/GdscBackend/Auth/UserController.cs deleted file mode 100644 index 5e9bbcf..0000000 --- a/GdscBackend/Auth/UserController.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Net.Mime; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; - -namespace GdscBackend.Auth; - -[ApiController] -[ApiVersion("1")] -[Route("v1/roles")] -[Authorize(Roles = "admin")] -[Consumes(MediaTypeNames.Application.Json)] -[Produces(MediaTypeNames.Application.Json)] -[Authorize(Roles = "admin")] -public class UserController : ControllerBase -{ - private readonly RoleManager _roleManager; - private readonly UserManager _userManager; - - public UserController(UserManager userManager, RoleManager roleManager) - { - _userManager = userManager; - _roleManager = roleManager; - } - - [HttpGet] - [ProducesResponseType(StatusCodes.Status200OK)] - public async Task>> GetByRole(string roleName) - { - //return Ok((await _repository.GetAsync()).ToList()); - return Ok(await _userManager.GetUsersInRoleAsync(roleName)); - } - - [HttpGet("{id}")] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> Get([FromRoute] string id) - { - var entity = await _userManager.FindByIdAsync(id); - - return entity is null ? NotFound() : Ok(entity); - } - - [HttpPost] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - public async Task> Post(User entity) - { - var result = await _userManager.CreateAsync(entity); - //entity = await _userManager.CreateAsync(entity); - - if (result.Succeeded) - { - return await _userManager.FindByNameAsync(entity.UserName); - } - - return BadRequest(result.Errors); - - //return CreatedAtAction(nameof(Post), new {result.Id}, result); - } - - [HttpDelete("{id}")] - [ProducesResponseType(StatusCodes.Status201Created)] - [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> Delete([FromRoute] string id) - { - //var entity = await _repository.DeleteAsync(id); - var entity = await _userManager.DeleteAsync(await _userManager.FindByIdAsync(id)); - - return entity is null ? NotFound() : Ok(entity); - } -} \ No newline at end of file diff --git a/GdscBackend/Auth/UserViewModel.cs b/GdscBackend/Auth/UserViewModel.cs deleted file mode 100644 index 8698354..0000000 --- a/GdscBackend/Auth/UserViewModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace GdscBackend.Auth; - -public class UserViewModel -{ - public string Id { get; set; } - public string UserName { get; set; } - public string Email { get; set; } - public IEnumerable Errors { get; set; } -} \ No newline at end of file diff --git a/GdscBackend/Database/AppDbContext.cs b/GdscBackend/Database/AppDbContext.cs index deceaf2..ffab93f 100644 --- a/GdscBackend/Database/AppDbContext.cs +++ b/GdscBackend/Database/AppDbContext.cs @@ -1,4 +1,3 @@ -using GdscBackend.Auth; using GdscBackend.Features.Articles; using GdscBackend.Features.Contacts; using GdscBackend.Features.Events; @@ -17,7 +16,7 @@ namespace GdscBackend.Database; -public class AppDbContext : IdentityDbContext +public class AppDbContext : DbContext { public AppDbContext(DbContextOptions options) : base(options) { diff --git a/GdscBackend/Features/Articles/ArticleController.cs b/GdscBackend/Features/Articles/ArticleController.cs index edf1f13..9138d64 100644 --- a/GdscBackend/Features/Articles/ArticleController.cs +++ b/GdscBackend/Features/Articles/ArticleController.cs @@ -1,7 +1,5 @@ -using GdscBackend.Auth; -using GdscBackend.Database; +using GdscBackend.Database; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -9,9 +7,8 @@ namespace GdscBackend.Features.Articles; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize] [Route("v1/Articles")] - public class ArticleController : ControllerBase { private readonly AppDbContext _dbContext; @@ -21,13 +18,16 @@ public ArticleController(AppDbContext appDbContext) _dbContext = appDbContext; } + /* [HttpPost] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> Post(ArticleRequest request) { - var author = await _dbContext.Users.FirstOrDefaultAsync(entity => entity.Id == request.AuthorId); + + + //var author = await _dbContext.Users.FirstOrDefaultAsync(entity => entity.Id == request.AuthorId); if (author is null) { return NotFound("User not found!"); @@ -40,7 +40,7 @@ public async Task> Post(ArticleRequest request) Updated = DateTime.UtcNow, Title = request.Title, Content = request.Content, - Author = author + //Author = author --> author from keycloak }; var result = await _dbContext.Articles.AddAsync(article); @@ -48,6 +48,7 @@ public async Task> Post(ArticleRequest request) return Created("v1/Articles", result.Entity); } + */ [HttpGet] [AllowAnonymous] @@ -55,19 +56,14 @@ public async Task> Post(ArticleRequest request) [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task>> Get() { - var result = _dbContext.Articles.Include(a => a.Author).Select( + var result = _dbContext.Articles.Select( article => new ArticleResponse { Id = article.Id, Created = article.Created, Title = article.Title, Content = article.Content, - Author = new UserViewModel - { - Id = article.Author.Id, - UserName = article.Author.UserName, - Email = article.Author.Email - } + AuthorId = article.AuthorId }).ToList(); return Ok(result); @@ -80,17 +76,15 @@ public async Task>> Get() [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> Delete([FromRoute] string id) { - var articol = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); - if (articol is null) - { - return NotFound("Article not found!"); - } + var articol = await _dbContext.Articles.FirstOrDefaultAsync(entity => entity.Id == id); + if (articol is null) return NotFound("Article not found!"); var result = _dbContext.Articles.Remove(articol); await _dbContext.SaveChangesAsync(); return Ok(result.Entity); } + [HttpPatch("Change author/{id}")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] @@ -98,20 +92,19 @@ public async Task> Delete([FromRoute] string id) [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> ChangeAuthor([FromRoute] string id, [FromBody] string authorid) { - var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); - if (article is null) - { - return NotFound("Article not found!"); - } + var article = await _dbContext.Articles.FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) return NotFound("Article not found!"); - var author = await _dbContext.Users.FirstOrDefaultAsync(entity => entity.Id == authorid); + /* check from keycloak if (author is null) { return NotFound("Author not found!"); } + */ - article.Author = author; + article.AuthorId = authorid; article.Updated = DateTime.UtcNow; + await _dbContext.SaveChangesAsync(); return Ok(new ArticleResponse { @@ -119,15 +112,10 @@ public async Task> ChangeAuthor([FromRoute] string Created = article.Created, Title = article.Title, Content = article.Content, - Author = new UserViewModel - { - Id = article.Author.Id, - UserName = article.Author.UserName, - Email = article.Author.Email - } + AuthorId = article.AuthorId }); } - + [HttpPatch("Change content/{id}")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] @@ -135,12 +123,9 @@ public async Task> ChangeAuthor([FromRoute] string [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> ChangeContent([FromRoute] string id, [FromBody] string content) { - var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); - if (article is null) - { - return NotFound("Article not found!"); - } - + var article = await _dbContext.Articles.FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) return NotFound("Article not found!"); + article.Content = content; article.Updated = DateTime.UtcNow; await _dbContext.SaveChangesAsync(); @@ -150,15 +135,10 @@ public async Task> ChangeContent([FromRoute] strin Created = article.Created, Title = article.Title, Content = article.Content, - Author = new UserViewModel - { - Id = article.Author.Id, - UserName = article.Author.UserName, - Email = article.Author.Email - } + AuthorId = article.AuthorId }); } - + [HttpPatch("Change title/{id}")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] @@ -166,12 +146,9 @@ public async Task> ChangeContent([FromRoute] strin [ProducesResponseType(StatusCodes.Status401Unauthorized)] public async Task> ChangeTitle([FromRoute] string id, [FromBody] string title) { - var article = await _dbContext.Articles.Include(a => a.Author).FirstOrDefaultAsync(entity => entity.Id == id); - if (article is null) - { - return NotFound("Article not found!"); - } - + var article = await _dbContext.Articles.FirstOrDefaultAsync(entity => entity.Id == id); + if (article is null) return NotFound("Article not found!"); + article.Title = title; article.Updated = DateTime.UtcNow; await _dbContext.SaveChangesAsync(); @@ -181,12 +158,7 @@ public async Task> ChangeTitle([FromRoute] string Created = article.Created, Title = article.Title, Content = article.Content, - Author = new UserViewModel - { - Id = article.Author.Id, - UserName = article.Author.UserName, - Email = article.Author.Email - } + AuthorId = article.AuthorId }); } } \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleModel.cs b/GdscBackend/Features/Articles/ArticleModel.cs index 3923aa4..1df76aa 100644 --- a/GdscBackend/Features/Articles/ArticleModel.cs +++ b/GdscBackend/Features/Articles/ArticleModel.cs @@ -1,5 +1,4 @@ -using GdscBackend.Auth; -using GdscBackend.Common.Models; +using GdscBackend.Common.Models; namespace GdscBackend.Features.Articles; @@ -9,5 +8,5 @@ public class ArticleModel : Model public string Content { get; set; } - public User? Author { get; set; } + public string AuthorId { get; set; } } \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleResponse.cs b/GdscBackend/Features/Articles/ArticleResponse.cs index ae54769..4588747 100644 --- a/GdscBackend/Features/Articles/ArticleResponse.cs +++ b/GdscBackend/Features/Articles/ArticleResponse.cs @@ -1,6 +1,4 @@ -using GdscBackend.Auth; - -namespace GdscBackend.Features.Articles; +namespace GdscBackend.Features.Articles; public class ArticleResponse { @@ -11,5 +9,5 @@ public class ArticleResponse public string Content { get; set; } - public UserViewModel Author { get; set; } + public string AuthorId { get; set; } } \ No newline at end of file diff --git a/GdscBackend/GdscBackend.csproj b/GdscBackend/GdscBackend.csproj index 6898e8b..fea9f1a 100644 --- a/GdscBackend/GdscBackend.csproj +++ b/GdscBackend/GdscBackend.csproj @@ -8,24 +8,27 @@ - - - - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + - + + diff --git a/GdscBackend/Migrations/20231029144626_keycloak.Designer.cs b/GdscBackend/Migrations/20231029144626_keycloak.Designer.cs new file mode 100644 index 0000000..a897cdb --- /dev/null +++ b/GdscBackend/Migrations/20231029144626_keycloak.Designer.cs @@ -0,0 +1,444 @@ +// +using System; +using GdscBackend.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231029144626_keycloak")] + partial class keycloak + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AuthorId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Content") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("GdscBackend.Features.Contacts.ContactModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Contacts"); + }); + + modelBuilder.Entity("GdscBackend.Features.Events.EventModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("End") + .HasColumnType("timestamp with time zone"); + + b.Property("ImageId") + .HasColumnType("text"); + + b.Property("Start") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("GdscBackend.Features.Examples.ExampleModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Number") + .HasColumnType("integer"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Examples"); + }); + + modelBuilder.Entity("GdscBackend.Features.FIles.FileModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Extension") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("bigint"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("GdscBackend.Features.Faqs.FaqModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Answer") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Question") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Faqs"); + }); + + modelBuilder.Entity("GdscBackend.Features.Members.MemberModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Members"); + }); + + modelBuilder.Entity("GdscBackend.Features.MenuItems.MenuItemModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("MenuItems"); + }); + + modelBuilder.Entity("GdscBackend.Features.Pages.PageModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("isPublished") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Pages"); + }); + + modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("RedirectTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("Redirects"); + }); + + modelBuilder.Entity("GdscBackend.Features.Settings.SettingModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("GdscBackend.Features.Teams.TeamModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Teams"); + }); + + modelBuilder.Entity("GdscBackend.Features.Technologies.TechnologyModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Icon") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Technologies"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.Property("MembersId") + .HasColumnType("text"); + + b.Property("TeamsId") + .HasColumnType("text"); + + b.HasKey("MembersId", "TeamsId"); + + b.HasIndex("TeamsId"); + + b.ToTable("MemberModelTeamModel"); + }); + + modelBuilder.Entity("GdscBackend.Features.Events.EventModel", b => + { + b.HasOne("GdscBackend.Features.FIles.FileModel", "Image") + .WithMany() + .HasForeignKey("ImageId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("MemberModelTeamModel", b => + { + b.HasOne("GdscBackend.Features.Members.MemberModel", null) + .WithMany() + .HasForeignKey("MembersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GdscBackend.Features.Teams.TeamModel", null) + .WithMany() + .HasForeignKey("TeamsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GdscBackend/Migrations/20231029144626_keycloak.cs b/GdscBackend/Migrations/20231029144626_keycloak.cs new file mode 100644 index 0000000..a955896 --- /dev/null +++ b/GdscBackend/Migrations/20231029144626_keycloak.cs @@ -0,0 +1,261 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace gdscwebbackend.Migrations +{ + /// + public partial class keycloak : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Articles_AspNetUsers_AuthorId", + table: "Articles"); + + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + + migrationBuilder.DropIndex( + name: "IX_Articles_AuthorId", + table: "Articles"); + + migrationBuilder.AlterColumn( + name: "AuthorId", + table: "Articles", + type: "text", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "text", + oldNullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "AuthorId", + table: "Articles", + type: "text", + nullable: true, + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + ConcurrencyStamp = table.Column(type: "text", nullable: true), + Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "text", nullable: false), + AccessFailedCount = table.Column(type: "integer", nullable: false), + ConcurrencyStamp = table.Column(type: "text", nullable: true), + Email = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "boolean", nullable: false), + LockoutEnabled = table.Column(type: "boolean", nullable: false), + LockoutEnd = table.Column(type: "timestamp with time zone", nullable: true), + NormalizedEmail = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), + PasswordHash = table.Column(type: "text", nullable: true), + PhoneNumber = table.Column(type: "text", nullable: true), + PhoneNumberConfirmed = table.Column(type: "boolean", nullable: false), + SecurityStamp = table.Column(type: "text", nullable: true), + TwoFactorEnabled = table.Column(type: "boolean", nullable: false), + UserName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true), + RoleId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClaimType = table.Column(type: "text", nullable: true), + ClaimValue = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "text", nullable: false), + ProviderKey = table.Column(type: "text", nullable: false), + ProviderDisplayName = table.Column(type: "text", nullable: true), + UserId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "text", nullable: false), + RoleId = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "text", nullable: false), + LoginProvider = table.Column(type: "text", nullable: false), + Name = table.Column(type: "text", nullable: false), + Value = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Articles_AuthorId", + table: "Articles", + column: "AuthorId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + + migrationBuilder.AddForeignKey( + name: "FK_Articles_AspNetUsers_AuthorId", + table: "Articles", + column: "AuthorId", + principalTable: "AspNetUsers", + principalColumn: "Id"); + } + } +} diff --git a/GdscBackend/Migrations/AppDbContextModelSnapshot.cs b/GdscBackend/Migrations/AppDbContextModelSnapshot.cs index c5266d5..d0d4e90 100644 --- a/GdscBackend/Migrations/AppDbContextModelSnapshot.cs +++ b/GdscBackend/Migrations/AppDbContextModelSnapshot.cs @@ -22,102 +22,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("GdscBackend.Auth.Role", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("GdscBackend.Auth.User", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("AccessFailedCount") - .HasColumnType("integer"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PasswordHash") - .HasColumnType("text"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property("SecurityStamp") - .HasColumnType("text"); - - b.Property("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => { b.Property("Id") .HasColumnType("text"); b.Property("AuthorId") + .IsRequired() .HasColumnType("text"); b.Property("Content") @@ -136,39 +47,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("AuthorId"); - b.ToTable("Articles"); }); - modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Path") - .IsRequired() - .HasColumnType("text"); - - b.Property("RedirectTo") - .IsRequired() - .HasColumnType("text"); - - b.Property("Updated") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("Path") - .IsUnique(); - - b.ToTable("Redirects"); - }); - - modelBuilder.Entity("GdscBackend.Models.ContactModel", b => + modelBuilder.Entity("GdscBackend.Features.Contacts.ContactModel", b => { b.Property("Id") .HasColumnType("text"); @@ -200,7 +82,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Contacts"); }); - modelBuilder.Entity("GdscBackend.Models.EventModel", b => + modelBuilder.Entity("GdscBackend.Features.Events.EventModel", b => { b.Property("Id") .HasColumnType("text"); @@ -235,7 +117,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Events"); }); - modelBuilder.Entity("GdscBackend.Models.ExampleModel", b => + modelBuilder.Entity("GdscBackend.Features.Examples.ExampleModel", b => { b.Property("Id") .HasColumnType("text"); @@ -261,62 +143,62 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Examples"); }); - modelBuilder.Entity("GdscBackend.Models.FaqModel", b => + modelBuilder.Entity("GdscBackend.Features.FIles.FileModel", b => { b.Property("Id") .HasColumnType("text"); - b.Property("Answer") + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Extension") .IsRequired() .HasColumnType("text"); - b.Property("Created") - .HasColumnType("timestamp with time zone"); + b.Property("Name") + .IsRequired() + .HasColumnType("text"); - b.Property("Question") + b.Property("Path") .IsRequired() .HasColumnType("text"); + b.Property("Size") + .HasColumnType("bigint"); + b.Property("Updated") .HasColumnType("timestamp with time zone"); b.HasKey("Id"); - b.ToTable("Faqs"); + b.ToTable("Files"); }); - modelBuilder.Entity("GdscBackend.Models.FileModel", b => + modelBuilder.Entity("GdscBackend.Features.Faqs.FaqModel", b => { b.Property("Id") .HasColumnType("text"); - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Extension") + b.Property("Answer") .IsRequired() .HasColumnType("text"); - b.Property("Name") - .IsRequired() - .HasColumnType("text"); + b.Property("Created") + .HasColumnType("timestamp with time zone"); - b.Property("Path") + b.Property("Question") .IsRequired() .HasColumnType("text"); - b.Property("Size") - .HasColumnType("bigint"); - b.Property("Updated") .HasColumnType("timestamp with time zone"); b.HasKey("Id"); - b.ToTable("Files"); + b.ToTable("Faqs"); }); - modelBuilder.Entity("GdscBackend.Models.MemberModel", b => + modelBuilder.Entity("GdscBackend.Features.Members.MemberModel", b => { b.Property("Id") .HasColumnType("text"); @@ -340,7 +222,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Members"); }); - modelBuilder.Entity("GdscBackend.Models.MenuItemModel", b => + modelBuilder.Entity("GdscBackend.Features.MenuItems.MenuItemModel", b => { b.Property("Id") .HasColumnType("text"); @@ -367,7 +249,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("MenuItems"); }); - modelBuilder.Entity("GdscBackend.Models.PageModel", b => + modelBuilder.Entity("GdscBackend.Features.Pages.PageModel", b => { b.Property("Id") .HasColumnType("text"); @@ -406,7 +288,34 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Pages"); }); - modelBuilder.Entity("GdscBackend.Models.SettingModel", b => + modelBuilder.Entity("GdscBackend.Features.Redirects.RedirectModel", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text"); + + b.Property("RedirectTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Path") + .IsUnique(); + + b.ToTable("Redirects"); + }); + + modelBuilder.Entity("GdscBackend.Features.Settings.SettingModel", b => { b.Property("Id") .HasColumnType("text"); @@ -440,7 +349,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Settings"); }); - modelBuilder.Entity("GdscBackend.Models.TeamModel", b => + modelBuilder.Entity("GdscBackend.Features.Teams.TeamModel", b => { b.Property("Id") .HasColumnType("text"); @@ -460,7 +369,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Teams"); }); - modelBuilder.Entity("GdscBackend.Models.TechnologyModel", b => + modelBuilder.Entity("GdscBackend.Features.Technologies.TechnologyModel", b => { b.Property("Id") .HasColumnType("text"); @@ -503,124 +412,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("MemberModelTeamModel"); }); - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + modelBuilder.Entity("GdscBackend.Features.Events.EventModel", b => { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("ProviderKey") - .HasColumnType("text"); - - b.Property("ProviderDisplayName") - .HasColumnType("text"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("RoleId") - .HasColumnType("text"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("GdscBackend.Features.Articles.ArticleModel", b => - { - b.HasOne("GdscBackend.Auth.User", "Author") - .WithMany() - .HasForeignKey("AuthorId"); - - b.Navigation("Author"); - }); - - modelBuilder.Entity("GdscBackend.Models.EventModel", b => - { - b.HasOne("GdscBackend.Models.FileModel", "Image") + b.HasOne("GdscBackend.Features.FIles.FileModel", "Image") .WithMany() .HasForeignKey("ImageId"); @@ -629,69 +423,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("MemberModelTeamModel", b => { - b.HasOne("GdscBackend.Models.MemberModel", null) + b.HasOne("GdscBackend.Features.Members.MemberModel", null) .WithMany() .HasForeignKey("MembersId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("GdscBackend.Models.TeamModel", null) + b.HasOne("GdscBackend.Features.Teams.TeamModel", null) .WithMany() .HasForeignKey("TeamsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("GdscBackend.Auth.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("GdscBackend.Auth.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("GdscBackend.Auth.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("GdscBackend.Auth.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("GdscBackend.Auth.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("GdscBackend.Auth.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); #pragma warning restore 612, 618 } } diff --git a/GdscBackend/Program.cs b/GdscBackend/Program.cs index 641251e..b9d1167 100644 --- a/GdscBackend/Program.cs +++ b/GdscBackend/Program.cs @@ -1,14 +1,11 @@ -using System.Text; -using GdscBackend.Auth; using GdscBackend.Database; using GdscBackend.Swagger; using GdscBackend.Utils; using GdscBackend.Utils.Mappers; using GdscBackend.Utils.Services; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Identity; +using Keycloak.AuthServices.Authentication; +using Keycloak.AuthServices.Common; using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); var services = builder.Services; @@ -24,35 +21,17 @@ policy.AllowAnyHeader(); })); services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); -services.AddSwaggerConfiguration(); -services.AddIdentity(options => - { - options.Password.RequireDigit = false; - options.Password.RequiredLength = 8; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); -services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.SaveToken = true; - options.RequireHttpsMetadata = false; - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidateAudience = true, - ValidAudience = configuration["JWT:ValidAudience"], - ValidIssuer = configuration["JWT:ValidIssuer"], - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"])) - }; - }); + +var keycloakOptions = configuration + .GetRequiredSection(ConfigurationConstants.ConfigurationPrefix) + .Get(); + +if (keycloakOptions is null) throw new Exception("keyCloakAdminConfiguartions is null"); + +services.AddSwaggerConfiguration(keycloakOptions); + +services.AddKeycloakAuthentication(configuration); + services.AddTransient(); services.AddTransient(); @@ -63,10 +42,7 @@ app.MigrateIfNeeded(); -if (builder.Environment.IsDevelopment()) -{ - app.UseDeveloperExceptionPage(); -} +if (builder.Environment.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseCors("EnableAll"); @@ -79,4 +55,4 @@ app.MapControllers(); -app.Run(); +app.Run(); \ No newline at end of file diff --git a/GdscBackend/Swagger/ConfigureSwaggerOptions.cs b/GdscBackend/Swagger/ConfigureSwaggerOptions.cs index 44f3b0a..4adcd1d 100644 --- a/GdscBackend/Swagger/ConfigureSwaggerOptions.cs +++ b/GdscBackend/Swagger/ConfigureSwaggerOptions.cs @@ -24,33 +24,5 @@ public void Configure(SwaggerGenOptions options) Title = $"GDSC UPT API v{description.ApiVersion}", Version = description.ApiVersion.ToString() }); - - // To Enable authorization using Swagger (JWT) - options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme - { - Name = "Authorization", - Type = SecuritySchemeType.ApiKey, - Scheme = "Bearer", - BearerFormat = "JWT", - In = ParameterLocation.Header, - Description = - "Enter 'Bearer' [space] and then your valid token in the text input below.\r\n\r\n" + - "Example: \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\"" - }); - - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, - Id = "Bearer" - } - }, - Array.Empty() - } - }); } -} +} \ No newline at end of file diff --git a/GdscBackend/Swagger/SwaggerConfiguration.cs b/GdscBackend/Swagger/SwaggerConfiguration.cs index d9199a9..33cc7e6 100644 --- a/GdscBackend/Swagger/SwaggerConfiguration.cs +++ b/GdscBackend/Swagger/SwaggerConfiguration.cs @@ -1,14 +1,55 @@ +using Keycloak.AuthServices.Common; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; namespace GdscBackend.Swagger; public static class SwaggerConfiguration { - public static IServiceCollection AddSwaggerConfiguration(this IServiceCollection services) + public static IServiceCollection AddSwaggerConfiguration( + this IServiceCollection services, + KeycloakInstallationOptions keycloakOption) { + var url = $"{keycloakOption.KeycloakUrlRealm}/protocol/openid-connect"; + + var openIdConnectSecurityScheme = new OpenApiSecurityScheme + { + Name = "Authorization", + Scheme = JwtBearerDefaults.AuthenticationScheme, + Type = SecuritySchemeType.OAuth2, + In = ParameterLocation.Header, + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri(url + "/auth"), + TokenUrl = new Uri(url + "/token"), + Scopes = new Dictionary { { "openid", "openid" }, { "profile", "profile" } } + } + } + }; + + var securityRequirements = new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Name = "Authorization", + In = ParameterLocation.Header, + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "gdsc" + } + }, + Array.Empty() + } + }; + services.AddApiVersioning(config => { config.DefaultApiVersion = new ApiVersion(1, 0); @@ -20,6 +61,10 @@ public static IServiceCollection AddSwaggerConfiguration(this IServiceCollection services.AddVersionedApiExplorer(options => options.GroupNameFormat = "'v'V"); services.AddTransient, ConfigureSwaggerOptions>(); - return services.AddSwaggerGen(); + return services.AddSwaggerGen(option => + { + option.AddSecurityDefinition("gdsc", openIdConnectSecurityScheme); + option.AddSecurityRequirement(securityRequirements); + }); } -} +} \ No newline at end of file diff --git a/GdscBackend/appsettings.json b/GdscBackend/appsettings.json index 654148c..bc0c4f2 100644 --- a/GdscBackend/appsettings.json +++ b/GdscBackend/appsettings.json @@ -22,5 +22,13 @@ }, "Webhooks": { "Contact": "https://discord.com/api/webhooks/854767318348595230/5D3zX05rGHcgEJ13Ckf7sYP9Vihki86vNl1lqFWXACVG6DKZ9tIA8jtW6w6AtlB4Y2eJ" + }, + "Keycloak": { + "realm": "", + "auth-server-url": "", + "ssl-required": "none", + "resource": "test-client", + "verify-token-audience": false, + "confidential-port": 0 } } From 3dc88e8610aa08bdd98fe2628411772ae26d7c57 Mon Sep 17 00:00:00 2001 From: Balan Veniamin Date: Sun, 29 Oct 2023 18:11:34 +0200 Subject: [PATCH 6/8] added authorization --- GdscBackend.sln.DotSettings | 2 ++ .../Features/Articles/ArticleController.cs | 2 +- .../Features/Contacts/ContactController.cs | 11 +++------ .../Features/Events/EventsController.cs | 5 ++-- GdscBackend/Features/FIles/FilesController.cs | 3 ++- GdscBackend/Features/Faqs/FaqsController.cs | 3 ++- .../Features/Members/MembersController.cs | 3 ++- .../Features/MenuItems/MenuItemsController.cs | 3 ++- GdscBackend/Features/Pages/PagesController.cs | 3 ++- .../Features/Redirects/RedirectsController.cs | 23 +++++-------------- .../Features/Settings/SettingsController.cs | 3 ++- GdscBackend/Features/Teams/TeamsController.cs | 3 ++- GdscBackend/GdscBackend.csproj | 1 + GdscBackend/Program.cs | 4 ++++ GdscBackend/Utils/AuthorizeConstants.cs | 6 +++++ 15 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 GdscBackend.sln.DotSettings create mode 100644 GdscBackend/Utils/AuthorizeConstants.cs diff --git a/GdscBackend.sln.DotSettings b/GdscBackend.sln.DotSettings new file mode 100644 index 0000000..e2b76d2 --- /dev/null +++ b/GdscBackend.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/GdscBackend/Features/Articles/ArticleController.cs b/GdscBackend/Features/Articles/ArticleController.cs index 9138d64..2929629 100644 --- a/GdscBackend/Features/Articles/ArticleController.cs +++ b/GdscBackend/Features/Articles/ArticleController.cs @@ -7,7 +7,7 @@ namespace GdscBackend.Features.Articles; [ApiController] [ApiVersion("1")] -[Authorize] +[Authorize("CoreTeam")] [Route("v1/Articles")] public class ArticleController : ControllerBase { diff --git a/GdscBackend/Features/Contacts/ContactController.cs b/GdscBackend/Features/Contacts/ContactController.cs index 4bb8188..e668008 100644 --- a/GdscBackend/Features/Contacts/ContactController.cs +++ b/GdscBackend/Features/Contacts/ContactController.cs @@ -10,8 +10,8 @@ namespace GdscBackend.Features.Contacts; [ApiController] -[Authorize(Roles = "admin")] -[ApiVersion("1")] +[Authorize(AuthorizeConstants.CoreTeam)] +[ApiVersion("v1")] [Route("v1/contact")] public class ContactController : ControllerBase { @@ -35,15 +35,10 @@ public ContactController(IRepository repository, IMapper mapper, I [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task>> Post(ContactRequest entity) { - if (entity is null) - { - return BadRequest(new ErrorViewModel { Message = "Request has no body" }); - } + if (entity is null) return BadRequest(new ErrorViewModel { Message = "Request has no body" }); if (!new EmailAddressAttribute().IsValid(entity.Email)) - { return BadRequest(new ErrorViewModel { Message = "Invalid email provided" }); - } var newEntity = await _repository.AddAsync(Map(entity)); diff --git a/GdscBackend/Features/Events/EventsController.cs b/GdscBackend/Features/Events/EventsController.cs index 2474f99..8a53327 100644 --- a/GdscBackend/Features/Events/EventsController.cs +++ b/GdscBackend/Features/Events/EventsController.cs @@ -2,6 +2,7 @@ using AutoMapper; using GdscBackend.Database; using GdscBackend.Features.FIles; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -9,7 +10,7 @@ namespace GdscBackend.Features.Events; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/events")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] @@ -30,7 +31,7 @@ public EventsController(IRepository repository, IMapper mapper, /*<<<<<<< HEAD ======= - + >>>>>>> dev*/ [HttpPost] [ProducesResponseType(StatusCodes.Status201Created)] diff --git a/GdscBackend/Features/FIles/FilesController.cs b/GdscBackend/Features/FIles/FilesController.cs index 204d7c5..04410d2 100644 --- a/GdscBackend/Features/FIles/FilesController.cs +++ b/GdscBackend/Features/FIles/FilesController.cs @@ -1,4 +1,5 @@ using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -6,7 +7,7 @@ namespace GdscBackend.Features.FIles; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/files")] public class FilesController : ControllerBase { diff --git a/GdscBackend/Features/Faqs/FaqsController.cs b/GdscBackend/Features/Faqs/FaqsController.cs index ee4b34c..697843e 100644 --- a/GdscBackend/Features/Faqs/FaqsController.cs +++ b/GdscBackend/Features/Faqs/FaqsController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,7 +9,7 @@ namespace GdscBackend.Features.Faqs; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/faqs")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] diff --git a/GdscBackend/Features/Members/MembersController.cs b/GdscBackend/Features/Members/MembersController.cs index 500e931..aec84db 100644 --- a/GdscBackend/Features/Members/MembersController.cs +++ b/GdscBackend/Features/Members/MembersController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using GdscBackend.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -9,7 +10,7 @@ namespace GdscBackend.Features.Members; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/members")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] diff --git a/GdscBackend/Features/MenuItems/MenuItemsController.cs b/GdscBackend/Features/MenuItems/MenuItemsController.cs index 5506dfd..0c0b1b4 100644 --- a/GdscBackend/Features/MenuItems/MenuItemsController.cs +++ b/GdscBackend/Features/MenuItems/MenuItemsController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,7 +9,7 @@ namespace GdscBackend.Features.MenuItems; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/menu-items")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] diff --git a/GdscBackend/Features/Pages/PagesController.cs b/GdscBackend/Features/Pages/PagesController.cs index 07ab488..0a237ce 100644 --- a/GdscBackend/Features/Pages/PagesController.cs +++ b/GdscBackend/Features/Pages/PagesController.cs @@ -1,5 +1,6 @@ using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using GdscBackend.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,7 +9,7 @@ namespace GdscBackend.Features.Pages; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/pages")] public class PagesController : ControllerBase { diff --git a/GdscBackend/Features/Redirects/RedirectsController.cs b/GdscBackend/Features/Redirects/RedirectsController.cs index d5e20b1..8d1c311 100644 --- a/GdscBackend/Features/Redirects/RedirectsController.cs +++ b/GdscBackend/Features/Redirects/RedirectsController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,7 +9,7 @@ namespace GdscBackend.Features.Redirects; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/redirects")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] @@ -30,10 +31,7 @@ public async Task Get() { var dict = new Dictionary(); var redirects = (await _repository.GetAsync()).ToList(); - foreach (var redirectModel in redirects) - { - dict.Add(redirectModel.Path, redirectModel.RedirectTo); - } + foreach (var redirectModel in redirects) dict.Add(redirectModel.Path, redirectModel.RedirectTo); return Ok(dict); } @@ -67,16 +65,10 @@ public async Task> Delete([FromRoute] string path { var all = await _repository.GetAsync(); var newEntity = all.FirstOrDefault(entity => entity.Path == path); - if (newEntity is null) - { - return NotFound(); - } + if (newEntity is null) return NotFound(); var result = await _repository.DeleteAsync(newEntity.Id); - if (result is null) - { - return NotFound(); - } + if (result is null) return NotFound(); return Ok(result); } @@ -90,10 +82,7 @@ public async Task> Update([FromRoute] string path { var all = await _repository.GetAsync(); var newEntity = all.FirstOrDefault(entity => entity.Path == path); - if (newEntity is null) - { - return NotFound(); - } + if (newEntity is null) return NotFound(); newEntity.Path = request.Path; newEntity.RedirectTo = request.RedirectTo; diff --git a/GdscBackend/Features/Settings/SettingsController.cs b/GdscBackend/Features/Settings/SettingsController.cs index 9e3217b..6135eb9 100644 --- a/GdscBackend/Features/Settings/SettingsController.cs +++ b/GdscBackend/Features/Settings/SettingsController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -9,7 +10,7 @@ namespace GdscBackend.Features.Settings; // This marks this controller as a public one that can be called from the internet [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] // This sets the URL that we can enter to call the controller's methods // ex: https://localhost:5000/v1/examples [Route("v1/settings")] diff --git a/GdscBackend/Features/Teams/TeamsController.cs b/GdscBackend/Features/Teams/TeamsController.cs index 6a7739d..228fe5d 100644 --- a/GdscBackend/Features/Teams/TeamsController.cs +++ b/GdscBackend/Features/Teams/TeamsController.cs @@ -1,6 +1,7 @@ using System.Net.Mime; using AutoMapper; using GdscBackend.Database; +using GdscBackend.Utils; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -8,7 +9,7 @@ namespace GdscBackend.Features.Teams; [ApiController] [ApiVersion("1")] -[Authorize(Roles = "admin")] +[Authorize(AuthorizeConstants.CoreTeam)] [Route("v1/teams")] [Consumes(MediaTypeNames.Application.Json)] [Produces(MediaTypeNames.Application.Json)] diff --git a/GdscBackend/GdscBackend.csproj b/GdscBackend/GdscBackend.csproj index fea9f1a..d55156d 100644 --- a/GdscBackend/GdscBackend.csproj +++ b/GdscBackend/GdscBackend.csproj @@ -10,6 +10,7 @@ + diff --git a/GdscBackend/Program.cs b/GdscBackend/Program.cs index b9d1167..871ba4c 100644 --- a/GdscBackend/Program.cs +++ b/GdscBackend/Program.cs @@ -4,6 +4,7 @@ using GdscBackend.Utils.Mappers; using GdscBackend.Utils.Services; using Keycloak.AuthServices.Authentication; +using Keycloak.AuthServices.Authorization; using Keycloak.AuthServices.Common; using Microsoft.EntityFrameworkCore; @@ -31,6 +32,9 @@ services.AddSwaggerConfiguration(keycloakOptions); services.AddKeycloakAuthentication(configuration); +services.AddAuthorization( + o => o.AddPolicy(AuthorizeConstants.CoreTeam, b => { b.RequireRealmRoles("GDSC_CORE_TEAM"); })); +services.AddKeycloakAuthorization(configuration); services.AddTransient(); services.AddTransient(); diff --git a/GdscBackend/Utils/AuthorizeConstants.cs b/GdscBackend/Utils/AuthorizeConstants.cs new file mode 100644 index 0000000..1f4087e --- /dev/null +++ b/GdscBackend/Utils/AuthorizeConstants.cs @@ -0,0 +1,6 @@ +namespace GdscBackend.Utils; + +public static class AuthorizeConstants +{ + public const string CoreTeam = "CoreTeam"; +} \ No newline at end of file From 723dfcb0a580230732ddb7e5c7a9bb50bdc787b3 Mon Sep 17 00:00:00 2001 From: Balan Veniamin Date: Sun, 29 Oct 2023 18:24:52 +0200 Subject: [PATCH 7/8] small fixes --- .github/CODEOWNERS | 2 +- .github/workflows/main.yml | 2 +- Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 037754a..0a1fe82 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,4 +6,4 @@ # review when someone opens a pull request. -* @ad0bre +* @VeniaminBalan diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 018579d..67dd836 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: context: . secrets: GIT_AUTH_TOKEN=${{ secrets.CR_PAT }} push: true - tags: ghcr.io/dsc-upt/gdsc-backend-${{ env.BRANCH }}:latest + tags: ghcr.io/gdsc-upt/gdsc-backend-${{ env.BRANCH }}:latest deploy: needs: [ build ] diff --git a/Dockerfile b/Dockerfile index b49c948..f294414 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,4 +21,4 @@ RUN chmod +x /usr/bin/docker-entrypoint.sh ENTRYPOINT ["docker-entrypoint.sh"] # Link image with github repo -LABEL org.opencontainers.image.source=https://github.com/dsc-upt/gdsc-backend +LABEL org.opencontainers.image.source=https://github.com/gdsc-upt/gdsc-backend From 558ab390e1c0a464f1d55f55052b6eee94c177e8 Mon Sep 17 00:00:00 2001 From: Balan Veniamin Date: Sun, 29 Oct 2023 18:46:01 +0200 Subject: [PATCH 8/8] api version fixed --- GdscBackend/Features/Contacts/ContactController.cs | 2 +- GdscBackend/Features/Events/EventsController.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/GdscBackend/Features/Contacts/ContactController.cs b/GdscBackend/Features/Contacts/ContactController.cs index e668008..5094ae6 100644 --- a/GdscBackend/Features/Contacts/ContactController.cs +++ b/GdscBackend/Features/Contacts/ContactController.cs @@ -11,7 +11,7 @@ namespace GdscBackend.Features.Contacts; [ApiController] [Authorize(AuthorizeConstants.CoreTeam)] -[ApiVersion("v1")] +[ApiVersion("1")] [Route("v1/contact")] public class ContactController : ControllerBase { diff --git a/GdscBackend/Features/Events/EventsController.cs b/GdscBackend/Features/Events/EventsController.cs index 8a53327..6375049 100644 --- a/GdscBackend/Features/Events/EventsController.cs +++ b/GdscBackend/Features/Events/EventsController.cs @@ -28,11 +28,6 @@ public EventsController(IRepository repository, IMapper mapper, _filesRepository = filesRepository; } -/*<<<<<<< HEAD - -======= - ->>>>>>> dev*/ [HttpPost] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)]