diff --git a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs index 2bc911895..d6d047bf8 100644 --- a/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs +++ b/HwProj.APIGateway/HwProj.APIGateway.API/Controllers/CoursesController.cs @@ -304,6 +304,7 @@ private async Task ToCourseViewModel(CourseDTO course) Homeworks = course.Homeworks, IsCompleted = course.IsCompleted, IsOpen = course.IsOpen, + Description = course.Description, }; } } diff --git a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs index d17abd732..c84734035 100644 --- a/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs +++ b/HwProj.Common/HwProj.Models/CoursesService/ViewModels/CourseViewModels.cs @@ -16,6 +16,7 @@ public class CreateCourseViewModel public List StudentIDs { get; set; } = new List(); public bool FetchStudents { get; set; } [Required] public bool IsOpen { get; set; } + public string Description { get; set; } public long? BaseCourseId { get; set; } } @@ -30,6 +31,8 @@ public class UpdateCourseViewModel [Required] public bool IsOpen { get; set; } public bool IsCompleted { get; set; } + + public string Description { get; set; } } public class CourseDTO : CoursePreview @@ -50,6 +53,7 @@ public class CourseViewModel public string GroupName { get; set; } public bool IsOpen { get; set; } public bool IsCompleted { get; set; } + public string Description { get; set; } public AccountDataDto[] Mentors { get; set; } public AccountDataDto[] AcceptedStudents { get; set; } @@ -66,5 +70,6 @@ public class CoursePreview public bool IsCompleted { get; set; } public string[] MentorIds { get; set; } public long? TaskId { get; set; } + public string Description { get; set; } } } \ No newline at end of file diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs index 18503d91e..21956433b 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Controllers/CoursesController.cs @@ -122,14 +122,7 @@ public async Task DeleteCourse(long courseId) [ServiceFilter(typeof(CourseMentorOnlyAttribute))] public async Task UpdateCourse(long courseId, [FromBody] UpdateCourseViewModel courseViewModel) { - await _coursesService.UpdateAsync(courseId, new Course - { - Name = courseViewModel.Name, - GroupName = courseViewModel.GroupName, - IsCompleted = courseViewModel.IsCompleted, - IsOpen = courseViewModel.IsOpen - }); - + await _coursesService.UpdateAsync(courseId, courseViewModel); return Ok(); } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.Designer.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.Designer.cs new file mode 100644 index 000000000..a85d4a2c3 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.Designer.cs @@ -0,0 +1,344 @@ +// +using System; +using HwProj.CoursesService.API.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace HwProj.CoursesService.API.Migrations +{ + [DbContext(typeof(CourseContext))] + [Migration("20250507181748_CoursesDescriptions")] + partial class CoursesDescriptions + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Assignment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("MentorId"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Assignments"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Course", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupName"); + + b.Property("InviteCode"); + + b.Property("IsCompleted"); + + b.Property("IsOpen"); + + b.Property("MentorIds"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Courses"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseDescription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("Description"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("CoursesDescriptions"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("FilterJson"); + + b.HasKey("Id"); + + b.ToTable("CourseFilters"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseMate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("IsAccepted"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("CourseMates"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.GroupMate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupId"); + + b.Property("StudentId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasAlternateKey("GroupId", "StudentId"); + + b.ToTable("GroupMates"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Homework", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("DeadlineDate"); + + b.Property("Description"); + + b.Property("HasDeadline"); + + b.Property("IsDeadlineStrict"); + + b.Property("PublicationDate"); + + b.Property("Tags"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("Homeworks"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.HomeworkTask", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("DeadlineDate"); + + b.Property("Description"); + + b.Property("HasDeadline"); + + b.Property("HomeworkId"); + + b.Property("IsDeadlineStrict"); + + b.Property("MaxRating"); + + b.Property("PublicationDate"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("HomeworkId"); + + b.ToTable("Tasks"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.StudentCharacteristics", b => + { + b.Property("CourseMateId"); + + b.Property("Description"); + + b.Property("Tags"); + + b.HasKey("CourseMateId"); + + b.ToTable("StudentCharacteristics"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("GroupId"); + + b.Property("TaskId"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.ToTable("TasksModels"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Answer") + .HasMaxLength(1000); + + b.Property("IsPrivate"); + + b.Property("LecturerId"); + + b.Property("StudentId"); + + b.Property("TaskId"); + + b.Property("Text") + .HasMaxLength(1000); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Questions"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.UserToCourseFilter", b => + { + b.Property("CourseId"); + + b.Property("UserId"); + + b.Property("CourseFilterId"); + + b.HasKey("CourseId", "UserId"); + + b.HasIndex("CourseFilterId"); + + b.ToTable("UserToCourseFilters"); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Assignment", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("Assignments") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseMate", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("CourseMates") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.GroupMate", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Group") + .WithMany("GroupMates") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.Homework", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Course") + .WithMany("Homeworks") + .HasForeignKey("CourseId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.HomeworkTask", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Homework", "Homework") + .WithMany("Tasks") + .HasForeignKey("HomeworkId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.StudentCharacteristics", b => + { + b.HasOne("HwProj.CoursesService.API.Models.CourseMate") + .WithOne("Characteristics") + .HasForeignKey("HwProj.CoursesService.API.Models.StudentCharacteristics", "CourseMateId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.TaskModel", b => + { + b.HasOne("HwProj.CoursesService.API.Models.Group") + .WithMany("Tasks") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("HwProj.CoursesService.API.Models.UserToCourseFilter", b => + { + b.HasOne("HwProj.CoursesService.API.Models.CourseFilter", "CourseFilter") + .WithMany() + .HasForeignKey("CourseFilterId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.cs new file mode 100644 index 000000000..790614b2f --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/20250507181748_CoursesDescriptions.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace HwProj.CoursesService.API.Migrations +{ + public partial class CoursesDescriptions : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CoursesDescriptions", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), + Description = table.Column(nullable: true), + CourseId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CoursesDescriptions", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_CoursesDescriptions_CourseId", + table: "CoursesDescriptions", + column: "CourseId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CoursesDescriptions"); + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs index 736fb0058..0502c4f82 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Migrations/CourseContextModelSnapshot.cs @@ -61,6 +61,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Courses"); }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseDescription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CourseId"); + + b.Property("Description"); + + b.HasKey("Id"); + + b.HasIndex("CourseId"); + + b.ToTable("CoursesDescriptions"); + }); + modelBuilder.Entity("HwProj.CoursesService.API.Models.CourseFilter", b => { b.Property("Id") diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs index ca089ff93..c27493d5c 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseContext.cs @@ -15,6 +15,7 @@ public sealed class CourseContext : DbContext public DbSet CourseFilters { get; set; } public DbSet UserToCourseFilters { get; set; } public DbSet Questions { get; set; } + public DbSet CoursesDescriptions { get; set; } public CourseContext(DbContextOptions options) : base(options) @@ -27,6 +28,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasIndex(a => a.CourseId); modelBuilder.Entity().HasKey(u => new { u.CourseId, u.UserId }); modelBuilder.Entity().HasIndex(t => t.TaskId); + modelBuilder.Entity().HasIndex(cd => cd.CourseId); } } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseDescription.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseDescription.cs new file mode 100644 index 000000000..1a46c7838 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Models/CourseDescription.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using HwProj.Repositories; + +namespace HwProj.CoursesService.API.Models +{ + public class CourseDescription : IEntity + { + [Key] public long Id { get; set; } + + public string Description { get; set; } + + public long CourseId { get; set; } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/DescriptionsRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/DescriptionsRepository.cs new file mode 100644 index 000000000..e662e7112 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/DescriptionsRepository.cs @@ -0,0 +1,40 @@ +using HwProj.CoursesService.API.Models; +using HwProj.Repositories; +using Microsoft.EntityFrameworkCore; +using System.Threading.Tasks; + +namespace HwProj.CoursesService.API.Repositories +{ + public class DescriptionsRepository : CrudRepository, IDescriptionsRepository + { + public DescriptionsRepository(CourseContext context) + : base(context) + { + } + + public async Task GetDescriptionAsync(long courseId) => + await Context.Set() + .AsNoTracking() + .FirstOrDefaultAsync(c => c.Id == courseId); + + public async Task ChangeOrAdd(long courseId, string description) + { + var courseDescription = await Context.Set().FirstOrDefaultAsync(cd => cd.CourseId == courseId); + + if (courseDescription is null) + { + await Context.AddAsync(new CourseDescription + { + CourseId = courseId, + Description = description, + }); + } + else + { + courseDescription.Description = description; + } + + await Context.SaveChangesAsync(); + } + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IDescriptionsRepository.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IDescriptionsRepository.cs new file mode 100644 index 000000000..285e48311 --- /dev/null +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Repositories/IDescriptionsRepository.cs @@ -0,0 +1,14 @@ +using HwProj.CoursesService.API.Models; +using HwProj.Repositories; +using System.Linq; +using System.Threading.Tasks; + +namespace HwProj.CoursesService.API.Repositories +{ + public interface IDescriptionsRepository : ICrudRepository + { + public Task GetDescriptionAsync(long courseId); + + public Task ChangeOrAdd(long courseId, string description); + } +} diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterService.cs index b47139ee0..9049d36bb 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CourseFilterService.cs @@ -167,7 +167,8 @@ private CourseDTO ApplyFilterInternal(CourseDTO courseDto, CourseFilter? courseF Homeworks = filter.HomeworkIds.Any() ? courseDto.Homeworks.Where(hw => filter.HomeworkIds.Contains(hw.Id)).ToArray() - : courseDto.Homeworks + : courseDto.Homeworks, + Description = courseDto.Description, }; } } diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs index 7fd03cdb0..0cbab8264 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/CoursesService.cs @@ -16,6 +16,7 @@ using HwProj.Models.Roles; using HwProj.Utils.Authorization; using Microsoft.EntityFrameworkCore; +using Z.EntityFramework.Plus; namespace HwProj.CoursesService.API.Services { @@ -29,6 +30,7 @@ public class CoursesService : ICoursesService private readonly IAuthServiceClient _authServiceClient; private readonly IGroupsRepository _groupsRepository; private readonly ICourseFilterService _courseFilterService; + private readonly IDescriptionsRepository _descriptionRepository; private readonly CourseContext _context; public CoursesService(ICoursesRepository coursesRepository, @@ -39,6 +41,7 @@ public CoursesService(ICoursesRepository coursesRepository, IAuthServiceClient authServiceClient, IGroupsRepository groupsRepository, ICourseFilterService courseFilterService, + IDescriptionsRepository descriptionRepository, CourseContext context) { _coursesRepository = coursesRepository; @@ -49,6 +52,7 @@ public CoursesService(ICoursesRepository coursesRepository, _authServiceClient = authServiceClient; _groupsRepository = groupsRepository; _courseFilterService = courseFilterService; + _descriptionRepository = descriptionRepository; _context = context; } @@ -83,6 +87,8 @@ public async Task GetAllAsync() StudentsIds = g.GroupMates.Select(t => t.StudentId).ToArray() }).ToArray(); + courseDto.Description = (await _descriptionRepository.GetDescriptionAsync(id))?.Description ?? string.Empty; + Console.WriteLine(courseDto.Description == string.Empty ? "asdf" : "1234"); var result = userId == string.Empty ? courseDto : await _courseFilterService.ApplyFilter(courseDto, userId); return result; } @@ -104,11 +110,11 @@ public async Task AddAsync(CreateCourseViewModel courseViewModel, courseTemplate.Homeworks = baseCourse.Homeworks.Select(h => h.ToHomeworkTemplate()).ToList(); } - return await AddFromTemplateAsync(courseTemplate, courseViewModel.StudentIDs, mentorId); + return await AddFromTemplateAsync(courseTemplate, courseViewModel.StudentIDs, mentorId, courseViewModel.Description); } public async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List studentIds, - string mentorId) + string mentorId, string description) { using var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); @@ -117,6 +123,12 @@ public async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List course.InviteCode = Guid.NewGuid().ToString(); var courseId = await _coursesRepository.AddAsync(course); + await _descriptionRepository.AddAsync(new CourseDescription + { + CourseId = courseId, + Description = description, + }); + var homeworks = courseTemplate.Homeworks.Select(hwTemplate => hwTemplate.ToHomework(courseId)); var homeworkIds = await _homeworksRepository.AddRangeAsync(homeworks); @@ -154,9 +166,10 @@ public async Task AddFromTemplateAsync(CourseTemplate courseTemplate, List public async Task DeleteAsync(long id) { await _coursesRepository.DeleteAsync(id); + await _descriptionRepository.DeleteAsync(id); } - public async Task UpdateAsync(long courseId, Course updated) + public async Task UpdateAsync(long courseId, UpdateCourseViewModel updated) { await _coursesRepository.UpdateAsync(courseId, c => new Course { @@ -165,6 +178,8 @@ public async Task UpdateAsync(long courseId, Course updated) IsCompleted = updated.IsCompleted, IsOpen = updated.IsOpen }); + + await _descriptionRepository.ChangeOrAdd(courseId, updated.Description); } public async Task AddStudentAsync(long courseId, string studentId) diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs index 57ae4c023..02d94a984 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Services/ICoursesService.cs @@ -14,7 +14,7 @@ public interface ICoursesService Task GetByTaskAsync(long taskId, string userId); Task AddAsync(CreateCourseViewModel courseViewModel, CourseDTO? baseCourse, string mentorId); Task DeleteAsync(long id); - Task UpdateAsync(long courseId, Course updated); + Task UpdateAsync(long courseId, UpdateCourseViewModel updated); Task AddStudentAsync(long courseId, string studentId); Task AcceptCourseMateAsync(long courseId, string studentId); Task RejectCourseMateAsync(long courseId, string studentId); diff --git a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs index c1a6b9957..ffbb66d65 100644 --- a/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs +++ b/HwProj.CoursesService/HwProj.CoursesService.API/Startup.cs @@ -33,6 +33,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/hwproj.front/src/api/api.ts b/hwproj.front/src/api/api.ts index f8f840ec9..e2aa97e34 100644 --- a/hwproj.front/src/api/api.ts +++ b/hwproj.front/src/api/api.ts @@ -458,6 +458,12 @@ export interface CourseViewModel { * @memberof CourseViewModel */ isCompleted?: boolean; + /** + * + * @type {string} + * @memberof CourseViewModel + */ + description?: string; /** * * @type {Array} @@ -519,6 +525,12 @@ export interface CreateCourseViewModel { * @memberof CreateCourseViewModel */ isOpen: boolean; + /** + * + * @type {string} + * @memberof CourseViewModel + */ + description?: string; /** * * @type {number} @@ -2440,6 +2452,12 @@ export interface UpdateCourseViewModel { * @memberof UpdateCourseViewModel */ isCompleted?: boolean; + /** + * + * @type {string} + * @memberof CourseViewModel + */ + description?: string; } /** * diff --git a/hwproj.front/src/components/Common/MarkdownEditor.tsx b/hwproj.front/src/components/Common/MarkdownEditor.tsx index 71864698b..006031965 100644 --- a/hwproj.front/src/components/Common/MarkdownEditor.tsx +++ b/hwproj.front/src/components/Common/MarkdownEditor.tsx @@ -13,6 +13,7 @@ interface MarkdownEditorProps { label: string; maxHeight?: number; height?: number; + style?: React.CSSProperties; value: string; onChange: (value: string) => void; } @@ -63,6 +64,7 @@ const MarkdownEditor: FC = (props) => { }} > = ({state, setState}) => { @@ -51,6 +52,20 @@ const AddCourseInfo: FC = ({state, setState}) => { onChange={handleCourseNameChange} /> + + { + setState((prevState) => ({ + ...prevState, + description: value + })) + }} + /> + { const showStatsTab = isCourseMentor || isAcceptedStudent const showApplicationsTab = isCourseMentor + const hasAccessToMaterials = course.isOpen || isCourseMentor || isAcceptedStudent + const changeTab = (newTab: string) => { if (isAcceptableTabValue(newTab) && newTab !== pageState.tabValue) { if (newTab === "stats" && !showStatsTab) return; @@ -293,6 +298,17 @@ const Course: React.FC = () => { + {!hasAccessToMaterials && !course.isOpen && + + + О курсе + + + + + + + } {!isSignedInCourse && !isMentor && !isAcceptedStudent && (