diff --git a/Entities/Contracts/AppMainStruct.cs b/Entities/Contracts/AppMainStruct.cs index 6039c28..32f73c8 100644 --- a/Entities/Contracts/AppMainStruct.cs +++ b/Entities/Contracts/AppMainStruct.cs @@ -43,18 +43,11 @@ namespace Entities.Contracts veryHard } - public enum QuestionType : byte + public enum TypeNameType : byte { - Unknown = 0, - Spelling, // 拼写 - Pronunciation, // 给带点字选择正确读音 - WordFormation, // 组词 - FillInTheBlanks, // 选词填空 / 补充词语 - SentenceDictation, // 默写句子 - SentenceRewriting, // 仿句 / 改写句子 - ReadingComprehension, // 阅读理解 - Composition // 作文 - + Subject = 0, + QuestionType = 1, + ExamType = 2, } public enum SubjectAreaEnum : byte @@ -90,7 +83,7 @@ namespace Entities.Contracts ComputerScience // 计算机科学 } - public enum AssignmentStructType : byte + public enum ExamStructType : byte { [Display(Name = "根节点", Description = "根")] Root, @@ -105,26 +98,12 @@ namespace Entities.Contracts [Display(Name = "选项", Description = "选")] Option } - - public enum ExamType : byte + + public enum UserRoles { - [Display(Name = "期中考试", Description = "中")] - MidtermExam, - - [Display(Name = "期末考试", Description = "末")] - FinalExam, - - [Display(Name = "月考", Description = "月")] - MonthlyExam, - - [Display(Name = "周考", Description = "周")] - WeeklyExam, - - [Display(Name = "平时测试", Description = "平")] - DailyTest, - - [Display(Name = "AI测试", Description = "AI")] - AITest, + Student, + Teacher, + Admin } public enum SubmissionStatus diff --git a/Entities/Contracts/AssignmentClass.cs b/Entities/Contracts/AssignmentClass.cs deleted file mode 100644 index 1fc69df..0000000 --- a/Entities/Contracts/AssignmentClass.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.Contracts -{ - [Table("assignment_class")] - public class AssignmentClass - { - [Key] - [Column("assignment_id", Order = 0)] - [ForeignKey("Assignment")] - public Guid AssignmentId { get; set; } - - [Key] - [Column("class_id", Order = 1)] - [ForeignKey("Class")] - public Guid ClassId { get; set; } - - [Column("assigned_at")] - public DateTime AssignedAt { get; set; } - - [Column("deleted")] - public bool IsDeleted { get; set; } - - // Navigation Properties - public Assignment Assignment { get; set; } - public Class Class { get; set; } - - - } -} diff --git a/Entities/Contracts/AssignmentQuestion.cs b/Entities/Contracts/AssignmentQuestion.cs deleted file mode 100644 index 9c4f81e..0000000 --- a/Entities/Contracts/AssignmentQuestion.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Entities.DTO; - -namespace Entities.Contracts -{ - [Table("assignment_questions")] - public class AssignmentQuestion - { - [Key] - [Column("id")] - public Guid Id { get; set; } - - [Column("question_id")] - public Guid? QuestionId { get; set; } - - [Column("title")] - [MaxLength(1024)] - public string? Title { get; set; } - - [Column("description")] - public Guid? QuestionContextId { get; set; } - - [Required] - [Column("question_number")] - public byte Index { get; set; } - - [Column("sequence")] - public string Sequence { get; set; } = string.Empty; - - [Column("parent_question_group_id")] - public Guid? ParentAssignmentQuestionId { get; set; } - - [Column("group_state")] - public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question; - - public QuestionType Type { get; set; } = QuestionType.Unknown; - - [Column("created_at")] - public DateTime CreatedAt { get; set; } - - [Column("score")] - public float? Score { get; set; } - - public bool BCorrect { get; set; } - - [Column("deleted")] - public bool IsDeleted { get; set; } - - - public Question? Question { get; set; } - public Assignment? Assignment { get; set; } - - [ForeignKey(nameof(QuestionContextId))] - public QuestionContext? QuestionContext { get; set; } - - public ICollection SubmissionDetails { get; set; } - - [ForeignKey(nameof(ParentAssignmentQuestionId))] - public AssignmentQuestion? ParentAssignmentQuestion { get; set; } - public ICollection ChildrenAssignmentQuestion { get; set; } = new List(); - - - public AssignmentQuestion() - { - Id = Guid.NewGuid(); - SubmissionDetails = new HashSet(); - } - } -} diff --git a/Entities/Contracts/Class.cs b/Entities/Contracts/Class.cs index 68d1269..da5b4f8 100644 --- a/Entities/Contracts/Class.cs +++ b/Entities/Contracts/Class.cs @@ -10,19 +10,24 @@ namespace Entities.Contracts { [Key] [Column("class_id")] - public int ClassId { get; set; } + public Guid Id { get; set; } [Column("grade_id")] - public int GradeId { get; set; } - public Grade Grade { get; set; } + public Guid GradeId { get; set; } + [ForeignKey(nameof(GradeId))] + public virtual Grade Grade { get; set; } + + [Column("index")] + public byte Index { get; set; } [Column("class_name")] [MaxLength(30)] public string ClassName { get; set; } [Column("head_teacher_id")] - public int? HeadTeacherId { get; set; } - public User HeadTeacher { get; set; } + public Guid? HeadTeacherId { get; set; } + [ForeignKey(nameof(HeadTeacherId))] + public virtual User HeadTeacher { get; set; } [Column("created_at")] public DateTime CreatedAt { get; set; } @@ -34,15 +39,20 @@ namespace Entities.Contracts public bool IsDeleted { get; set; } // Navigation Properties - public ICollection ClassTeachers { get; set; } - public ICollection ClassStudents { get; set; } - public ICollection AssignmentClasses { get; set; } + + [NotMapped] + public ICollection Techers => ClassUsers.Where(cu => cu.User.Role == UserRoles.Teacher).ToList(); + + [NotMapped] + public ICollection Students => ClassUsers.Where(cu => cu.User.Role == UserRoles.Student).ToList(); + + [InverseProperty(nameof(ClassUser.Class))] + public virtual ICollection ClassUsers { get; set; } public Class() { - ClassStudents = new HashSet(); - ClassTeachers = new HashSet(); - AssignmentClasses = new HashSet(); + Id = Guid.NewGuid(); + ClassUsers = new HashSet(); CreatedAt = DateTime.Now; UpdatedAt = DateTime.Now; } diff --git a/Entities/Contracts/ClassStudent.cs b/Entities/Contracts/ClassStudent.cs deleted file mode 100644 index 6351794..0000000 --- a/Entities/Contracts/ClassStudent.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.Contracts -{ - [Table("class_student")] - public class ClassStudent - { - [Key] - [Column("class_id", Order = 0)] - [ForeignKey("Class")] - public Guid ClassId { get; set; } - - [Key] - [Column("student_id", Order = 1)] - [ForeignKey("Student")] - public Guid StudentId { get; set; } - - [Column("enrollment_date")] - public DateTime EnrollmentDate { get; set; } - - [Column("deleted")] - public bool IsDeleted { get; set; } - - // Navigation Properties - public Class Class { get; set; } - public User Student { get; set; } - } -} diff --git a/Entities/Contracts/ClassTeacher.cs b/Entities/Contracts/ClassTeacher.cs deleted file mode 100644 index 5b1e5ab..0000000 --- a/Entities/Contracts/ClassTeacher.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.Contracts -{ - [Table("class_teachers")] - public class ClassTeacher - { - [Key] - [Column("class_id")] - public Guid ClassId { get; set; } - [ForeignKey(nameof(ClassId))] - public Class Class { get; set; } - - [Key] - [Column("teacher_id")] - public Guid TeacherId { get; set; } - [ForeignKey(nameof(TeacherId))] - public User Teacher { get; set; } - - [Column("subject_taught")] - public SubjectAreaEnum SubjectTaught { get; set; } - } -} diff --git a/Entities/Contracts/ClassUser.cs b/Entities/Contracts/ClassUser.cs new file mode 100644 index 0000000..19b6757 --- /dev/null +++ b/Entities/Contracts/ClassUser.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace Entities.Contracts +{ + /// + /// 班级用户关联实体类 + /// 表示用户与班级之间的多对多关系 + /// + [Table("class_user")] + [PrimaryKey(nameof(ClassId), nameof(UserId))] + public class ClassUser + { + /// + /// 班级ID,复合主键的一部分,外键 + /// 关联到Class表中的班级 + /// + [Key] + [Column("class_id", Order = 0)] + public Guid ClassId { get; set; } + [ForeignKey(nameof(ClassId))] + public virtual Class Class { get; set; } + /// + /// 用户ID,复合主键的一部分,外键 + /// 关联到User表中的用户用户 + /// + [Key] + [Column("student_id", Order = 1)] + public Guid UserId { get; set; } + [ForeignKey(nameof(UserId))] + public virtual User User { get; set; } + + /// + /// 入学日期 + /// 记录用户加入该班级的日期 + /// + [Column("enrollment_date")] + public DateTime EnrollmentDate { get; set; } + + /// + /// 是否已删除 + /// 软删除标记,true表示已删除 + /// + [Column("deleted")] + public bool IsDeleted { get; set; } + + + + } +} diff --git a/Entities/Contracts/Assignment.cs b/Entities/Contracts/Exam.cs similarity index 56% rename from Entities/Contracts/Assignment.cs rename to Entities/Contracts/Exam.cs index 1dbc9f7..6600574 100644 --- a/Entities/Contracts/Assignment.cs +++ b/Entities/Contracts/Exam.cs @@ -9,8 +9,8 @@ using Entities.DTO; namespace Entities.Contracts { - [Table("assignments")] - public class Assignment + [Table("exams")] + public class Exam { [Key] [Column("id")] @@ -24,12 +24,26 @@ namespace Entities.Contracts [Column("description")] public string Description { get; set; } - [Column("subject_area")] - public SubjectAreaEnum SubjectArea { get; set; } + [Column("subject_id")] + public Guid SubjectId { get; set; } + [ForeignKey(nameof(SubjectId))] + public virtual Subject Subject { get; set; } [Required] [Column("exam_struct_id")] + [ForeignKey(nameof(ExamStruct))] public Guid ExamStructId { get; set; } + public virtual ExamQuestion ExamStruct { get; set; } + + [Column("exam_type_id")] + public Guid ExamTypeId { get; set; } + [ForeignKey(nameof(ExamTypeId))] + public virtual ExamType ExamType { get; set; } + + [Column("created_by")] + public Guid CreatorId { get; set; } + [ForeignKey(nameof(CreatorId))] + public virtual User Creator { get; set; } [Required] [Column("due_date")] @@ -41,13 +55,9 @@ namespace Entities.Contracts [Column("score")] public float Score { get; set; } + [Column("name")] public string Name { get; set; } = string.Empty; - public ExamType ExamType { get; set; } = ExamType.DailyTest; - - [Column("created_by")] - public Guid CreatorId { get; set; } - [Column("created_at")] public DateTime CreatedAt { get; set; } @@ -57,61 +67,53 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } = false; - // Navigation Properties - [ForeignKey(nameof(CreatorId))] - public User Creator { get; set; } - public ICollection AssignmentClasses { get; set; } + [InverseProperty(nameof(ExamAttachment.Exam))] + public virtual ICollection ExamAttachments { get; set; } + [InverseProperty(nameof(Submission.Exam))] + public virtual ICollection Submissions { get; set; } - [ForeignKey(nameof(ExamStructId))] - public AssignmentQuestion ExamStruct { get; set; } - public ICollection AssignmentAttachments { get; set; } - public ICollection Submissions { get; set; } - - public Assignment() + public Exam() { Id = Guid.NewGuid(); + ExamAttachments = new HashSet(); Submissions = new HashSet(); - AssignmentClasses = new HashSet(); - AssignmentAttachments = new HashSet(); } } - public static class AssignmentExt + public static class examExt { - public static Submission ConvertToSubmission(this Assignment assignment, Guid studentId, Guid GraderId) + public static Submission ConvertToSubmission(this Exam exam, Guid studentId, Guid GraderId, Guid classId) { - if (assignment == null) return new Submission(); + if (exam == null) return new Submission(); var submission = new Submission(); submission.StudentId = studentId; submission.SubmissionTime = DateTime.Now; submission.Status = SubmissionStatus.Pending; submission.GraderId = GraderId; - submission.AssignmentId = assignment.Id; - - ConvertExamSturctToSubmissionDetails(assignment.ExamStruct, studentId, submission.SubmissionDetails); + submission.ExamId = exam.Id; + submission.ClassId = classId; + ConvertExamSturctToSubmissionDetails(exam.ExamStruct, studentId, submission.SubmissionDetails); return submission; } - public static void ConvertExamSturctToSubmissionDetails(AssignmentQuestion examStruct, Guid studentId, ICollection submissions) + public static void ConvertExamSturctToSubmissionDetails(ExamQuestion examStruct, Guid studentId, ICollection submissions) { if (examStruct == null) return; submissions.Add(new SubmissionDetail { StudentId = studentId, - AssignmentQuestionId = examStruct.Id, - IsCorrect = true, + ExamQuestionId = examStruct.Id, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now, - Status = SubmissionStatus.Pending, }); - examStruct.ChildrenAssignmentQuestion?.ToList().ForEach(s => + examStruct.ChildExamQuestions?.ToList().ForEach(s => { ConvertExamSturctToSubmissionDetails(s, studentId, submissions); }); diff --git a/Entities/Contracts/AssignmentAttachment.cs b/Entities/Contracts/ExamAttachment.cs similarity index 72% rename from Entities/Contracts/AssignmentAttachment.cs rename to Entities/Contracts/ExamAttachment.cs index a745c01..217b348 100644 --- a/Entities/Contracts/AssignmentAttachment.cs +++ b/Entities/Contracts/ExamAttachment.cs @@ -9,17 +9,18 @@ using System.Diagnostics.CodeAnalysis; namespace Entities.Contracts { - [Table("assignment_attachments")] - public class AssignmentAttachment + [Table("exam_attachments")] + public class ExamAttachment { [Key] [Column("id")] public Guid Id { get; set; } [Required] - [Column("assignment_id")] - [ForeignKey("Assignment")] - public Guid AssignmentId { get; set; } + [Column("exam_id")] + public Guid ExamId { get; set; } + [ForeignKey(nameof(ExamId))] + public virtual Exam Exam { get; set; } [Required] [Column("file_path")] @@ -37,10 +38,7 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } - // Navigation Properties - public Assignment Assignment { get; set; } - - public AssignmentAttachment() + public ExamAttachment() { Id = Guid.NewGuid(); } diff --git a/Entities/Contracts/ExamQuestion.cs b/Entities/Contracts/ExamQuestion.cs new file mode 100644 index 0000000..ed903c9 --- /dev/null +++ b/Entities/Contracts/ExamQuestion.cs @@ -0,0 +1,71 @@ +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using Entities.DTO; + +namespace Entities.Contracts +{ + [Table("exam_questions")] + public class ExamQuestion + { + [Key] + [Column("id")] + public Guid Id { get; set; } + + [Column("title")] + [MaxLength(1024)] + public string? Title { get; set; } + + [Column("question_id")] + public Guid? QuestionId { get; set; } + [ForeignKey(nameof(QuestionId))] + public virtual Question? Question { get; set; } + + [Column("description")] + public Guid? QuestionContextId { get; set; } + [ForeignKey(nameof(QuestionContextId))] + public virtual QuestionContext? QuestionContext { get; set; } + + [Required] + [Column("question_number")] + public byte Index { get; set; } + + [Column("sequence")] + public string Sequence { get; set; } = string.Empty; + + [Column("parent_question_group_id")] + public Guid? ParentExamQuestionId { get; set; } + [ForeignKey(nameof(ParentExamQuestionId))] + public virtual ExamQuestion? ParentExamQuestion { get; set; } + + public Guid QuestionTypeId { get;set; } + [ForeignKey(nameof(QuestionTypeId))] + public virtual QuestionType Type { get; set; } + + [Column("created_at")] + public DateTime CreatedAt { get; set; } + + [Column("exam_struct_type")] + public ExamStructType ExamStructType { get; set; } + + [Column("score")] + public float? Score { get; set; } + + [Column("deleted")] + public bool IsDeleted { get; set; } + + + public virtual Exam? Exam { get; set; } + + + [InverseProperty(nameof(SubmissionDetail.ExamQuestion))] + public virtual ICollection SubmissionDetails { get; set; } + [InverseProperty(nameof(ParentExamQuestion))] + public virtual ICollection ChildExamQuestions { get; set; } = new List(); + + public ExamQuestion() + { + Id = Guid.NewGuid(); + SubmissionDetails = new HashSet(); + } + } +} diff --git a/Entities/Contracts/ExamType.cs b/Entities/Contracts/ExamType.cs new file mode 100644 index 0000000..ce1f596 --- /dev/null +++ b/Entities/Contracts/ExamType.cs @@ -0,0 +1,30 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities.Contracts +{ + [Table("exam_type")] + public class ExamType + { + [Key] + [Column("id")] + public Guid Id { get; set; } + + [Column("name")] + [MaxLength(20)] + public string Name { get; set; } + + [Column("description")] + public string Description { get; set; } + + [InverseProperty(nameof(Exam.ExamType))] + public virtual ICollection Exams { get; set; } + + public ExamType() + { + Id = Guid.NewGuid(); + Exams = new HashSet(); + } + } +} diff --git a/Entities/Contracts/Global.cs b/Entities/Contracts/Global.cs deleted file mode 100644 index 03c5425..0000000 --- a/Entities/Contracts/Global.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.Contracts -{ - [Table("global")] - public class Global - { - [Key] - [Column("id")] - public Guid Id { get; set; } = Guid.NewGuid(); - - public SubjectAreaEnum Area { get; set; } - - public string Info { get; set; } = string.Empty; - } - - -} diff --git a/Entities/Contracts/Grade.cs b/Entities/Contracts/Grade.cs index a98be1e..5a6c415 100644 --- a/Entities/Contracts/Grade.cs +++ b/Entities/Contracts/Grade.cs @@ -10,24 +10,25 @@ namespace Entities.Contracts { [Key] [Column("grade_id")] - public int GradeId { get; set; } + public Guid Id { get; set; } [Column("school_id")] - public int SchoolId { get; set; } - public School School { get; set; } + public Guid SchoolId { get; set; } + public virtual School School { get; set; } [Column("grade_name")] [MaxLength(20)] public string GradeName { get; set; } [Column("grade_level")] - public int GradeLevel { get; set; } + public byte GradeLevel { get; set; } - // Navigation Properties - public ICollection Classes { get; set; } + [InverseProperty(nameof(Class.Grade))] + public virtual ICollection Classes { get; set; } public Grade() { + Id = Guid.NewGuid(); Classes = new HashSet(); } } diff --git a/Entities/Contracts/Question.cs b/Entities/Contracts/Question.cs index c824eeb..377a9bd 100644 --- a/Entities/Contracts/Question.cs +++ b/Entities/Contracts/Question.cs @@ -24,35 +24,38 @@ namespace Entities.Contracts [MaxLength(65535)] public string? Answer { get; set; } - - [Required] [Column("type")] - [MaxLength(20)] - public QuestionType Type { get; set; } = QuestionType.Unknown; - - [Column("difficulty_level")] - [MaxLength(10)] - public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy; + public Guid QuestioTypeId { get; set; } + [ForeignKey(nameof(QuestioTypeId))] + public virtual QuestionType QuestionType { get; set; } [Column("subject_area")] - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - - public string QType { get; set; } = string.Empty; - - [Column("options")] - public string? Options { get; set; } + public Guid SubjectId { get; set; } + [ForeignKey(nameof(SubjectId))] + public virtual Subject Subject { get; set; } [Column("key_point")] public Guid? KeyPointId { get; set; } + [ForeignKey(nameof(KeyPointId))] + public virtual KeyPoint? KeyPoint { get; set; } [Column("lesson")] public Guid? LessonId { get; set; } + [ForeignKey(nameof(LessonId))] + public virtual Lesson? Lesson { get; set; } - - [Required] - [Column("created_by")] - public Guid CreatorId { get; set; } + //[Required] + //[Column("created_by")] + //public Guid CreatorId { get; set; } + //[ForeignKey(nameof(CreatorId))] + //public virtual User Creator { get; set; } + + //[Column("difficulty_level")] + //public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy; + + [Column("options")] + public string? Options { get; set; } [Column("created_at")] public DateTime CreatedAt { get; set; } @@ -63,22 +66,13 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } - - // Navigation Properties - [ForeignKey(nameof(CreatorId))] - public User Creator { get; set; } - - [ForeignKey(nameof(KeyPointId))] - public KeyPoint? KeyPoint { get; set; } - [ForeignKey(nameof(LessonId))] - public Lesson? Lesson { get; set; } - - public ICollection? AssignmentQuestions { get; set; } + [InverseProperty(nameof(ExamQuestion.Question))] + public virtual ICollection? ExamQuestions { get; set; } public Question() { Id = Guid.NewGuid(); - AssignmentQuestions = new HashSet(); + ExamQuestions = new HashSet(); } } diff --git a/Entities/Contracts/QuestionContext.cs b/Entities/Contracts/QuestionContext.cs index d78adba..10522c0 100644 --- a/Entities/Contracts/QuestionContext.cs +++ b/Entities/Contracts/QuestionContext.cs @@ -13,13 +13,13 @@ namespace Entities.Contracts public string Description { get; set; } = string.Empty; - [InverseProperty(nameof(AssignmentQuestion.QuestionContext))] - public ICollection? Questions { get; set; } = new List(); + [InverseProperty(nameof(ExamQuestion.QuestionContext))] + public virtual ICollection? Questions { get; set; } = new List(); public QuestionContext() { - Questions = new HashSet(); + Questions = new HashSet(); } } } diff --git a/Entities/Contracts/QuestionType.cs b/Entities/Contracts/QuestionType.cs new file mode 100644 index 0000000..66121e2 --- /dev/null +++ b/Entities/Contracts/QuestionType.cs @@ -0,0 +1,40 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities.Contracts +{ + [Table("question_types")] + public class QuestionType + { + [Key] + [Column("id")] + public Guid Id { get; set; } + + [Column("name")] + [MaxLength(20)] + public string Name { get; set; } + + [Column("subject_id")] + public Guid SubjectId { get; set; } + [ForeignKey(nameof(SubjectId))] + public virtual Subject Subject { get; set; } + + [Column("description")] + public string Description { get; set; } + + [Column("score_rule")] + [MaxLength(20)] + public string ScoreRule { get; set; } + + [InverseProperty(nameof(Question.QuestionType))] + public virtual IEnumerable Questions { get; set; } + + public QuestionType() + { + Id = Guid.NewGuid(); + + Questions = new HashSet(); + } + } +} diff --git a/Entities/Contracts/School.cs b/Entities/Contracts/School.cs index d6358f8..9cc05a8 100644 --- a/Entities/Contracts/School.cs +++ b/Entities/Contracts/School.cs @@ -9,8 +9,8 @@ namespace Entities.Contracts public class School { [Key] - [Column("school_id")] - public int SchoolId { get; set; } + [Column("id")] + public Guid Id { get; set; } [Column("school_name")] [MaxLength(50)] @@ -23,11 +23,12 @@ namespace Entities.Contracts [Column("create_time")] public DateTime CreateTime { get; set; } - // Navigation Properties - public ICollection Grades { get; set; } + [InverseProperty(nameof(Grade.School))] + public virtual ICollection Grades { get; set; } public School() { + Id = Guid.NewGuid(); Grades = new HashSet(); CreateTime = DateTime.Now; } diff --git a/Entities/Contracts/Subject.cs b/Entities/Contracts/Subject.cs new file mode 100644 index 0000000..68793de --- /dev/null +++ b/Entities/Contracts/Subject.cs @@ -0,0 +1,36 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities.Contracts +{ + [Table("subjects")] + public class Subject + { + [Key] + [Column("id")] + public Guid Id { get; set; } + + [Column("name")] + [MaxLength(20)] + public string Name { get; set; } + + [Column("description")] + public string Description { get; set; } + + [InverseProperty(nameof(QuestionType.Subject))] + public virtual IEnumerable QuestionTypes { get; set; } + + [InverseProperty(nameof(Question.Subject))] + public virtual IEnumerable Questions { get; set; } + + [InverseProperty(nameof(User.TeachSubject))] + public virtual IEnumerable SubjectTeachers { get; set; } + public Subject() + { + Id = Guid.NewGuid(); + QuestionTypes = new HashSet(); + Questions = new HashSet(); + } + } +} diff --git a/Entities/Contracts/Submission.cs b/Entities/Contracts/Submission.cs index 2412f02..1acebc0 100644 --- a/Entities/Contracts/Submission.cs +++ b/Entities/Contracts/Submission.cs @@ -17,18 +17,30 @@ namespace Entities.Contracts public Guid Id { get; set; } [Required] - [Column("assignment_id")] - [ForeignKey("Assignment")] - public Guid AssignmentId { get; set; } + [Column("exam_id")] + public Guid ExamId { get; set; } + [ForeignKey(nameof(ExamId))] + public virtual Exam Exam { get; set; } [Required] [Column("student_id")] - [ForeignKey("Student")] public Guid StudentId { get; set; } + [ForeignKey(nameof(StudentId))] + public virtual User Student { get; set; } + + [Column("graded_by")] + public Guid? GraderId { get; set; } + [ForeignKey(nameof(GraderId))] + public virtual User Grader { get; set; } + + [Column("class_id")] + public Guid ClassId { get; set; } + [ForeignKey(nameof(ClassId))] + public virtual Class Class { get; set; } [Required] [Column("attempt_number")] - public byte AttemptNumber { get; set; } + public byte AttemptNumber { get; set; } // 第几次提交 [Column("submission_time")] public DateTime SubmissionTime { get; set; } @@ -39,31 +51,36 @@ namespace Entities.Contracts [Column("overall_feedback")] public string? OverallFeedback { get; set; } - [Column("graded_by")] - [ForeignKey("Grader")] - public Guid? GraderId { get; set; } - [Column("graded_at")] public DateTime? GradedAt { get; set; } - [Column("deleted")] - public bool IsDeleted { get; set; } - - public byte TotalQuesNum { get; set; } - - public byte ErrorQuesNum { get; set; } - - public byte TotalScore { get; set; } - [Required] [Column("status")] public SubmissionStatus Status { get; set; } + [Column("deleted")] + public bool IsDeleted { get; set; } // Navigation Properties - public Assignment Assignment { get; set; } - public User Student { get; set; } - public User Grader { get; set; } - public ICollection SubmissionDetails { get; set; } + + [NotMapped] + public int ErrorCount => SubmissionDetails.Where(sd => sd?.IsCorrect == false && sd.IsCorrect != null).Count(); + + [NotMapped] + public Dictionary ErrorQuestionTypeDistribution => SubmissionDetails + .Where(sd => sd?.IsCorrect == false) + .GroupBy(sd => sd.ExamQuestion.Type.Name) + .ToDictionary(g => g.Key, g => g.Count()); + + [NotMapped] + public Dictionary ErrorQuestionLessonDistribution => SubmissionDetails + .Where(sd => sd?.IsCorrect == false && sd.ExamQuestion.Question?.Lesson != null) + .GroupBy(sd => sd.ExamQuestion.Question.Lesson.Title) + .ToDictionary(g => g.Key, g => g.Count()); + + + + [InverseProperty(nameof(SubmissionDetail.Submission))] + public virtual ICollection SubmissionDetails { get; set; } public Submission() { diff --git a/Entities/Contracts/SubmissionDetail.cs b/Entities/Contracts/SubmissionDetail.cs index 3a8812d..b736018 100644 --- a/Entities/Contracts/SubmissionDetail.cs +++ b/Entities/Contracts/SubmissionDetail.cs @@ -20,15 +20,20 @@ namespace Entities.Contracts [Column("submission_id")] [ForeignKey("Submission")] public Guid SubmissionId { get; set; } + [ForeignKey(nameof(SubmissionId))] + public virtual Submission Submission { get; set; } [Required] [Column("student_id")] public Guid StudentId { get; set; } + [ForeignKey(nameof(StudentId))] + public virtual User Student { get; set; } [Required] - [Column("assignment_question_id")] - [ForeignKey("AssignmentQuestion")] - public Guid AssignmentQuestionId { get; set; } + [Column("exam_question_id")] + public Guid ExamQuestionId { get; set; } + [ForeignKey(nameof(ExamQuestionId))] + public virtual ExamQuestion ExamQuestion { get; set; } [Column("student_answer")] public string? StudentAnswer { get; set; } @@ -37,7 +42,7 @@ namespace Entities.Contracts public bool? IsCorrect { get; set; } [Column("points_awarded")] - public float? PointsAwarded { get; set; } // score + public float? PointsAwarded { get; set; } // 得分 [Column("teacher_feedback")] public string? TeacherFeedback { get; set; } @@ -51,20 +56,6 @@ namespace Entities.Contracts [Column("deleted")] public bool IsDeleted { get; set; } - [Required] - [Column("status")] - public SubmissionStatus Status { get; set; } - - - - [ForeignKey(nameof(StudentId))] - public User Student { get; set; } - - [ForeignKey(nameof(SubmissionId))] - public Submission Submission { get; set; } - - [ForeignKey(nameof(AssignmentQuestionId))] - public AssignmentQuestion AssignmentQuestion { get; set; } public SubmissionDetail() { diff --git a/Entities/Contracts/Textbook/KeyPoint.cs b/Entities/Contracts/Textbook/KeyPoint.cs index 4f58dae..06eb1ae 100644 --- a/Entities/Contracts/Textbook/KeyPoint.cs +++ b/Entities/Contracts/Textbook/KeyPoint.cs @@ -18,14 +18,14 @@ namespace Entities.Contracts public string Key { get; set; } = string.Empty; + [Required] public Guid LessonID { get; set; } - [ForeignKey(nameof(LessonID))] - public Lesson Lesson { get; set; } + public virtual Lesson Lesson { get; set; } - public ICollection Questions { get; set; } + public virtual ICollection Questions { get; set; } public KeyPoint() { diff --git a/Entities/Contracts/Textbook/Lesson.cs b/Entities/Contracts/Textbook/Lesson.cs index 339689a..21366a9 100644 --- a/Entities/Contracts/Textbook/Lesson.cs +++ b/Entities/Contracts/Textbook/Lesson.cs @@ -21,19 +21,19 @@ namespace Entities.Contracts [Required] public Guid TextbookID { get; set; } - - [ForeignKey(nameof(TextbookID))] - public Textbook Textbook { get; set; } + public virtual Textbook Textbook { get; set; } + + [InverseProperty(nameof(KeyPoint.Lesson))] - public ICollection? KeyPoints { get; set; } + public virtual ICollection? KeyPoints { get; set; } [InverseProperty(nameof(Question.Lesson))] - public ICollection? Questions { get; set; } + public virtual ICollection? Questions { get; set; } [InverseProperty(nameof(LessonQuestion.Lesson))] - public ICollection? LessonQuestions { get; set; } + public virtual ICollection? LessonQuestions { get; set; } diff --git a/Entities/Contracts/Textbook/LessonQuestion.cs b/Entities/Contracts/Textbook/LessonQuestion.cs index a498317..5c6d6fd 100644 --- a/Entities/Contracts/Textbook/LessonQuestion.cs +++ b/Entities/Contracts/Textbook/LessonQuestion.cs @@ -19,9 +19,9 @@ namespace Entities.Contracts [Required] public Guid LessonID { get; set; } - [ForeignKey(nameof(LessonID))] - public Lesson Lesson { get; set; } + public virtual Lesson Lesson { get; set; } + public LessonQuestion() { diff --git a/Entities/Contracts/Textbook/Textbook.cs b/Entities/Contracts/Textbook/Textbook.cs index 5764381..a6c9eb7 100644 --- a/Entities/Contracts/Textbook/Textbook.cs +++ b/Entities/Contracts/Textbook/Textbook.cs @@ -24,7 +24,7 @@ namespace Entities.Contracts public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; [InverseProperty(nameof(Lesson.Textbook))] - public ICollection Lessons { get; set; } + public virtual ICollection Lessons { get; set; } public Textbook() { diff --git a/Entities/Contracts/User.cs b/Entities/Contracts/User.cs index 87cfb3c..ed573ef 100644 --- a/Entities/Contracts/User.cs +++ b/Entities/Contracts/User.cs @@ -3,47 +3,57 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Entities.Contracts { - public enum UserRoles - { - Student, - Teacher, - Administrator - } public class User : IdentityUser { public string? RefreshToken { get; set; } + public DateTime? RefreshTokenExpiryTime { get; set; } - public string? Address { get; set; } + + public string? HomeAddress { get; set; } + public string? DisplayName { get; set; } - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; + + public UserRoles? Role { get; set; } + + public Guid? TeachSubjectId { get; set; } + [ForeignKey(nameof(TeachSubjectId))] + public virtual Subject? TeachSubject { get; set; } [Column("deleted")] public bool IsDeleted { get; set; } + + [InverseProperty(nameof(ClassUser.User))] + public virtual ICollection UserInjoinedClass { get; set; } - [InverseProperty(nameof(ClassTeacher.Teacher))] - public ICollection TaughtClassesLink { get; set; } - [InverseProperty(nameof(ClassStudent.Student))] - public ICollection EnrolledClassesLink { get; set; } + //[InverseProperty(nameof(Question.Creator))] + //public virtual ICollection CreatedQuestions { get; set; } + + [InverseProperty(nameof(Exam.Creator))] + public virtual ICollection CreatedExams { get; set; } + + [InverseProperty(nameof(SubmissionDetail.Student))] + public virtual ICollection SubmissionDetails { get; set; } + + [InverseProperty(nameof(Submission.Student))] + public virtual ICollection StudentSubmissions { get; set; } + + [InverseProperty(nameof(Submission.Grader))] + public virtual ICollection GradedSubmissions { get; set; } - public ICollection CreatedQuestions { get; set; } - public ICollection CreatedAssignments { get; set; } - public ICollection SubmissionDetails { get; set; } - public ICollection SubmissionsAsStudent { get; set; } - public ICollection GradedSubmissions { get; set; } public User() { Id = Guid.NewGuid(); SecurityStamp = Guid.NewGuid().ToString(); - CreatedQuestions = new HashSet(); - TaughtClassesLink = new HashSet(); - EnrolledClassesLink = new HashSet(); - CreatedAssignments = new HashSet(); + //CreatedQuestions = new HashSet(); + UserInjoinedClass = new HashSet(); + CreatedExams = new HashSet(); GradedSubmissions = new HashSet(); - SubmissionsAsStudent = new HashSet(); + StudentSubmissions = new HashSet(); + SubmissionDetails = new HashSet(); } } } diff --git a/Entities/DTO/ApiResponse.cs b/Entities/DTO/ApiResponse.cs index 234c81f..a78013b 100644 --- a/Entities/DTO/ApiResponse.cs +++ b/Entities/DTO/ApiResponse.cs @@ -1,4 +1,4 @@ -namespace TechHelper.Services +namespace Entities.DTO { public class ApiResponse { @@ -50,4 +50,4 @@ public object Result { get; set; } } -} \ No newline at end of file +} diff --git a/Entities/DTO/AssignmentDto.cs b/Entities/DTO/AssignmentDto.cs deleted file mode 100644 index fab94bf..0000000 --- a/Entities/DTO/AssignmentDto.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class AssignmentDto - { - public Guid Id { get; set; } = Guid.Empty; - public string Title { get; set; } = string.Empty; - public string Description { get; set; } = string.Empty; - - public byte TotalQuestions { get; set; } - public float Score { get; set; } = 0; - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - public DateTime CreatedAt { get; set; } - public DateTime UpdatedAt { get; set; } - public DateTime DueDate { get; set; } - public Guid CreatorId { get; set; } - - public string Name { get; set; } = string.Empty; - public ExamType ExamType { get; set; } = ExamType.DailyTest; - - public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto(); - } -} diff --git a/Entities/DTO/AssignmentQuestionDto.cs b/Entities/DTO/AssignmentQuestionDto.cs deleted file mode 100644 index d76f076..0000000 --- a/Entities/DTO/AssignmentQuestionDto.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class AssignmentQuestionDto - { - public Guid Id { get; set; } = Guid.Empty; - public string Title { get; set; } = string.Empty; - public QuestionContextDto? Description { get; set; } - - public byte Index { get; set; } = 0; - public float Score { get; set; } = 0; - public string Sequence { get; set; } = string.Empty; - public bool BCorrect { get; set; } = true; - public QuestionType Type { get; set; } = QuestionType.Unknown; - public string QType { get; set; } = string.Empty; - - public Layout Layout { get; set; } = Layout.horizontal; - public AssignmentStructType StructType { get; set; } = AssignmentStructType.Question; - - public AssignmentQuestionDto? ParentAssignmentQuestion { get; set; } - public List ChildrenAssignmentQuestion { get; set; } = new List(); - - public QuestionDto? Question { get; set; } - } - - -} diff --git a/Entities/DTO/AuthResponseDto.cs b/Entities/DTO/Authentication/AuthResponseDto.cs similarity index 100% rename from Entities/DTO/AuthResponseDto.cs rename to Entities/DTO/Authentication/AuthResponseDto.cs diff --git a/Entities/DTO/ForgotPasswordDto.cs b/Entities/DTO/Authentication/ForgotPasswordDto.cs similarity index 100% rename from Entities/DTO/ForgotPasswordDto.cs rename to Entities/DTO/Authentication/ForgotPasswordDto.cs diff --git a/Entities/DTO/RefreshTokenDto.cs b/Entities/DTO/Authentication/RefreshTokenDto.cs similarity index 100% rename from Entities/DTO/RefreshTokenDto.cs rename to Entities/DTO/Authentication/RefreshTokenDto.cs diff --git a/Entities/DTO/ResetPasswordDto.cs b/Entities/DTO/Authentication/ResetPasswordDto.cs similarity index 100% rename from Entities/DTO/ResetPasswordDto.cs rename to Entities/DTO/Authentication/ResetPasswordDto.cs diff --git a/Entities/DTO/ResetPasswordResponseDto.cs b/Entities/DTO/Authentication/ResetPasswordResponseDto.cs similarity index 100% rename from Entities/DTO/ResetPasswordResponseDto.cs rename to Entities/DTO/Authentication/ResetPasswordResponseDto.cs diff --git a/Entities/DTO/TwoFactorVerificationDto.cs b/Entities/DTO/Authentication/TwoFactorVerificationDto.cs similarity index 100% rename from Entities/DTO/TwoFactorVerificationDto.cs rename to Entities/DTO/Authentication/TwoFactorVerificationDto.cs diff --git a/Entities/DTO/UserForAuthenticationDto.cs b/Entities/DTO/Authentication/UserForAuthenticationDto.cs similarity index 86% rename from Entities/DTO/UserForAuthenticationDto.cs rename to Entities/DTO/Authentication/UserForAuthenticationDto.cs index fce48c4..799a243 100644 --- a/Entities/DTO/UserForAuthenticationDto.cs +++ b/Entities/DTO/Authentication/UserForAuthenticationDto.cs @@ -2,7 +2,7 @@ namespace Entities.DTO { - public class UserForAuthenticationDto + public class UserForAuthenticationDto { [Required(ErrorMessage = "Email is required")] public string? Email { get; set; } diff --git a/Entities/DTO/Class/ClassCreateDto.cs b/Entities/DTO/Class/ClassCreateDto.cs new file mode 100644 index 0000000..262bbb9 --- /dev/null +++ b/Entities/DTO/Class/ClassCreateDto.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO.Class +{ + public record ClassCreateDto + { + public CreateGradeDto Grade { get; init; } + + [Required(ErrorMessage = "年级名称是必填项。")] + [StringLength(20, ErrorMessage = "年级名称不能超过 20 个字符。")] + public string ClassName { get; init; } + + [Required(ErrorMessage = "年级级别是必填项。")] + public byte Index { get; init; } + } +} diff --git a/Entities/DTO/Class/ClassDto.cs b/Entities/DTO/Class/ClassDto.cs new file mode 100644 index 0000000..b6602e3 --- /dev/null +++ b/Entities/DTO/Class/ClassDto.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class ClassDto + { + public Guid Id { get; set; } + + public Guid GradeId { get; set; } + + public GradeDto Grade { get; set; } + + [Required(ErrorMessage = "班级名称是必填项。")] + [StringLength(30, ErrorMessage = "班级名称不能超过 30 个字符。")] + public string ClassName { get; set; } + + public byte Index { get; set; } + + public Guid? HeadTeacherId { get; set; } + + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + } +} diff --git a/Entities/DTO/Class/ClassResponseDto.cs b/Entities/DTO/Class/ClassResponseDto.cs new file mode 100644 index 0000000..fd68e43 --- /dev/null +++ b/Entities/DTO/Class/ClassResponseDto.cs @@ -0,0 +1,22 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class ClassResponseDto + { + public Guid Id { get; set; } + public Guid GradeId { get; set; } + public string GradeName { get; set; } + public string ClassName { get; set; } + public Guid? HeadTeacherId { get; set; } + public string HeadTeacherName { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + public bool IsDeleted { get; set; } + + // Navigation properties for response + public ICollection ClassStudents { get; set; } + } +} diff --git a/Entities/DTO/Class/ClassUserDto.cs b/Entities/DTO/Class/ClassUserDto.cs new file mode 100644 index 0000000..04c962e --- /dev/null +++ b/Entities/DTO/Class/ClassUserDto.cs @@ -0,0 +1,15 @@ +using System; + +namespace Entities.DTO +{ + public class ClassUserDto + { + public Guid StudentId { get; set; } + public string? Email { get; set; } + public string? DisplayName { get; set; } + public string? PhoneNumber { get; set; } + public string? Address { get; set; } + public bool TwoFactorEnabled { get; set; } + public bool EmailConfirmed { get; set; } + } +} diff --git a/Entities/DTO/UserDto.cs b/Entities/DTO/Class/ClassValidDto.cs similarity index 58% rename from Entities/DTO/UserDto.cs rename to Entities/DTO/Class/ClassValidDto.cs index 502d1d6..fbe5dde 100644 --- a/Entities/DTO/UserDto.cs +++ b/Entities/DTO/Class/ClassValidDto.cs @@ -6,10 +6,5 @@ using System.Threading.Tasks; namespace Entities.DTO { - public class UserDto - { - public Guid Id { get; set; } - public string? DisplayName { get; set; } - - } + public record ClassValidDto(string SchoolName, byte Grade, byte Class); } diff --git a/Entities/DTO/Class/CreateClassDto.cs b/Entities/DTO/Class/CreateClassDto.cs new file mode 100644 index 0000000..f5d3cae --- /dev/null +++ b/Entities/DTO/Class/CreateClassDto.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateClassDto + { + [Required(ErrorMessage = "年级ID是必填项。")] + public Guid GradeId { get; set; } + + [Required(ErrorMessage = "班级名称是必填项。")] + [StringLength(30, ErrorMessage = "班级名称不能超过 30 个字符。")] + public string ClassName { get; set; } + + public byte Index { get; set; } + + public Guid? HeadTeacherId { get; set; } + } +} diff --git a/Entities/DTO/Class/RegisterUserToClassDto.cs b/Entities/DTO/Class/RegisterUserToClassDto.cs new file mode 100644 index 0000000..953bb0d --- /dev/null +++ b/Entities/DTO/Class/RegisterUserToClassDto.cs @@ -0,0 +1,18 @@ +using Entities.Contracts; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class RegisterUserToClassDto + { + + public Guid UserId { get; set; } + + public Guid ClassId { get; set; } + + public UserRoles Role { get; set; } = UserRoles.Student; + + public Guid? SubjectArea { get; set; } + } +} diff --git a/Entities/DTO/Class/UpdateClassDto.cs b/Entities/DTO/Class/UpdateClassDto.cs new file mode 100644 index 0000000..9ec1930 --- /dev/null +++ b/Entities/DTO/Class/UpdateClassDto.cs @@ -0,0 +1,20 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateClassDto + { + [Required(ErrorMessage = "班级ID是必填项。")] + public Guid ClassId { get; set; } + + [Required(ErrorMessage = "年级ID是必填项。")] + public Guid GradeId { get; set; } + + [Required(ErrorMessage = "班级名称是必填项。")] + [StringLength(30, ErrorMessage = "班级名称不能超过 30 个字符。")] + public string ClassName { get; set; } + + public Guid? HeadTeacherId { get; set; } + } +} diff --git a/Entities/DTO/ClassDto.cs b/Entities/DTO/ClassDto.cs deleted file mode 100644 index 40f5d18..0000000 --- a/Entities/DTO/ClassDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Entities.DTO -{ - public class ClassDto - { - public byte Class { get; set; } - - [StringLength(50, ErrorMessage = "班级名称不能超过 50 个字符。")] - public string Name { get; set; } - - [Required(ErrorMessage = "年级是必填项。")] - [Range(1, 12, ErrorMessage = "年级编号必须在 1 到 12 之间。")] - public byte Grade { get; set; } - - public string Description { get; set; } = "HELLO WORLD"; - - - public int? HeadTeacherId { get; set; } - } -} diff --git a/Entities/DTO/QuestionContextDto.cs b/Entities/DTO/Common/QueryParameterDto.cs similarity index 51% rename from Entities/DTO/QuestionContextDto.cs rename to Entities/DTO/Common/QueryParameterDto.cs index 523fe79..714623f 100644 --- a/Entities/DTO/QuestionContextDto.cs +++ b/Entities/DTO/Common/QueryParameterDto.cs @@ -6,10 +6,10 @@ using System.Threading.Tasks; namespace Entities.DTO { - - public class QuestionContextDto + public class QueryParameterDto { - public Guid Id { get; set; } = Guid.Empty; - public string Description { get; set; } = string.Empty; + public int PageIndex { get; set; } + public int PageSize { get; set; } + public string Search { get; set; } } } diff --git a/Entities/DTO/ResponseDto.cs b/Entities/DTO/Common/ResponseDto.cs similarity index 100% rename from Entities/DTO/ResponseDto.cs rename to Entities/DTO/Common/ResponseDto.cs diff --git a/Entities/DTO/Common/TypeCommonDto.cs b/Entities/DTO/Common/TypeCommonDto.cs new file mode 100644 index 0000000..2fbbe8b --- /dev/null +++ b/Entities/DTO/Common/TypeCommonDto.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record TypeCommonDto(Guid Id, string Name); +} diff --git a/Entities/DTO/Common/TypeCommonRequest.cs b/Entities/DTO/Common/TypeCommonRequest.cs new file mode 100644 index 0000000..d38cc2e --- /dev/null +++ b/Entities/DTO/Common/TypeCommonRequest.cs @@ -0,0 +1,11 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record TypeCommonRequest(TypeNameType Type, Guid? SubjectId); +} diff --git a/Entities/DTO/AssigExamToStudentsDto.cs b/Entities/DTO/Exam/AssigExamToStudentsDto.cs similarity index 68% rename from Entities/DTO/AssigExamToStudentsDto.cs rename to Entities/DTO/Exam/AssigExamToStudentsDto.cs index cf57528..b548d59 100644 --- a/Entities/DTO/AssigExamToStudentsDto.cs +++ b/Entities/DTO/Exam/AssigExamToStudentsDto.cs @@ -9,7 +9,10 @@ namespace Entities.DTO public class AssigExamToStudentsDto { public Guid CreaterId { get; set; } - public Guid AssignmentId { get; set; } + public Guid ExamId { get; set; } + public Guid ClassId { get; set; } public List StudentIds { get; set; } = new List(); } + + public record AssigExamToClassDto(Guid examId, Guid classId); } diff --git a/Entities/DTO/AssignmentClassDto.cs b/Entities/DTO/Exam/AssignmentClassDto.cs similarity index 77% rename from Entities/DTO/AssignmentClassDto.cs rename to Entities/DTO/Exam/AssignmentClassDto.cs index e6a0a99..063088e 100644 --- a/Entities/DTO/AssignmentClassDto.cs +++ b/Entities/DTO/Exam/AssignmentClassDto.cs @@ -12,8 +12,8 @@ namespace Entities.DTO public class AssignmentClassDto { - public AssignmentDto Assignment { get; set; } - public Class ClassId { get; set; } + public ExamDto Assignment { get; set; } + public ClassDto ClassId { get; set; } public DateTime AssignedAt { get; set; } } diff --git a/Entities/DTO/Exam/CreateExamDto.cs b/Entities/DTO/Exam/CreateExamDto.cs new file mode 100644 index 0000000..04a4446 --- /dev/null +++ b/Entities/DTO/Exam/CreateExamDto.cs @@ -0,0 +1,35 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateExamDto + { + [Required(ErrorMessage = "考试标题是必填项。")] + [StringLength(255, ErrorMessage = "考试标题不能超过 255 个字符。")] + public string Title { get; set; } + + public string Description { get; set; } + + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + [Required(ErrorMessage = "考试结构ID是必填项。")] + public Guid ExamStructId { get; set; } + + [Required(ErrorMessage = "考试类型ID是必填项。")] + public Guid ExamTypeId { get; set; } + + [Required(ErrorMessage = "创建者ID是必填项。")] + public Guid CreatorId { get; set; } + + [Required(ErrorMessage = "截止日期是必填项。")] + public DateTime DueDate { get; set; } + + public byte TotalQuestions { get; set; } + + public float Score { get; set; } + + public string Name { get; set; } + } +} diff --git a/Entities/DTO/Exam/ExamDto.cs b/Entities/DTO/Exam/ExamDto.cs new file mode 100644 index 0000000..bfc178a --- /dev/null +++ b/Entities/DTO/Exam/ExamDto.cs @@ -0,0 +1,44 @@ +using Entities.Contracts; +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class ExamDto + { + public Guid Id { get; set; } = Guid.NewGuid(); + + [Required(ErrorMessage = "考试标题是必填项。")] + [StringLength(255, ErrorMessage = "考试标题不能超过 255 个字符。")] + public string Title { get; set; } + + public string Description { get; set; } + + public byte TotalQuestions { get; set; } + + public float Score { get; set; } + + public string Name { get; set; } + + + + + + [Required(ErrorMessage = "截止日期是必填项。")] + public DateTime DueDate { get; set; } + + public Guid SubjectId { get; set; } + + public Guid ExamTypeId { get; set; } + + public Guid CreatorId { get; set; } + + //public Guid ExamStructId { get; set; } + + + public ExamQuestionDto ExamStruct { get; set; } = new ExamQuestionDto(); + + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + } +} diff --git a/Entities/DTO/Exam/ExamListDto.cs b/Entities/DTO/Exam/ExamListDto.cs new file mode 100644 index 0000000..874bee0 --- /dev/null +++ b/Entities/DTO/Exam/ExamListDto.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record ExamListDto(Guid Id, string Name); +} diff --git a/Entities/DTO/Exam/ExamQuestionDto.cs b/Entities/DTO/Exam/ExamQuestionDto.cs new file mode 100644 index 0000000..45d6aa0 --- /dev/null +++ b/Entities/DTO/Exam/ExamQuestionDto.cs @@ -0,0 +1,33 @@ +using Entities.Contracts; + +namespace Entities.DTO +{ + public class ExamQuestionDto + { + public Guid Id { get; set; } = Guid.NewGuid(); + + public string Title { get; set; } = string.Empty; + + public float Score { get; set; } = 0; + + public byte Index { get; set; } = 0; + + public string Sequence { get; set; } = string.Empty; + + + public Guid QuestionTypeId { get; set; } + + //public Guid? QuestionId { get; set; } + + //public Guid? ParentExamQuestionId { get; set; } + + public QuestionDto? Question { get; set; } + + //public ExamQuestionDto? ParentExamQuestion { get; set; } + + public ICollection ChildExamQuestions { get; set; } = new List(); + + // public Layout Layout { get; set; } = Layout.horizontal; + // public QuestionContextDto? Description { get; set; } + } +} diff --git a/Entities/DTO/Exam/ExamResponseDto.cs b/Entities/DTO/Exam/ExamResponseDto.cs new file mode 100644 index 0000000..7742fa9 --- /dev/null +++ b/Entities/DTO/Exam/ExamResponseDto.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class ExamResponseDto + { + public Guid Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public Guid SubjectId { get; set; } + public string SubjectName { get; set; } + public Guid ExamStructId { get; set; } + public string ExamStructName { get; set; } + public Guid ExamTypeId { get; set; } + public string ExamTypeName { get; set; } + public Guid CreatorId { get; set; } + public string CreatorName { get; set; } + public DateTime DueDate { get; set; } + public byte TotalQuestions { get; set; } + public float Score { get; set; } + public string Name { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime UpdatedAt { get; set; } + public bool IsDeleted { get; set; } + + // Navigation properties for response + public int AttachmentCount { get; set; } + public int SubmissionCount { get; set; } + public List AttachmentNames { get; set; } = new List(); + public List StudentNames { get; set; } = new List(); + public List SubmissionTimes { get; set; } = new List(); + } +} diff --git a/Entities/DTO/Exam/UpdateExamDto.cs b/Entities/DTO/Exam/UpdateExamDto.cs new file mode 100644 index 0000000..ec32dd4 --- /dev/null +++ b/Entities/DTO/Exam/UpdateExamDto.cs @@ -0,0 +1,38 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateExamDto + { + [Required(ErrorMessage = "考试ID是必填项。")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "考试标题是必填项。")] + [StringLength(255, ErrorMessage = "考试标题不能超过 255 个字符。")] + public string Title { get; set; } + + public string Description { get; set; } + + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + [Required(ErrorMessage = "考试结构ID是必填项。")] + public Guid ExamStructId { get; set; } + + [Required(ErrorMessage = "考试类型ID是必填项。")] + public Guid ExamTypeId { get; set; } + + [Required(ErrorMessage = "创建者ID是必填项。")] + public Guid CreatorId { get; set; } + + [Required(ErrorMessage = "截止日期是必填项。")] + public DateTime DueDate { get; set; } + + public byte TotalQuestions { get; set; } + + public float Score { get; set; } + + public string Name { get; set; } + } +} diff --git a/Entities/DTO/ExamType/CreateExamTypeDto.cs b/Entities/DTO/ExamType/CreateExamTypeDto.cs new file mode 100644 index 0000000..07f7271 --- /dev/null +++ b/Entities/DTO/ExamType/CreateExamTypeDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateExamTypeDto + { + [Required(ErrorMessage = "考试类型名称是必填项。")] + [StringLength(20, ErrorMessage = "考试类型名称不能超过 20 个字符。")] + public string ExamTypeName { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/ExamType/ExamTypeDto.cs b/Entities/DTO/ExamType/ExamTypeDto.cs new file mode 100644 index 0000000..12b44d8 --- /dev/null +++ b/Entities/DTO/ExamType/ExamTypeDto.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class ExamTypeDto + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "考试类型名称是必填项。")] + [StringLength(20, ErrorMessage = "考试类型名称不能超过 20 个字符。")] + public string Name { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/ExamType/ExamTypeResponseDto.cs b/Entities/DTO/ExamType/ExamTypeResponseDto.cs new file mode 100644 index 0000000..c47a7ad --- /dev/null +++ b/Entities/DTO/ExamType/ExamTypeResponseDto.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class ExamTypeResponseDto + { + public Guid ExamId { get; set; } + public string ExamTypeName { get; set; } + public string Description { get; set; } + + // Navigation properties for response + public int ExamCount { get; set; } + public List ExamTitles { get; set; } = new List(); + } +} diff --git a/Entities/DTO/ExamType/UpdateExamTypeDto.cs b/Entities/DTO/ExamType/UpdateExamTypeDto.cs new file mode 100644 index 0000000..6393a2c --- /dev/null +++ b/Entities/DTO/ExamType/UpdateExamTypeDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateExamTypeDto + { + [Required(ErrorMessage = "考试类型ID是必填项。")] + public Guid ExamTypeId { get; set; } + + [Required(ErrorMessage = "考试类型名称是必填项。")] + [StringLength(20, ErrorMessage = "考试类型名称不能超过 20 个字符。")] + public string ExamTypeName { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/GlobalDto.cs b/Entities/DTO/GlobalDto.cs deleted file mode 100644 index c018284..0000000 --- a/Entities/DTO/GlobalDto.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - - public class GlobalDto - { - - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - public string Data { get; set; } = string.Empty; - } - - public class QuestionDisplayTypeData - { - public string Color { get; set; } - public string DisplayName { get; set; } - } -} diff --git a/Entities/DTO/Grade/CreateGradeDto.cs b/Entities/DTO/Grade/CreateGradeDto.cs new file mode 100644 index 0000000..de9bc28 --- /dev/null +++ b/Entities/DTO/Grade/CreateGradeDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public record CreateGradeDto + { + public Guid SchoolId { get; init; } + + [Required(ErrorMessage = "年级名称是必填项。")] + [StringLength(20, ErrorMessage = "年级名称不能超过 20 个字符。")] + public string GradeName { get; init; } + + [Required(ErrorMessage = "年级级别是必填项。")] + public byte GradeLevel { get; init; } + } +} diff --git a/Entities/DTO/Grade/GradeDto.cs b/Entities/DTO/Grade/GradeDto.cs new file mode 100644 index 0000000..a034eb0 --- /dev/null +++ b/Entities/DTO/Grade/GradeDto.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class GradeDto + { + public Guid Id { get; set; } + + public Guid SchoolId { get; set; } + + [Required(ErrorMessage = "年级名称是必填项。")] + [StringLength(20, ErrorMessage = "年级名称不能超过 20 个字符。")] + public string GradeName { get; set; } + + [Required(ErrorMessage = "年级级别是必填项。")] + public byte GradeLevel { get; set; } + } +} diff --git a/Entities/DTO/Grade/GradeResponseDto.cs b/Entities/DTO/Grade/GradeResponseDto.cs new file mode 100644 index 0000000..0e98665 --- /dev/null +++ b/Entities/DTO/Grade/GradeResponseDto.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class GradeResponseDto + { + public int Id { get; set; } + public int SchoolId { get; set; } + public string SchoolName { get; set; } + public string GradeName { get; set; } + public int GradeLevel { get; set; } + + // Navigation properties for response + public ICollection Responses { get; set; } + } +} diff --git a/Entities/DTO/Grade/UpdateGradeDto.cs b/Entities/DTO/Grade/UpdateGradeDto.cs new file mode 100644 index 0000000..b08e385 --- /dev/null +++ b/Entities/DTO/Grade/UpdateGradeDto.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateGradeDto + { + [Required(ErrorMessage = "年级ID是必填项。")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "学校ID是必填项。")] + public Guid SchoolId { get; set; } + + [Required(ErrorMessage = "年级名称是必填项。")] + [StringLength(20, ErrorMessage = "年级名称不能超过 20 个字符。")] + public string GradeName { get; set; } + + [Required(ErrorMessage = "年级级别是必填项。")] + public byte GradeLevel { get; set; } + } +} diff --git a/Entities/DTO/KeyPoint/CreateKeyPointDto.cs b/Entities/DTO/KeyPoint/CreateKeyPointDto.cs new file mode 100644 index 0000000..8fd20fd --- /dev/null +++ b/Entities/DTO/KeyPoint/CreateKeyPointDto.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public record CreateKeyPointDto + { + [Required] + [StringLength(255)] + public string Key { get; init; } = string.Empty; + + [Required] + public Guid LessonID { get; init; } + } +} diff --git a/Entities/DTO/KeyPoint/KeyPointDto.cs b/Entities/DTO/KeyPoint/KeyPointDto.cs new file mode 100644 index 0000000..ce44de1 --- /dev/null +++ b/Entities/DTO/KeyPoint/KeyPointDto.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record KeyPointDto(Guid Id, string Key, Guid LessonId); +} diff --git a/Entities/DTO/KeyPoint/KeyPointResponseDto.cs b/Entities/DTO/KeyPoint/KeyPointResponseDto.cs new file mode 100644 index 0000000..bd14258 --- /dev/null +++ b/Entities/DTO/KeyPoint/KeyPointResponseDto.cs @@ -0,0 +1,13 @@ +using System; + +namespace Entities.DTO +{ + public record KeyPointResponseDto + { + public Guid Id { get; init; } + public string Key { get; init; } = string.Empty; + public Guid LessonID { get; init; } + public DateTime CreatedAt { get; init; } + public DateTime? UpdatedAt { get; init; } + } +} diff --git a/Entities/DTO/KeyPoint/UpdateKeyPointDto.cs b/Entities/DTO/KeyPoint/UpdateKeyPointDto.cs new file mode 100644 index 0000000..ec6f8a7 --- /dev/null +++ b/Entities/DTO/KeyPoint/UpdateKeyPointDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public record UpdateKeyPointDto + { + [Required] + public Guid Id { get; init; } + + [Required] + [StringLength(255)] + public string Key { get; init; } = string.Empty; + + [Required] + public Guid LessonID { get; init; } + } +} diff --git a/Entities/DTO/Lesson/CreateLessonDto.cs b/Entities/DTO/Lesson/CreateLessonDto.cs new file mode 100644 index 0000000..83af893 --- /dev/null +++ b/Entities/DTO/Lesson/CreateLessonDto.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateLessonDto + { + [Required(ErrorMessage = "课程标题是必填项")] + [StringLength(255, ErrorMessage = "课程标题长度不能超过255个字符")] + public string Title { get; set; } = string.Empty; + + [StringLength(1000, ErrorMessage = "课程描述长度不能超过1000个字符")] + public string Description { get; set; } = string.Empty; + + [Required(ErrorMessage = "教材ID是必填项")] + public Guid TextbookID { get; set; } + } +} diff --git a/Entities/DTO/Lesson/LessonDto.cs b/Entities/DTO/Lesson/LessonDto.cs new file mode 100644 index 0000000..90dc7cf --- /dev/null +++ b/Entities/DTO/Lesson/LessonDto.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record LessonDto(Guid Id, string Title, string Description, Guid TextBookId); +} diff --git a/Entities/DTO/Lesson/LessonResponseDto.cs b/Entities/DTO/Lesson/LessonResponseDto.cs new file mode 100644 index 0000000..691b90a --- /dev/null +++ b/Entities/DTO/Lesson/LessonResponseDto.cs @@ -0,0 +1,14 @@ +using System; + +namespace Entities.DTO +{ + public class LessonResponseDto + { + public Guid Id { get; set; } + public string Title { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public Guid TextbookID { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? UpdatedAt { get; set; } + } +} diff --git a/Entities/DTO/Lesson/UpdateLessonDto.cs b/Entities/DTO/Lesson/UpdateLessonDto.cs new file mode 100644 index 0000000..5093067 --- /dev/null +++ b/Entities/DTO/Lesson/UpdateLessonDto.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateLessonDto + { + [Required(ErrorMessage = "课程ID是必填项")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "课程标题是必填项")] + [StringLength(255, ErrorMessage = "课程标题长度不能超过255个字符")] + public string Title { get; set; } = string.Empty; + + [StringLength(1000, ErrorMessage = "课程描述长度不能超过1000个字符")] + public string Description { get; set; } = string.Empty; + + [Required(ErrorMessage = "教材ID是必填项")] + public Guid TextbookID { get; set; } + } +} diff --git a/Entities/DTO/Question/QuestionDto.cs b/Entities/DTO/Question/QuestionDto.cs new file mode 100644 index 0000000..dea56be --- /dev/null +++ b/Entities/DTO/Question/QuestionDto.cs @@ -0,0 +1,36 @@ +using Entities.Contracts; + +namespace Entities.DTO +{ + public class QuestionDto + { + public Guid Id { get; set; } = Guid.NewGuid(); + + public string Title { get; set; } = string.Empty; + + public string? Answer { get; set; } = string.Empty; + + public string? Options { get; set; } + + //public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy; + + + + public Guid QuestioTypeId { get; set; } + + public Guid SubjectId { get; set; } + + //public Guid CreatorId { get; set; } + + public Guid? KeyPointId { get; set; } + + public Guid? LessonId { get; set; } + + + + public DateTime CreatedAt { get; set; } + + public DateTime UpdatedAt { get; set; } = DateTime.Now; + + } +} diff --git a/Entities/DTO/QuestionDto.cs b/Entities/DTO/QuestionDto.cs deleted file mode 100644 index fad6196..0000000 --- a/Entities/DTO/QuestionDto.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class QuestionDto - { - public Guid Id { get; set; } = Guid.Empty; - - public string Title { get; set; } = string.Empty; - - public QuestionType Type { get; set; } = QuestionType.Unknown; - public string QType { get; set; } = string.Empty; - - public string? Answer { get; set; } = string.Empty; - - public string? Options { get; set; } - - public DifficultyLevel DifficultyLevel { get; set; } = DifficultyLevel.easy; - - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - - public Guid CreatorId { get; set; } - - public Guid? KeyPointId { get; set; } - - public Guid? LessonId { get; set; } - - public DateTime CreatedAt { get; set; } - - public DateTime UpdatedAt { get; set; } = DateTime.Now; - - } - - - /// - /// Can be removed because the class isn't used - /// - public class OptionDto - { - public string? Value { get; set; } = string.Empty; - } -} diff --git a/Entities/DTO/QuestionType/CreateQuestionTypeDto.cs b/Entities/DTO/QuestionType/CreateQuestionTypeDto.cs new file mode 100644 index 0000000..a6c3426 --- /dev/null +++ b/Entities/DTO/QuestionType/CreateQuestionTypeDto.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateQuestionTypeDto + { + [Required(ErrorMessage = "题型名称是必填项。")] + [StringLength(20, ErrorMessage = "题型名称不能超过 20 个字符。")] + public string TypeName { get; set; } + + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + public string Description { get; set; } + + [StringLength(20, ErrorMessage = "评分规则不能超过 20 个字符。")] + public string ScoreRule { get; set; } + } +} diff --git a/Entities/DTO/QuestionType/QuestionTypeDto.cs b/Entities/DTO/QuestionType/QuestionTypeDto.cs new file mode 100644 index 0000000..98f649b --- /dev/null +++ b/Entities/DTO/QuestionType/QuestionTypeDto.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class QuestionTypeDto + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "题型名称是必填项。")] + [StringLength(20, ErrorMessage = "题型名称不能超过 20 个字符。")] + public string Name { get; set; } + + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + public string Description { get; set; } + + [StringLength(20, ErrorMessage = "评分规则不能超过 20 个字符。")] + public string ScoreRule { get; set; } + } +} diff --git a/Entities/DTO/QuestionType/QuestionTypeResponseDto.cs b/Entities/DTO/QuestionType/QuestionTypeResponseDto.cs new file mode 100644 index 0000000..a189e6f --- /dev/null +++ b/Entities/DTO/QuestionType/QuestionTypeResponseDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class QuestionTypeResponseDto + { + public Guid TypeId { get; set; } + public string TypeName { get; set; } + public Guid SubjectId { get; set; } + public string SubjectName { get; set; } + public string Description { get; set; } + public string ScoreRule { get; set; } + + // Navigation properties for response + public int QuestionCount { get; set; } + public List QuestionTitles { get; set; } = new List(); + } +} diff --git a/Entities/DTO/QuestionType/UpdateQuestionTypeDto.cs b/Entities/DTO/QuestionType/UpdateQuestionTypeDto.cs new file mode 100644 index 0000000..d2ef1a3 --- /dev/null +++ b/Entities/DTO/QuestionType/UpdateQuestionTypeDto.cs @@ -0,0 +1,23 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateQuestionTypeDto + { + [Required(ErrorMessage = "题型ID是必填项。")] + public Guid TypeId { get; set; } + + [Required(ErrorMessage = "题型名称是必填项。")] + [StringLength(20, ErrorMessage = "题型名称不能超过 20 个字符。")] + public string TypeName { get; set; } + + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + public string Description { get; set; } + + [StringLength(20, ErrorMessage = "评分规则不能超过 20 个字符。")] + public string ScoreRule { get; set; } + } +} diff --git a/Entities/DTO/School/CreateSchoolDto.cs b/Entities/DTO/School/CreateSchoolDto.cs new file mode 100644 index 0000000..095bf6d --- /dev/null +++ b/Entities/DTO/School/CreateSchoolDto.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateSchoolDto + { + [Required(ErrorMessage = "学校名称是必填项。")] + [StringLength(50, ErrorMessage = "学校名称不能超过 50 个字符。")] + public string SchoolName { get; set; } + + [StringLength(100, ErrorMessage = "地址不能超过 100 个字符。")] + public string Address { get; set; } + } +} diff --git a/Entities/DTO/School/SchoolDto.cs b/Entities/DTO/School/SchoolDto.cs new file mode 100644 index 0000000..d91be21 --- /dev/null +++ b/Entities/DTO/School/SchoolDto.cs @@ -0,0 +1,19 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class SchoolDto + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "学校名称是必填项。")] + [StringLength(50, ErrorMessage = "学校名称不能超过 50 个字符。")] + public string SchoolName { get; set; } + + [StringLength(100, ErrorMessage = "地址不能超过 100 个字符。")] + public string Address { get; set; } + + public DateTime CreateTime { get; set; } + } +} diff --git a/Entities/DTO/School/SchoolResponseDto.cs b/Entities/DTO/School/SchoolResponseDto.cs new file mode 100644 index 0000000..340f1c9 --- /dev/null +++ b/Entities/DTO/School/SchoolResponseDto.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class SchoolResponseDto + { + public int SchoolId { get; set; } + public string SchoolName { get; set; } + public string Address { get; set; } + public DateTime CreateTime { get; set; } + + // Navigation properties for response + public ICollection Grades { get; set; } + } +} diff --git a/Entities/DTO/School/UpdateSchoolDto.cs b/Entities/DTO/School/UpdateSchoolDto.cs new file mode 100644 index 0000000..1c3c30d --- /dev/null +++ b/Entities/DTO/School/UpdateSchoolDto.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateSchoolDto + { + [Required(ErrorMessage = "学校ID是必填项。")] + public Guid SchoolId { get; set; } + + [Required(ErrorMessage = "学校名称是必填项。")] + [StringLength(50, ErrorMessage = "学校名称不能超过 50 个字符。")] + public string SchoolName { get; set; } + + [StringLength(100, ErrorMessage = "地址不能超过 100 个字符。")] + public string Address { get; set; } + } +} diff --git a/Entities/DTO/StudentDto.cs b/Entities/DTO/StudentDto.cs deleted file mode 100644 index 51f38b1..0000000 --- a/Entities/DTO/StudentDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class StudentDto - { - public Guid Id { get; set; } - public string? DisplayName { get; set; } - - public UInt32 ErrorQuestionNum { get; set; } - public Dictionary ErrorQuestionTypes { get; set; } = new Dictionary(); - public Dictionary SubjectAreaErrorQuestionDis { get; set; } = new Dictionary(); - public Dictionary LessonErrorDis { get; set; } = new Dictionary(); - public float Score { get; set; } - } -} diff --git a/Entities/DTO/Subject/CreateSubjectDto.cs b/Entities/DTO/Subject/CreateSubjectDto.cs new file mode 100644 index 0000000..8f6cdbe --- /dev/null +++ b/Entities/DTO/Subject/CreateSubjectDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class CreateSubjectDto + { + [Required(ErrorMessage = "科目名称是必填项。")] + [StringLength(20, ErrorMessage = "科目名称不能超过 20 个字符。")] + public string SubjectName { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/Subject/SubjectDto.cs b/Entities/DTO/Subject/SubjectDto.cs new file mode 100644 index 0000000..62c18dd --- /dev/null +++ b/Entities/DTO/Subject/SubjectDto.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class SubjectDto + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "科目名称是必填项。")] + [StringLength(20, ErrorMessage = "科目名称不能超过 20 个字符。")] + public string Name { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/Subject/SubjectResponseDto.cs b/Entities/DTO/Subject/SubjectResponseDto.cs new file mode 100644 index 0000000..8c71b1c --- /dev/null +++ b/Entities/DTO/Subject/SubjectResponseDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + public class SubjectResponseDto + { + public Guid Id { get; set; } + public string Name { get; set; } + public string Description { get; set; } + + // Navigation properties for response + public int QuestionTypeCount { get; set; } + public int QuestionCount { get; set; } + public int TeacherCount { get; set; } + public List QuestionTypeNames { get; set; } = new List(); + public List TeacherNames { get; set; } = new List(); + } +} diff --git a/Entities/DTO/Subject/UpdateSubjectDto.cs b/Entities/DTO/Subject/UpdateSubjectDto.cs new file mode 100644 index 0000000..a285c92 --- /dev/null +++ b/Entities/DTO/Subject/UpdateSubjectDto.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + public class UpdateSubjectDto + { + [Required(ErrorMessage = "科目ID是必填项。")] + public Guid SubjectId { get; set; } + + [Required(ErrorMessage = "科目名称是必填项。")] + [StringLength(20, ErrorMessage = "科目名称不能超过 20 个字符。")] + public string SubjectName { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/SubjectTypeMetadataDto.cs b/Entities/DTO/SubjectTypeMetadataDto.cs deleted file mode 100644 index 6847777..0000000 --- a/Entities/DTO/SubjectTypeMetadataDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; -using System.Collections.Generic; -using Entities.Contracts; - -namespace Entities.DTO -{ - public class SubjectTypeMetadataDto - { - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - //public Dictionary Data = new Dictionary(); - - public string Data = string.Empty; - } -} diff --git a/Entities/DTO/StudentSubmissionDetailDto.cs b/Entities/DTO/Submission/StudentSubmissionDetailDto.cs similarity index 95% rename from Entities/DTO/StudentSubmissionDetailDto.cs rename to Entities/DTO/Submission/StudentSubmissionDetailDto.cs index 69ba247..a8512de 100644 --- a/Entities/DTO/StudentSubmissionDetailDto.cs +++ b/Entities/DTO/Submission/StudentSubmissionDetailDto.cs @@ -16,7 +16,7 @@ namespace Entities.DTO public SubmissionStatus Status { get; set; } // Assignment信息 - public AssignmentDto Assignment { get; set; } = new AssignmentDto(); + public ExamDto Assignment { get; set; } = new ExamDto(); // 错误分析 public Dictionary ErrorTypeDistribution { get; set; } = new Dictionary(); diff --git a/Entities/DTO/StudentSubmissionSummaryDto.cs b/Entities/DTO/Submission/StudentSubmissionSummaryDto.cs similarity index 100% rename from Entities/DTO/StudentSubmissionSummaryDto.cs rename to Entities/DTO/Submission/StudentSubmissionSummaryDto.cs diff --git a/Entities/DTO/SubmissionDetailDto.cs b/Entities/DTO/Submission/SubmissionDetailDto.cs similarity index 79% rename from Entities/DTO/SubmissionDetailDto.cs rename to Entities/DTO/Submission/SubmissionDetailDto.cs index d12702d..beab938 100644 --- a/Entities/DTO/SubmissionDetailDto.cs +++ b/Entities/DTO/Submission/SubmissionDetailDto.cs @@ -10,12 +10,12 @@ namespace Entities.DTO public class SubmissionDetailDto { public Guid Id { get; set; } = Guid.Empty; + public Guid SubmissionId { get; set; } public Guid StudentId { get; set; } - public Guid AssignmentQuestionId { get; set; } + public Guid ExamQuestionId { get; set; } public string? StudentAnswer { get; set; } public bool? IsCorrect { get; set; } public float? PointsAwarded { get; set; } public string? TeacherFeedback { get; set; } - public SubmissionStatus Status { get; set; } = SubmissionStatus.Graded; } } diff --git a/Entities/DTO/SubmissionDto.cs b/Entities/DTO/Submission/SubmissionDto.cs similarity index 94% rename from Entities/DTO/SubmissionDto.cs rename to Entities/DTO/Submission/SubmissionDto.cs index 14343fb..63b4fad 100644 --- a/Entities/DTO/SubmissionDto.cs +++ b/Entities/DTO/Submission/SubmissionDto.cs @@ -10,7 +10,7 @@ namespace Entities.DTO public class SubmissionDto { public Guid Id { get; set; } = Guid.Empty; - public Guid AssignmentId { get; set; } + public Guid ExamId { get; set; } public Guid StudentId { get; set; } public DateTime SubmissionTime { get; set; } public float OverallGrade { get; set; } = 0; diff --git a/Entities/DTO/Submission/SubmissionListDto.cs b/Entities/DTO/Submission/SubmissionListDto.cs new file mode 100644 index 0000000..36da052 --- /dev/null +++ b/Entities/DTO/Submission/SubmissionListDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record SubmissionListDto + { + public Guid Id { get; init; } + + + public float OverallGrade { get; init; } + public int ErrorCount { get; init; } + public Dictionary? ErrorQuestionTypeDistribution { get; init; } + public Dictionary? ErrorQuestionLessonDistribution { get; init; } + + + public byte AttemptNumber { get; init; } + } +} diff --git a/Entities/DTO/Submission/SubmissionUpdateDto.cs b/Entities/DTO/Submission/SubmissionUpdateDto.cs new file mode 100644 index 0000000..9af4b8f --- /dev/null +++ b/Entities/DTO/Submission/SubmissionUpdateDto.cs @@ -0,0 +1,12 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record SubmissionDetailTeacherUpdateDto(Guid Id, bool IsCorrect, float? PointsAwarded); + public record SubmissionTeacherUpdateDto(Guid Id, float OverallGrade, string? OverallFeedback, SubmissionStatus Status, ICollection SubmissionUpdateDetails); +} diff --git a/Entities/DTO/Textbook/CreateTextbookDto.cs b/Entities/DTO/Textbook/CreateTextbookDto.cs new file mode 100644 index 0000000..a3de862 --- /dev/null +++ b/Entities/DTO/Textbook/CreateTextbookDto.cs @@ -0,0 +1,26 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + /// + /// 创建教材数据传输对象 + /// + public class CreateTextbookDto + { + [Required(ErrorMessage = "教材标题是必填项。")] + [StringLength(100, ErrorMessage = "教材标题不能超过 100 个字符。")] + public string Title { get; set; } + + [Required(ErrorMessage = "年级是必选项。")] + public string Grade { get; set; } + + [Required(ErrorMessage = "出版社是必选项。")] + public string Publisher { get; set; } + + [Required(ErrorMessage = "学科领域是必选项。")] + public string SubjectArea { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/Textbook/TextbookDto.cs b/Entities/DTO/Textbook/TextbookDto.cs new file mode 100644 index 0000000..d41d2a4 --- /dev/null +++ b/Entities/DTO/Textbook/TextbookDto.cs @@ -0,0 +1,28 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + /// + /// 教材数据传输对象 + /// + public class TextbookDto + { + public Guid Id { get; set; } + + [Required(ErrorMessage = "教材标题是必填项。")] + [StringLength(100, ErrorMessage = "教材标题不能超过 100 个字符。")] + public string Title { get; set; } + + [Required(ErrorMessage = "年级是必选项。")] + public string Grade { get; set; } + + [Required(ErrorMessage = "出版社是必选项。")] + public string Publisher { get; set; } + + [Required(ErrorMessage = "学科领域是必选项。")] + public string SubjectArea { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/Textbook/TextbookResponseDto.cs b/Entities/DTO/Textbook/TextbookResponseDto.cs new file mode 100644 index 0000000..9fba853 --- /dev/null +++ b/Entities/DTO/Textbook/TextbookResponseDto.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace Entities.DTO +{ + /// + /// 教材响应数据传输对象 + /// + public class TextbookResponseDto + { + public Guid Id { get; set; } + public string Title { get; set; } + public string Grade { get; set; } + public string Publisher { get; set; } + public string SubjectArea { get; set; } + public string Description { get; set; } + + // 导航属性 + public int LessonCount { get; set; } + public List LessonTitles { get; set; } = new List(); + } +} diff --git a/Entities/DTO/Textbook/UpdateTextbookDto.cs b/Entities/DTO/Textbook/UpdateTextbookDto.cs new file mode 100644 index 0000000..42c3c61 --- /dev/null +++ b/Entities/DTO/Textbook/UpdateTextbookDto.cs @@ -0,0 +1,29 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace Entities.DTO +{ + /// + /// 更新教材数据传输对象 + /// + public class UpdateTextbookDto + { + [Required(ErrorMessage = "教材ID是必填项。")] + public Guid Id { get; set; } + + [Required(ErrorMessage = "教材标题是必填项。")] + [StringLength(100, ErrorMessage = "教材标题不能超过 100 个字符。")] + public string Title { get; set; } + + [Required(ErrorMessage = "年级是必选项。")] + public string Grade { get; set; } + + [Required(ErrorMessage = "出版社是必选项。")] + public string Publisher { get; set; } + + [Required(ErrorMessage = "学科领域是必选项。")] + public string SubjectArea { get; set; } + + public string Description { get; set; } + } +} diff --git a/Entities/DTO/User/StudentExamDetailDto.cs b/Entities/DTO/User/StudentExamDetailDto.cs new file mode 100644 index 0000000..1827813 --- /dev/null +++ b/Entities/DTO/User/StudentExamDetailDto.cs @@ -0,0 +1,21 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record StudentExamDetailDto + { + public Guid Id { get; init; } + public string? DisplayName { get; init; } + + public uint ErrorQuestionNum { get; init; } + public Dictionary ErrorQuestionTypes { get; init; } = new Dictionary(); + public Dictionary SubjectAreaErrorQuestionDis { get; init; } = new Dictionary(); + public Dictionary LessonErrorDis { get; init; } = new Dictionary(); + public float Score { get; init; } + } +} diff --git a/Entities/DTO/User/UserClassInfoDto.cs b/Entities/DTO/User/UserClassInfoDto.cs new file mode 100644 index 0000000..61c1b87 --- /dev/null +++ b/Entities/DTO/User/UserClassInfoDto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record UserClassDetailInfoDto(IEnumerable UserClassInfos, string School); + public record UserClassInfoDto(Guid Id, byte Class, byte Grade); +} diff --git a/Entities/DTO/User/UserDto.cs b/Entities/DTO/User/UserDto.cs new file mode 100644 index 0000000..56c170c --- /dev/null +++ b/Entities/DTO/User/UserDto.cs @@ -0,0 +1,129 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + /// + /// 用户信息数据传输对象 + /// 用于在API调用中传输用户的基本信息 + /// + public record UserDto + { + /// + /// 用户唯一标识符 + /// + public Guid Id { get; init; } + + /// + /// 用户名 + /// + public string? UserName { get; init; } + + /// + /// 电子邮箱 + /// + [EmailAddress] + public string? Email { get; init; } + + /// + /// 手机号码 + /// + [Phone] + public string? PhoneNumber { get; init; } + + /// + /// 显示名称 + /// + public string? DisplayName { get; init; } + + /// + /// 家庭住址 + /// + public string? HomeAddress { get; init; } + + /// + /// 用户角色 + /// + public UserRoles? Role { get; init; } + + /// + /// 教授科目ID + /// + public Guid? TeachSubjectId { get; init; } + + /// + /// 教授科目信息 + /// + public SubjectDto? TeachSubject { get; init; } + + /// + /// 用户加入的班级数量 + /// + public int JoinedClassCount { get; init; } + + /// + /// 创建的问题数量 + /// + public int CreatedQuestionsCount { get; init; } + + /// + /// 创建的考试数量 + /// + public int CreatedExamsCount { get; init; } + + /// + /// 提交的作业数量 + /// + public int SubmittedAssignmentsCount { get; init; } + + /// + /// 批改的作业数量 + /// + public int GradedAssignmentsCount { get; init; } + + /// + /// 用户创建时间 + /// + public DateTime CreatedAt { get; init; } + + /// + /// 用户最后更新时间 + /// + public DateTime UpdatedAt { get; init; } + + /// + /// 用户是否已验证邮箱 + /// + public bool EmailConfirmed { get; init; } + + /// + /// 用户是否已锁定 + /// + public bool LockoutEnabled { get; init; } + + /// + /// 用户锁定结束时间 + /// + public DateTime? LockoutEnd { get; init; } + + /// + /// 获取用户角色的显示名称 + /// + public string? RoleDisplayName => Role?.GetDisplayName(); + + /// + /// 获取用户角色的简短名称 + /// + public string? RoleShortName => Role?.GetShortName(); + + /// + /// 获取用户的基本信息字符串 + /// + public string? UserInfoString => $"{DisplayName ?? UserName} ({Email})"; + } +} diff --git a/Entities/DTO/User/UserForAdmin.cs b/Entities/DTO/User/UserForAdmin.cs new file mode 100644 index 0000000..8abbb48 --- /dev/null +++ b/Entities/DTO/User/UserForAdmin.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record UserForAdmin + { + public string Email { get; init; } + public string SchoolName { get; init; } + public string Password { get; init; } + public string DisplayName { get; init; } + public string Address { get; init; } + } +} diff --git a/Entities/DTO/User/UserForRegistrationDto.cs b/Entities/DTO/User/UserForRegistrationDto.cs new file mode 100644 index 0000000..4f62a52 --- /dev/null +++ b/Entities/DTO/User/UserForRegistrationDto.cs @@ -0,0 +1,43 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public class UserForRegistrationDto + { + [Required(ErrorMessage = "姓名是必填项。")] + [StringLength(50, MinimumLength = 2, ErrorMessage = "姓名长度必须在 2 到 50 个字符之间。")] + public string DisplayName { get; set; } + + [Required(ErrorMessage = "电子邮件是必填项。")] + [EmailAddress(ErrorMessage = "电子邮件格式不正确。")] + public string Email { get; set; } + + [Required(ErrorMessage = "密码是必填项。")] + [StringLength(100, MinimumLength = 6, ErrorMessage = "密码长度至少为 6 个字符。")] + [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&.])[A-Za-z\d@$!%*?&.]{6,}$", + ErrorMessage = "密码必须包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符。特殊字符包含 @$!%*?&. ")] + public string Password { get; set; } + + [Compare(nameof(Password), ErrorMessage = "密码和确认密码不匹配。")] + [Required(ErrorMessage = "确认密码是必填项。")] + public string ConfirmPassword { get; set; } + + [Required(ErrorMessage = "至少选择一个角色。")] + public UserRoles Roles { get; set; } = UserRoles.Student; + + [Phone(ErrorMessage = "电话号码格式不正确。")] + [StringLength(11, MinimumLength = 11, ErrorMessage = "电话号码必须是 11 位数字。")] + public string? PhoneNumber { get; set; } + + [StringLength(200, ErrorMessage = "家庭住址不能超过 200 个字符。")] + public string? HomeAddress { get; set; } + + public RegisterUserToClassDto RegisterUserToClassDto { get; set; } = new RegisterUserToClassDto(); + } +} diff --git a/Entities/DTO/User/UserListDto.cs b/Entities/DTO/User/UserListDto.cs new file mode 100644 index 0000000..c2df85d --- /dev/null +++ b/Entities/DTO/User/UserListDto.cs @@ -0,0 +1,11 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public record UserListDto (Guid Id, string DisplayName, UserRoles Role, string Email, SubjectDto TeachSubject); +} diff --git a/Entities/DTO/User/UserRegistrationToClassDto.cs b/Entities/DTO/User/UserRegistrationToClassDto.cs new file mode 100644 index 0000000..3559463 --- /dev/null +++ b/Entities/DTO/User/UserRegistrationToClassDto.cs @@ -0,0 +1,18 @@ +using Entities.Contracts; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Entities.DTO +{ + public class UserRegistrationToClassDto + { + public string User { get; set; } = string.Empty; + public byte ClassId { get; set; } + public byte GradeId { get; set; } + public UserRoles Roles { get; set; } = UserRoles.Student; + public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; + } +} diff --git a/Entities/DTO/UserClassRoleDto.cs b/Entities/DTO/UserClassRoleDto.cs deleted file mode 100644 index 6f4d7d4..0000000 --- a/Entities/DTO/UserClassRoleDto.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class UserClassRoleDto - { - public List<(byte, byte)> ClassInfo { get; set; } = new List<(byte, byte)> (); - public string Role { get; set; } = string.Empty; - } -} diff --git a/Entities/DTO/UserForRegistrationDto.cs b/Entities/DTO/UserForRegistrationDto.cs deleted file mode 100644 index ede7e5b..0000000 --- a/Entities/DTO/UserForRegistrationDto.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class UserForRegistrationDto - { - [Required(ErrorMessage = "姓名是必填项。")] - [StringLength(50, MinimumLength = 2, ErrorMessage = "姓名长度必须在 2 到 50 个字符之间。")] - public string Name { get; set; } - - [Required(ErrorMessage = "电子邮件是必填项。")] - [EmailAddress(ErrorMessage = "电子邮件格式不正确。")] // 添加 Email 格式验证 - public string Email { get; set; } - - [Required(ErrorMessage = "密码是必填项。")] - [StringLength(100, MinimumLength = 6, ErrorMessage = "密码长度至少为 6 个字符。")] // 确保长度验证 - [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&.])[A-Za-z\d@$!%*?&.]{6,}$", - ErrorMessage = "密码必须包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符。特殊字符包含 @$!%*?&. ")] - public string Password { get; set; } - - [Compare(nameof(Password), ErrorMessage = "密码和确认密码不匹配。")] - [Required(ErrorMessage = "确认密码是必填项。")] // 确保确认密码也必须填写 - public string ConfirmPassword { get; set; } - - [Required(ErrorMessage = "至少选择一个角色。")] - public UserRoles Roles { get; set; } = UserRoles.Student; // 根据你当前的 MudRadioGroup 设定,这里是单选 - - [Required(ErrorMessage = "班级是必填项。")] - [Range(1, 14, ErrorMessage = "班级编号必须在 1 到 14 之间。")] // 班级范围已调整为 1-14 - public int Class { get; set; } = 1; - - [Required(ErrorMessage = "年级是必填项。")] - [Range(1, 6, ErrorMessage = "年级编号必须在 1 到 6 之间。")] // 年级范围已调整为 1-6 - public int Grade { get; set; } = 1; - - [Phone(ErrorMessage = "电话号码格式不正确。")] - [StringLength(11, MinimumLength = 11, ErrorMessage = "电话号码必须是 11 位数字。")] // 电话号码长度已调整为固定 11 位 - public string PhoneNumber { get; set; } - - [StringLength(200, ErrorMessage = "家庭住址不能超过 200 个字符。")] - public string HomeAddress { get; set; } - - public string ClientURI { get; set; } - } -} diff --git a/Entities/DTO/UserRegistrationToClassDto.cs b/Entities/DTO/UserRegistrationToClassDto.cs deleted file mode 100644 index 84ba109..0000000 --- a/Entities/DTO/UserRegistrationToClassDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Entities.Contracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Entities.DTO -{ - public class UserRegistrationToClassDto - { - public string User { get; set; } - public byte ClassId { get; set; } - public byte GradeId { get; set; } - public UserRoles Roles { get; set; } = UserRoles.Student; - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - } -} diff --git a/TechHelper.Client/App.razor b/TechHelper.Client/App.razor index d07039a..3f4af3a 100644 --- a/TechHelper.Client/App.razor +++ b/TechHelper.Client/App.razor @@ -2,6 +2,9 @@ + +

Authorizing...

+
@if (context.User.Identity?.IsAuthenticated != true) { diff --git a/TechHelper.Client/Content/AutoMapperProFile.cs b/TechHelper.Client/Content/AutoMapperProFile.cs index 22d9846..fd1b086 100644 --- a/TechHelper.Client/Content/AutoMapperProFile.cs +++ b/TechHelper.Client/Content/AutoMapperProFile.cs @@ -1,5 +1,4 @@ using AutoMapper; -using AutoMapper.Internal.Mappers; using Entities.Contracts; using Entities.DTO; using TechHelper.Client.Exam; @@ -12,11 +11,8 @@ namespace TechHelper.Context { CreateMap() .ForMember(d => d.Options, o => o.MapFrom(s => string.Join(Environment.NewLine, s.Options.Select(op => op.Text)))); - CreateMap() - .ForMember(d=>d.Description, o=>o.Ignore()); - CreateMap(); - - + CreateMap(); + CreateMap(); CreateMap(); } } diff --git a/TechHelper.Client/Exam/AssignmentCheckData.cs b/TechHelper.Client/Exam/AssignmentCheckData.cs index 0510537..c333650 100644 --- a/TechHelper.Client/Exam/AssignmentCheckData.cs +++ b/TechHelper.Client/Exam/AssignmentCheckData.cs @@ -14,7 +14,7 @@ namespace TechHelper.Client.Exam public class AssignmentCheckQuestion { public string Sequence { get; set; } = string.Empty; - public AssignmentQuestionDto AssignmentQuestionDto { get; set; } = new AssignmentQuestionDto(); + public ExamQuestionDto ExamQuestionDto { get; set; } = new ExamQuestionDto(); public float Score { get; set; } } @@ -42,7 +42,7 @@ namespace TechHelper.Client.Exam public static class ExamStructExtensions { - public static AssignmentCheckData GetStruct(this AssignmentDto dto) + public static AssignmentCheckData GetStruct(this ExamDto dto) { if (dto == null) { @@ -66,7 +66,7 @@ namespace TechHelper.Client.Exam /// 当前题目组的父级序号(例如:"1", "2.1")。如果为空,则表示顶级题目组。 /// 用于收集所有生成题目项的列表。 private static void GetSeqRecursive( - AssignmentQuestionDto currentGroup, + ExamQuestionDto currentGroup, string? parentSequence, List allQuestions) { @@ -74,7 +74,7 @@ namespace TechHelper.Client.Exam ? $"{parentSequence}.{currentGroup.Index}" : currentGroup.Index.ToString(); - foreach (var subGroup in currentGroup.ChildrenAssignmentQuestion) + foreach (var subGroup in currentGroup.ChildExamQuestions) { GetSeqRecursive(subGroup, currentGroupSequence, allQuestions); } @@ -83,7 +83,7 @@ namespace TechHelper.Client.Exam allQuestions.Add(new AssignmentCheckQuestion { - AssignmentQuestionDto = currentGroup, + ExamQuestionDto = currentGroup, //Sequence = currentGroupSequence, Sequence = currentGroup.Sequence, Score = currentGroup.Score, diff --git a/TechHelper.Client/Exam/ExamPaperExtensions .cs b/TechHelper.Client/Exam/ExamPaperExtensions .cs index e082727..0a02351 100644 --- a/TechHelper.Client/Exam/ExamPaperExtensions .cs +++ b/TechHelper.Client/Exam/ExamPaperExtensions .cs @@ -16,18 +16,18 @@ namespace TechHelper.Client.Exam .Where(line => !string.IsNullOrWhiteSpace(line)).ToList(); } - public static void SeqIndex(this AssignmentDto dto) + public static void SeqIndex(this ExamDto dto) { dto.ExamStruct.SeqQGroupIndex(); } - public static void SeqQGroupIndex(this AssignmentQuestionDto dto) + public static void SeqQGroupIndex(this ExamQuestionDto dto) { - foreach (var sqg in dto.ChildrenAssignmentQuestion) + foreach (var sqg in dto.ChildExamQuestions) { - sqg.Index = (byte)(dto.ChildrenAssignmentQuestion.IndexOf(sqg) + 1); + sqg.Index = (byte)(dto.ChildExamQuestions.ToList().IndexOf(sqg) + 1); sqg.SeqQGroupIndex(); } diff --git a/TechHelper.Client/Exam/ExamParse.cs b/TechHelper.Client/Exam/ExamParse.cs index 7c1a910..affbbb8 100644 --- a/TechHelper.Client/Exam/ExamParse.cs +++ b/TechHelper.Client/Exam/ExamParse.cs @@ -1,6 +1,8 @@ using Entities.Contracts; // 假设这些实体合约仍然是必需的 using System.Text.RegularExpressions; using System.Text; +using Entities.DTO; +using TechHelper.Client.Services; namespace TechHelper.Client.Exam { @@ -41,17 +43,17 @@ namespace TechHelper.Client.Exam } } - public class AssignmentEx + public class ExamEx { public string Title { get; set; } = "Title"; public string Description { get; set; } = "Description"; - public SubjectAreaEnum SubjectArea { get; set; } = SubjectAreaEnum.Unknown; - public AssignmentQuestionEx ExamStruct { get; set; } = new AssignmentQuestionEx(); + public TypeCommonDto Subject { get; set; } + public ExamQuestionEx ExamStruct { get; set; } = new ExamQuestionEx(); public List Errors { get; set; } = new List(); } // 试题的包裹器, 或者 单独作为一个试题结构存在 - public class AssignmentQuestionEx + public class ExamQuestionEx { public string Title { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; @@ -59,8 +61,8 @@ namespace TechHelper.Client.Exam public float Score { get; set; } public string Sequence { get; set; } = string.Empty; public QuestionEx? Question { get; set; } - public AssignmentStructType Type { get; set; } - public List ChildrenAssignmentQuestion { get; set; } = new List(); + public TypeCommonDto Type { get; set; } + public List ChildrenAssignmentQuestion { get; set; } = new List(); public int Priority { get; set; } } @@ -85,10 +87,10 @@ namespace TechHelper.Client.Exam { public string Pattern { get; set; } public int Priority { get; set; } - public AssignmentStructType Type { get; set; } + public ExamStructType Type { get; set; } public Regex Regex { get; private set; } - public RegexPatternConfig(string pattern, int priority, AssignmentStructType type = AssignmentStructType.Question) + public RegexPatternConfig(string pattern, int priority, ExamStructType type = ExamStructType.Question) { Pattern = pattern; Priority = priority; @@ -113,26 +115,26 @@ namespace TechHelper.Client.Exam // Group 2: 题目/题组标题内容 // 例如:一. 这是大题一 - QuestionPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[.\、]\s*(.+)", 1, AssignmentStructType.Struct)); + QuestionPatterns.Add(new RegexPatternConfig(@"^([一二三四五六七八九十]+)[.\、]\s*(.+)", 1, ExamStructType.Struct)); // 例如:(一) 这是第一子题组 - QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+)", 2, AssignmentStructType.Group)); + QuestionPatterns.Add(new RegexPatternConfig(@"^\(([一二三四五六七八九十]{1,2}|十[一二三四五六七八九])\)\s*(.+)", 2, ExamStructType.Group)); // 例如:1. 这是第一道题目 或 1 这是第一道题目 - QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.?\s*(.+)", 3, AssignmentStructType.Question)); + QuestionPatterns.Add(new RegexPatternConfig(@"^(\d+)\.?\s*(.+)", 3, ExamStructType.Question)); // 例如:(1). 这是小问一 或 (1) 这是小问一 - QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\.?\s*(.+)", 4, AssignmentStructType.Question)); + QuestionPatterns.Add(new RegexPatternConfig(@"^\((\d+)\)\.?\s*(.+)", 4, ExamStructType.Question)); // 例如:① 这是另一种小问 或 ①. 这是另一种小问 (如果 ① 后面会跟点,这个更通用) // 如果 ① 后面通常没有点,但您希望它也能匹配,则保留原样或根据实际情况调整 - QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\.?\s*(.+)", 5, AssignmentStructType.Question)); + QuestionPatterns.Add(new RegexPatternConfig(@"^[①②③④⑤⑥⑦⑧⑨⑩]+\.?\s*(.+)", 5, ExamStructType.Question)); - // 选项模式 (保持不变,使用 AssignmentStructType.Option 区分) - OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1, AssignmentStructType.Option)); - OptionPatterns.Add(new RegexPatternConfig(@"([a-z]\.)\s*(.*?)(?=[a-z]\.|$)", 2, AssignmentStructType.Option)); + // 选项模式 (保持不变,使用 ExamStructType.Option 区分) + OptionPatterns.Add(new RegexPatternConfig(@"([A-Z]\.)\s*(.*?)(?=[A-Z]\.|$)", 1, ExamStructType.Option)); + OptionPatterns.Add(new RegexPatternConfig(@"([a-z]\.)\s*(.*?)(?=[a-z]\.|$)", 2, ExamStructType.Option)); // 独立的得分正则表达式:匹配行末尾的 "(X分)" 格式 // Group 1: 捕获分数(如 "10" 或 "0.5") @@ -206,7 +208,7 @@ namespace TechHelper.Client.Exam _config = config ?? throw new ArgumentNullException(nameof(config), "ExamParserConfig cannot be null."); } - public AssignmentEx BuildExam(string fullExamText, List allPotentialMatches) + public ExamEx BuildExam(string fullExamText, List allPotentialMatches) { if (string.IsNullOrWhiteSpace(fullExamText)) { @@ -217,7 +219,7 @@ namespace TechHelper.Client.Exam throw new ArgumentNullException(nameof(allPotentialMatches), "Potential matches list cannot be null."); } - var assignment = new AssignmentEx(); + var assignment = new ExamEx(); try { assignment.Title = GetExamTitle(fullExamText); @@ -228,8 +230,8 @@ namespace TechHelper.Client.Exam assignment.Title = "未识别试卷标题"; } - var assignmentQuestionStack = new Stack(); - var rootAssignmentQuestion = new AssignmentQuestionEx { Type = AssignmentStructType.Struct, Priority = 0, Title = "Root Exam Structure" }; + var assignmentQuestionStack = new Stack(); + var rootAssignmentQuestion = new ExamQuestionEx { Priority = 0, Title = "Root Exam Structure" }; assignmentQuestionStack.Push(rootAssignmentQuestion); assignment.ExamStruct = rootAssignmentQuestion; @@ -270,7 +272,7 @@ namespace TechHelper.Client.Exam } } - if (pm.PatternConfig.Type == AssignmentStructType.Option) + if (pm.PatternConfig.Type == ExamStructType.Option) { HandleOptionMatch(pm, i, assignmentQuestionStack.Peek(), assignment.Errors); } @@ -337,7 +339,7 @@ namespace TechHelper.Client.Exam return true; } - private void HandleQuestionGroupMatch(PotentialMatch pm, int index, Stack assignmentQuestionStack, List errors) + private void HandleQuestionGroupMatch(PotentialMatch pm, int index, Stack assignmentQuestionStack, List errors) { try { @@ -379,24 +381,22 @@ namespace TechHelper.Client.Exam string seq = pm.RegexMatch.Groups[1].Value.Trim(); seq = string.IsNullOrEmpty(seq) || string.IsNullOrEmpty(sequence) ? seq : " ." + seq; - AssignmentQuestionEx newAssignmentQuestion; - if (pm.PatternConfig.Type == AssignmentStructType.Struct) + ExamQuestionEx newAssignmentQuestion; + if (pm.PatternConfig.Type == ExamStructType.Struct) { - newAssignmentQuestion = new AssignmentQuestionEx + newAssignmentQuestion = new ExamQuestionEx { Title = title, Score = score, Sequence = sequence + seq, Priority = pm.PatternConfig.Priority, - Type = pm.PatternConfig.Type }; } - else // AssignmentStructType.Question 类型 + else // ExamStructType.Question 类型 { - newAssignmentQuestion = new AssignmentQuestionEx + newAssignmentQuestion = new ExamQuestionEx { Priority = pm.PatternConfig.Priority, - Type = pm.PatternConfig.Type, Sequence = sequence + seq, Score = score, Question = new QuestionEx @@ -417,7 +417,7 @@ namespace TechHelper.Client.Exam } } - private void HandleOptionMatch(PotentialMatch pm, int index, AssignmentQuestionEx currentAssignmentQuestion, List errors) + private void HandleOptionMatch(PotentialMatch pm, int index, ExamQuestionEx currentAssignmentQuestion, List errors) { try { @@ -452,7 +452,7 @@ namespace TechHelper.Client.Exam } } - private void ProcessQuestionContent(AssignmentQuestionEx question, string contentText, List errors) + private void ProcessQuestionContent(ExamQuestionEx question, string contentText, List errors) { if (question?.Question == null) { @@ -479,12 +479,14 @@ namespace TechHelper.Client.Exam public class ExamParser { private readonly ExamParserConfig _config; + private readonly ICommonService _commonService; private readonly ExamDocumentScanner _scanner; private readonly ExamStructureBuilder _builder; - public ExamParser(ExamParserConfig config) + public ExamParser(ExamParserConfig config, ICommonService commonService) { _config = config ?? throw new ArgumentNullException(nameof(config)); + _commonService = commonService; _scanner = new ExamDocumentScanner(_config); _builder = new ExamStructureBuilder(_config); } @@ -494,9 +496,9 @@ namespace TechHelper.Client.Exam /// /// 完整的试卷文本 /// 解析后的 AssignmentEx 对象 - public AssignmentEx ParseExamPaper(string examPaperText) + public ExamEx ParseExamPaper(string examPaperText) { - var assignment = new AssignmentEx(); + var assignment = new ExamEx(); List allPotentialMatches = _scanner.Scan(examPaperText, assignment.Errors); assignment = _builder.BuildExam(examPaperText, allPotentialMatches); return assignment; diff --git a/TechHelper.Client/HttpRepository/AuthenticationClientService.cs b/TechHelper.Client/HttpRepository/AuthenticationClientService.cs index 311acdc..03c7b76 100644 --- a/TechHelper.Client/HttpRepository/AuthenticationClientService.cs +++ b/TechHelper.Client/HttpRepository/AuthenticationClientService.cs @@ -92,8 +92,8 @@ namespace TechHelper.Client.HttpRepository public async Task RegisterUserAsync(UserForRegistrationDto userForRegistrationDto) { - userForRegistrationDto.ClientURI = Path.Combine( - _navigationManager.BaseUri, "emailconfirmation"); + //userForRegistrationDto.ClientURI = Path.Combine( + // _navigationManager.BaseUri, "emailconfirmation"); var reponse = await _client.PostAsJsonAsync("account/register", userForRegistrationDto); diff --git a/TechHelper.Client/Layout/MainLayout.razor b/TechHelper.Client/Layout/MainLayout.razor index 499fb53..5f2ff45 100644 --- a/TechHelper.Client/Layout/MainLayout.razor +++ b/TechHelper.Client/Layout/MainLayout.razor @@ -5,22 +5,22 @@ - + - + application - - - + + + @@ -42,7 +42,7 @@ - + @Body diff --git a/TechHelper.Client/Pages/Author/Login.razor.cs b/TechHelper.Client/Pages/Author/Login.razor.cs index 34cfb3f..7f968d0 100644 --- a/TechHelper.Client/Pages/Author/Login.razor.cs +++ b/TechHelper.Client/Pages/Author/Login.razor.cs @@ -1,7 +1,7 @@ using TechHelper.Client.HttpRepository; -using Entities.DTO; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.WebUtilities; +using Entities.DTO; namespace TechHelper.Client.Pages.Author { diff --git a/TechHelper.Client/Pages/Author/Registration.razor b/TechHelper.Client/Pages/Author/Registration.razor index cbaf041..c47db4e 100644 --- a/TechHelper.Client/Pages/Author/Registration.razor +++ b/TechHelper.Client/Pages/Author/Registration.razor @@ -33,7 +33,7 @@ 注册账户 + @bind-Value="_userForRegistration.DisplayName" For="@(() => _userForRegistration.Email)" /> MudDialog.Cancel(); diff --git a/TechHelper.Client/Pages/Common/GlobalInfoCard.razor b/TechHelper.Client/Pages/Common/GlobalInfoCard.razor index e1e8e1b..bad46a1 100644 --- a/TechHelper.Client/Pages/Common/GlobalInfoCard.razor +++ b/TechHelper.Client/Pages/Common/GlobalInfoCard.razor @@ -3,10 +3,10 @@ @using Helper - - SCORE - NUMQUESTION - + + SCORE + NUMQUESTION +@* @foreach (SubjectAreaEnum item in Enum.GetValues(typeof(SubjectAreaEnum))) { @@ -15,7 +15,7 @@ Value="@item"> } - + *@ DUETIME EXAMTYPE @@ -24,7 +24,7 @@ @code { [Parameter] - public AssignmentDto AssignmentDto { get; set; } + public ExamDto ExamDto { get; set; } [Parameter] public string Style { get; set; } [Parameter] @@ -32,6 +32,6 @@ public void HandleQTSelectedValueChanged(SubjectAreaEnum subject) { - AssignmentDto.SubjectArea = subject; + // ExamDto.SubjectArea = subject; } } \ No newline at end of file diff --git a/TechHelper.Client/Pages/Common/PublishExamDialog.razor b/TechHelper.Client/Pages/Common/PublishExamDialog.razor index b093d23..c59f549 100644 --- a/TechHelper.Client/Pages/Common/PublishExamDialog.razor +++ b/TechHelper.Client/Pages/Common/PublishExamDialog.razor @@ -12,7 +12,7 @@ - +@* @@ -40,7 +40,7 @@ @ExamType.AITest - + *@ Cancel @@ -53,7 +53,7 @@ private IMudDialogInstance MudDialog { get; set; } [Parameter] - public AssignmentDto Exam { get; set; } = new AssignmentDto(); + public ExamDto Exam { get; set; } = new ExamDto(); public SubjectAreaEnum SubjectArea { get; set; } diff --git a/TechHelper.Client/Pages/Common/Question/QuestionType.razor b/TechHelper.Client/Pages/Common/Question/QuestionType.razor new file mode 100644 index 0000000..7a6c095 --- /dev/null +++ b/TechHelper.Client/Pages/Common/Question/QuestionType.razor @@ -0,0 +1,31 @@ +@using TechHelper.Client.Services +@using Entities.DTO +@using Entities.Contracts + + + + @foreach (var item in QuestionTypes) + { + @item.Name + } + + + +@code { + private TypeCommonDto SelectedValue; + private List QuestionTypes; + + [Parameter] + public TypeNameType Type { get; set; } + + [Parameter] + public Guid? SubjectID { get; set; } = null; + + [Inject] + public ICommonService CommonService { get; set; } + + protected async override Task OnInitializedAsync() + { + var QuestionServices = await CommonService.GetCommonTypesAsync(Type, SubjectID); + } +} diff --git a/TechHelper.Client/Pages/Common/QuestionCardDialog.razor b/TechHelper.Client/Pages/Common/QuestionCardDialog.razor index b373699..92ed498 100644 --- a/TechHelper.Client/Pages/Common/QuestionCardDialog.razor +++ b/TechHelper.Client/Pages/Common/QuestionCardDialog.razor @@ -9,7 +9,7 @@ - + Cancel @@ -22,7 +22,7 @@ private IMudDialogInstance MudDialog { get; set; } [Parameter] - public AssignmentQuestionDto Questions { get; set; } = new AssignmentQuestionDto(); + public ExamQuestionDto Questions { get; set; } = new ExamQuestionDto(); private void Cancel() => MudDialog.Cancel(); diff --git a/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor b/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor deleted file mode 100644 index 0561315..0000000 --- a/TechHelper.Client/Pages/Exam/AssignmentQuestionEdit.razor +++ /dev/null @@ -1,113 +0,0 @@ -@using Entities.DTO -@using Entities.Contracts -@using Newtonsoft.Json -@using TechHelper.Client.Exam -@using TechHelper.Client.Pages.Exam.QuestionCard - - - - @* @AssignmentQuestion.Id *@ - - 包裹器属性 - - - - - @AssignmentStructType.Root - @AssignmentStructType.Struct - @AssignmentStructType.Group - @AssignmentStructType.Question - @AssignmentStructType.SubQuestion - @AssignmentStructType.Option - - - - - - @foreach (var item in QuestionTypes) - { - var qt = item; - @* Style = "@($"background - color:{ item.Value.Color} ")"*@ - - - @item.Value.DisplayName - - } - - - @if (AssignmentQuestion.Question != null) - { - - } - - - -@code { - [Parameter] - public AssignmentQuestionDto AssignmentQuestion { get; set; } = new AssignmentQuestionDto(); - public QuestionDto TempQuesdto; - Dictionary QuestionTypes = new Dictionary(); - - [Inject] - private ILocalStorageService LocalStorageService { get; set; } - protected override void OnInitialized() - { - base.OnInitialized(); - if (AssignmentQuestion.Question != null) - { - TempQuesdto = AssignmentQuestion.Question; - } - - var cs = LocalStorageService.GetItem("GlobalInfo"); - var GlobalInfo = JsonConvert.DeserializeObject>(cs); - if(GlobalInfo != null) - { - QuestionTypes = GlobalInfo; - } - } - - private void HandleQTSelectedValueChanged(string type) - { - AssignmentQuestion.QType = type; - if (AssignmentQuestion.ChildrenAssignmentQuestion.Count > 0 && AssignmentQuestion.StructType == AssignmentStructType.Group) - { - foreach (var item in AssignmentQuestion.ChildrenAssignmentQuestion) - { - item.QType = type; - if (item.Question != null) - { - item.Question.QType = type; - } - } - } - StateHasChanged(); - } - - private void HandleSelectedValueChanged(AssignmentStructType type) - { - AssignmentQuestion.StructType = type; - if (type != AssignmentStructType.Question && AssignmentQuestion.Question != null) - { - AssignmentQuestion.Title = AssignmentQuestion.Question.Title; - AssignmentQuestion.Question = null; - } - - if (type == AssignmentStructType.Question && AssignmentQuestion.Question == null) - { - if (TempQuesdto != null) - { - AssignmentQuestion.Question = TempQuesdto; - if (AssignmentQuestion.Title == AssignmentQuestion.Question.Title) - { - AssignmentQuestion.Title = ""; - } - } - else - AssignmentQuestion.Question = new QuestionDto { }; - } - StateHasChanged(); - } -} diff --git a/TechHelper.Client/Pages/Exam/ExamCheck.razor b/TechHelper.Client/Pages/Exam/ExamCheck.razor index fe601c5..04fa234 100644 --- a/TechHelper.Client/Pages/Exam/ExamCheck.razor +++ b/TechHelper.Client/Pages/Exam/ExamCheck.razor @@ -59,9 +59,9 @@ else if (_questionsForTable.Any() && _students.Any()) @student.DisplayName: @GetStudentTotalScore(student.Id) } - +@* 提交批改结果 (模拟) - + *@ } @@ -86,10 +86,10 @@ else private NavigationManager Navigation { get; set; } private MudTable _table = new(); - private AssignmentDto Assignment { get; set; } = new AssignmentDto(); + private ExamDto Assignment { get; set; } = new ExamDto(); private AssignmentCheckData _examStruct = new AssignmentCheckData(); - private List _students = new List(); + private List _students = new List(); private List _questionsForTable = new List(); private bool _isLoading = true; @@ -99,14 +99,14 @@ else protected override async Task OnInitializedAsync() { - _isLoading = true; - await LoadExamData(); + // _isLoading = true; + // await LoadExamData(); - var result = await ClassServices.GetClassStudents(); - if (!result.Status) Snackbar.Add($"获取学生失败, {result.Message}", Severity.Error); - _students = result.Result as List ?? new List(); - BuildTable(); - _isLoading = false; + // var result = await ClassServices.GetClassStudents(); + // if (!result.Status) Snackbar.Add($"获取学生失败, {result.Message}", Severity.Error); + // _students = result.Result as List ?? new List(); + // BuildTable(); + // _isLoading = false; } private void BuildTable() @@ -135,7 +135,7 @@ else var result = await ExamService.GetExam(parsedExamId); if (result.Status) { - Assignment = result.Result as AssignmentDto ?? new AssignmentDto(); + Assignment = result.Result as ExamDto ?? new ExamDto(); _examStruct = Assignment.GetStruct(); } else @@ -188,52 +188,52 @@ else StateHasChanged(); } - private void SubmitGrading() - { + // private void SubmitGrading() + // { - List submissionDto = new List(); + // List submissionDto = new List(); - foreach (var student in _students) - { - var newSubmission = new SubmissionDto(); - newSubmission.StudentId = student.Id; - newSubmission.AssignmentId = Assignment.Id; - newSubmission.SubmissionTime = DateTime.Now; - newSubmission.Status = Entities.Contracts.SubmissionStatus.Graded; + // foreach (var student in _students) + // { + // var newSubmission = new SubmissionDto(); + // newSubmission.StudentId = student.Id; + // newSubmission.AssignmentId = Assignment.Id; + // newSubmission.SubmissionTime = DateTime.Now; + // newSubmission.Status = Entities.Contracts.SubmissionStatus.Graded; - foreach (var row in _questionsForTable) - { - if (row.QuestionItem.AssignmentQuestionDto.StructType == Entities.Contracts.AssignmentStructType.Struct) continue; - if (row.StudentAnswers.TryGetValue(student.Id, out bool isCorrect)) - { - newSubmission.SubmissionDetails.Add(new SubmissionDetailDto - { - IsCorrect = isCorrect, - StudentId = student.Id, - AssignmentQuestionId = row.QuestionItem.AssignmentQuestionDto.Id, - PointsAwarded = isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0 - }); + // foreach (var row in _questionsForTable) + // { + // if (row.QuestionItem.AssignmentQuestionDto.StructType == Entities.Contracts.AssignmentStructType.Struct) continue; + // if (row.StudentAnswers.TryGetValue(student.Id, out bool isCorrect)) + // { + // newSubmission.SubmissionDetails.Add(new SubmissionDetailDto + // { + // IsCorrect = isCorrect, + // StudentId = student.Id, + // AssignmentQuestionId = row.QuestionItem.AssignmentQuestionDto.Id, + // PointsAwarded = isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0 + // }); - newSubmission.OverallGrade += isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0; - } - } - submissionDto.Add(newSubmission); - } + // newSubmission.OverallGrade += isCorrect ? row.QuestionItem.AssignmentQuestionDto.Score : 0; + // } + // } + // submissionDto.Add(newSubmission); + // } - submissionDto.ForEach(async s => - { - Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info); - var submidResult = await ExamService.SubmissionAssignment(s); - if (submidResult.Status) - Snackbar?.Add($"批改结果已提交 {_students.FirstOrDefault(st => st.Id == s.StudentId)?.DisplayName}", Severity.Success); - else - Snackbar?.Add("批改结果提交失败", Severity.Error); + // submissionDto.ForEach(async s => + // { + // Snackbar?.Add($"正在提交: {_students.FirstOrDefault(std => std.Id == s.StudentId)?.DisplayName} 的试卷", Severity.Info); + // var submidResult = await ExamService.SubmissionAssignment(s); + // if (submidResult.Status) + // Snackbar?.Add($"批改结果已提交 {_students.FirstOrDefault(st => st.Id == s.StudentId)?.DisplayName}", Severity.Success); + // else + // Snackbar?.Add("批改结果提交失败", Severity.Error); - }); + // }); - } + // } } \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/ExamCreate.razor b/TechHelper.Client/Pages/Exam/ExamCreate.razor index 7dde53f..c1638a1 100644 --- a/TechHelper.Client/Pages/Exam/ExamCreate.razor +++ b/TechHelper.Client/Pages/Exam/ExamCreate.razor @@ -16,54 +16,34 @@ @inject IDialogService DialogService - - - @if (_edit) + + + + + 文本编辑器 + 载入 + 发布 + 指派 + Test + GlobalExamInfo + + + + + + + + @if (_parsedExam.Errors.Any()) { - - } - else - { - - - 配置 - - - - - ParseExam - - } - - - - - - - 文本编辑器 - 载入 - 发布 - 指派 - Test - GlobalExamInfo - - - - - - - - @if (_parsedExam.Errors.Any()) + foreach (var item in _parsedExam.Errors) { - foreach (var item in _parsedExam.Errors) - { - @item.Message - } + @item.Message } - - - + } + + + @code { @@ -71,19 +51,11 @@ [CascadingParameter] private Task authenticationStateTask { get; set; } - private AssignmentQuestionDto selectedAssignmentQuestion = new AssignmentQuestionDto(); - private IReadOnlyCollection _selected; - private bool _open = false; - private bool _edit = false; + private ExamQuestionDto selectedAssignmentQuestion = new ExamQuestionDto(); - private void ToggleDrawer() - { - _open = !_open; - _edit = false; - } private BlazoredTextEditor _textEditor = new BlazoredTextEditor(); - private AssignmentEx _parsedExam = new AssignmentEx(); - private AssignmentDto ExamContent = new AssignmentDto(); + private ExamEx _parsedExam = new ExamEx(); + private ExamDto ExamContent = new ExamDto(); private ExamParserConfig _examParserConfig { get; set; } = new ExamParserConfig(); private string EditorText = ""; @@ -98,20 +70,6 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - - var response = await NoteService.GetNote((byte)SubjectAreaEnum.Literature); - - if (response.Status) - { - try - { - LocalStorageService.SetItem("GlobalInfo", response.Result); - } - catch (Exception ex) - { - - } - } } private async void OpenEditor() @@ -141,12 +99,8 @@ StateHasChanged(); } - private async void HandleClickedStruct(AssignmentQuestionDto dto) + private async void HandleClickedStruct(ExamQuestionDto dto) { - // _open = true; - // _edit = true; - // StateHasChanged(); - var parameters = new DialogParameters { { x => x.Questions, dto } }; var dialog = await DialogService.ShowAsync("Edit_Question", parameters); @@ -157,6 +111,9 @@ StateHasChanged(); } + [Inject] + public ICommonService commonService { get; set; } + private async Task ParseExam() { @@ -167,12 +124,12 @@ { try { - var exampar = new ExamParser(_examParserConfig); + var exampar = new ExamParser(_examParserConfig, commonService); _parsedExam = exampar.ParseExamPaper(plainText); Snackbar.Add("试卷解析成功。", Severity.Success); Snackbar.Add($"{_parsedExam.Errors}。", Severity.Success); StateHasChanged(); - ExamContent = Mapper.Map(_parsedExam); + ExamContent = Mapper.Map(_parsedExam); ExamContent.SeqIndex(); } catch (Exception ex) @@ -194,8 +151,6 @@ [Inject] public IExamService examService { get; set; } - [Inject] - public INoteService NoteService { get; set; } public async Task Publish() @@ -207,7 +162,6 @@ { Dictionary Note = new Dictionary { { "Hello", (Color.Surface, "World") }, { "My", (Color.Surface, "App") }, }; var json = JsonConvert.SerializeObject(Note); - var result = await NoteService.AddNote(new GlobalDto { SubjectArea = Entities.Contracts.SubjectAreaEnum.Physics, Data = json }); @@ -218,9 +172,6 @@ private async void HandleGlobalInfo() { - // _open = true; - // _edit = true; - // StateHasChanged(); var parameters = new DialogParameters { { x => x.Assignment, ExamContent } }; @@ -232,53 +183,3 @@ StateHasChanged(); } } - - - - - - - -@* - - - - - *@ -@* - - - - - - - - - - - - - - - - - - - - - - - - - - - *@ - - \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/ExamEdit.razor b/TechHelper.Client/Pages/Exam/ExamEdit.razor index 91f3734..64e567a 100644 --- a/TechHelper.Client/Pages/Exam/ExamEdit.razor +++ b/TechHelper.Client/Pages/Exam/ExamEdit.razor @@ -2,7 +2,6 @@ @using Entities.DTO @using TechHelper.Client.Pages.Exam.ExamView @using TechHelper.Client.Services -@using Entities.DTO @using TechHelper.Client.Exam @@ -20,7 +19,7 @@ [Inject] private ISnackbar Snackbar { get; set; } - private AssignmentDto ExamDto { get; set; } + private ExamDto ExamDto { get; set; } protected override async Task OnInitializedAsync() { @@ -31,7 +30,7 @@ try { var result = await ExamService.GetExam(parsedExamId); - if (result.Status) ExamDto = result.Result as AssignmentDto ?? new AssignmentDto(); + if (result.Status) ExamDto = result.Result as ExamDto ?? new ExamDto(); } catch (Exception ex) { diff --git a/TechHelper.Client/Pages/Exam/ExamManager.razor b/TechHelper.Client/Pages/Exam/ExamManager.razor index 539c1e2..fea70be 100644 --- a/TechHelper.Client/Pages/Exam/ExamManager.razor +++ b/TechHelper.Client/Pages/Exam/ExamManager.razor @@ -4,7 +4,6 @@ @using TechHelper.Client.Pages.Common.Exam @page "/exam/manage" -@using Entities.DTO @using TechHelper.Client.Services @attribute [Authorize] @@ -34,7 +33,7 @@ else [CascadingParameter] private Task authenticationStateTask { get; set; } - private List examDtos = new List(); + private List examDtos = new List(); private bool isloding = true; @@ -51,7 +50,7 @@ else var result = await ExamService.GetAllExam(); if (result.Status) { - examDtos = result.Result as List ?? new List(); + examDtos = result.Result as List ?? new List(); Snackbar.Add("加载成功", Severity.Info); } else diff --git a/TechHelper.Client/Pages/Exam/ExamPreview.razor b/TechHelper.Client/Pages/Exam/ExamPreview.razor index 05d2839..7f38f65 100644 --- a/TechHelper.Client/Pages/Exam/ExamPreview.razor +++ b/TechHelper.Client/Pages/Exam/ExamPreview.razor @@ -3,7 +3,7 @@ - @AssignmentDto.Title + @ExamDto.Title @@ -34,7 +34,7 @@ public NavigationManager navigationManager { get; set; } [Parameter] - public AssignmentDto AssignmentDto { get; set; } + public ExamDto ExamDto { get; set; } [Parameter] @@ -61,11 +61,11 @@ private void ExamClick() { - navigationManager.NavigateTo($"exam/edit/{AssignmentDto.Id}"); + navigationManager.NavigateTo($"exam/edit/{ExamDto.Id}"); } private void CheckExam() { - navigationManager.NavigateTo($"exam/check/{AssignmentDto.Id}"); + navigationManager.NavigateTo($"exam/check/{ExamDto.Id}"); } } diff --git a/TechHelper.Client/Pages/Exam/ExamQuestionEdit.razor b/TechHelper.Client/Pages/Exam/ExamQuestionEdit.razor new file mode 100644 index 0000000..09552bf --- /dev/null +++ b/TechHelper.Client/Pages/Exam/ExamQuestionEdit.razor @@ -0,0 +1,112 @@ +@using Entities.Contracts +@using Entities.DTO +@using Newtonsoft.Json +@using TechHelper.Client.Exam +@using TechHelper.Client.Pages.Exam.QuestionCard + + + + @* @AssignmentQuestion.Id *@ + + 包裹器属性 + + + +@* + @AssignmentStructType.Root + @AssignmentStructType.Struct + @AssignmentStructType.Group + @AssignmentStructType.Question + @AssignmentStructType.SubQuestion + @AssignmentStructType.Option + *@ + + +@* + + @foreach (var item in QuestionTypes) + { + var qt = item; + + + @item.Value.DisplayName + + } + *@ + + @if (ExamQuestion.Question != null) + { + + } + + + +@code { + [Parameter] + public ExamQuestionDto ExamQuestion { get; set; } = new ExamQuestionDto(); + public QuestionDto TempQuesdto; + // Dictionary QuestionTypes = new Dictionary(); + + [Inject] + private ILocalStorageService LocalStorageService { get; set; } + // protected override void OnInitialized() + // { + // base.OnInitialized(); + // if (AssignmentQuestion.Question != null) + // { + // TempQuesdto = AssignmentQuestion.Question; + // } + + // var cs = LocalStorageService.GetItem("GlobalInfo"); + // var GlobalInfo = JsonConvert.DeserializeObject>(cs); + // if(GlobalInfo != null) + // { + // QuestionTypes = GlobalInfo; + // } + // } + + // private void HandleQTSelectedValueChanged(string type) + // { + // AssignmentQuestion.QType = type; + // if (AssignmentQuestion.ChildrenAssignmentQuestion.Count > 0 && AssignmentQuestion.StructType == AssignmentStructType.Group) + // { + // foreach (var item in AssignmentQuestion.ChildrenAssignmentQuestion) + // { + // item.QType = type; + // if (item.Question != null) + // { + // item.Question.QType = type; + // } + // } + // } + // StateHasChanged(); + // } + + // private void HandleSelectedValueChanged(AssignmentStructType type) + // { + // AssignmentQuestion.StructType = type; + // if (type != AssignmentStructType.Question && AssignmentQuestion.Question != null) + // { + // AssignmentQuestion.Title = AssignmentQuestion.Question.Title; + // AssignmentQuestion.Question = null; + // } + + // if (type == AssignmentStructType.Question && AssignmentQuestion.Question == null) + // { + // if (TempQuesdto != null) + // { + // AssignmentQuestion.Question = TempQuesdto; + // if (AssignmentQuestion.Title == AssignmentQuestion.Question.Title) + // { + // AssignmentQuestion.Title = ""; + // } + // } + // else + // AssignmentQuestion.Question = new QuestionDto { }; + // } + // StateHasChanged(); + // } +} diff --git a/TechHelper.Client/Pages/Exam/ExamView/ExamStructView.razor b/TechHelper.Client/Pages/Exam/ExamView/ExamStructView.razor index ea7e5aa..10fa7bb 100644 --- a/TechHelper.Client/Pages/Exam/ExamView/ExamStructView.razor +++ b/TechHelper.Client/Pages/Exam/ExamView/ExamStructView.razor @@ -10,23 +10,15 @@ @ExamStruct.Title - Num: @ExamStruct.ChildrenAssignmentQuestion.Count + Num: @ExamStruct.ChildExamQuestions.Count 总分: @ExamStruct.Score 分 - - - @ExamStruct.StructType - @(ExamStruct.QType == string.Empty ? "" : QuestionTypes[ExamStruct.QType].DisplayName) + @* @ExamStruct.Type.Name *@ @if(ExamStruct.Question!=null) { - + @* *@ } @@ -36,41 +28,16 @@ } - @foreach (var examStruct in ExamStruct.ChildrenAssignmentQuestion) - { - "background-color: #ececec", - AssignmentStructType.Group => "background-color: #ffffff", - AssignmentStructType.Struct => "background-color: #cccccccc", - AssignmentStructType.SubQuestion => "background-color: #ffffff", - AssignmentStructType.Option => "background-color: #ffffff", - _ => "background-color: transparent" - }) /> - } - -@* Style=@(examStruct.StructType switch - { - AssignmentStructType.Question => "background-color: #ffffff", - AssignmentStructType.Composite => "background-color: #ececec", - AssignmentStructType.Struct => "background-color: #dcdcdc", - AssignmentStructType.SubQuestion => "background-color: #ffffff", - AssignmentStructType.Option => "background-color: #dddddd", - _ => "background-color: transparent" - }) *@ - @code { [Parameter] - public AssignmentQuestionDto ExamStruct { get; set; } = new AssignmentQuestionDto(); + public ExamQuestionDto ExamStruct { get; set; } = new ExamQuestionDto(); [Parameter] - public EventCallback ClickedStruct { get; set; } + public EventCallback ClickedStruct { get; set; } [Parameter] public string Class { get; set; } = "my-2 pa-1"; @@ -81,20 +48,11 @@ [Parameter] public string Style { get; set; } = "background-color : #eeeeee"; - Dictionary QuestionTypes = new Dictionary(); - [Inject] private ILocalStorageService LocalStorageService { get; set; } protected override void OnInitialized() { base.OnInitialized(); - - var cs = LocalStorageService.GetItem("GlobalInfo"); - var GlobalInfo = JsonConvert.DeserializeObject>(cs); - if (GlobalInfo != null) - { - QuestionTypes = GlobalInfo; - } } private async void HandleClick() @@ -102,14 +60,14 @@ await ClickedStruct.InvokeAsync(ExamStruct); } - private async void HandleChildStructClick(AssignmentQuestionDto clickedChildExamStruct) + private async void HandleChildStructClick(ExamQuestionDto clickedChildExamStruct) { await ClickedStruct.InvokeAsync(clickedChildExamStruct); } private void HandleSelected(int num) { - ExamStruct.Question.DifficultyLevel = (DifficultyLevel)num; + // ExamStruct.Question.DifficultyLevel = (DifficultyLevel)num; } } \ No newline at end of file diff --git a/TechHelper.Client/Pages/Exam/ExamView/ExamView.razor b/TechHelper.Client/Pages/Exam/ExamView/ExamView.razor index 77569c4..95f8d5e 100644 --- a/TechHelper.Client/Pages/Exam/ExamView/ExamView.razor +++ b/TechHelper.Client/Pages/Exam/ExamView/ExamView.razor @@ -24,10 +24,10 @@ else @code { [Parameter] - public AssignmentDto ParsedExam { get; set; } = new AssignmentDto(); + public ExamDto ParsedExam { get; set; } = new ExamDto(); [Parameter] - public EventCallback ClickedStruct { get; set; } + public EventCallback ClickedStruct { get; set; } [Parameter] public string Height { get; set; } = "100%"; @@ -39,7 +39,7 @@ else public string Style { get; set; } = ""; - private void HandleClickedStruct(AssignmentQuestionDto dto) + private void HandleClickedStruct(ExamQuestionDto dto) { ClickedStruct.InvokeAsync(dto); } diff --git a/TechHelper.Client/Pages/Exam/QuestionCard/QuestionCard.razor b/TechHelper.Client/Pages/Exam/QuestionCard/QuestionCard.razor index 6e64b6d..2d5d1d7 100644 --- a/TechHelper.Client/Pages/Exam/QuestionCard/QuestionCard.razor +++ b/TechHelper.Client/Pages/Exam/QuestionCard/QuestionCard.razor @@ -30,7 +30,7 @@ public QuestionDto Question { get; set; } = new QuestionDto(); [Parameter] - public AssignmentStructType Type { get; set; } = AssignmentStructType.Question; + public ExamStructType Type { get; set; } = ExamStructType.Question; [Parameter] public byte Index { get; set; } = 0; diff --git a/TechHelper.Client/Pages/Exam/QuestionCard/QuestionEdit.razor b/TechHelper.Client/Pages/Exam/QuestionCard/QuestionEdit.razor index 3432676..dd0c01b 100644 --- a/TechHelper.Client/Pages/Exam/QuestionCard/QuestionEdit.razor +++ b/TechHelper.Client/Pages/Exam/QuestionCard/QuestionEdit.razor @@ -1,5 +1,5 @@ -@using Entities.DTO -@using Entities.Contracts +@using Entities.Contracts +@using Entities.DTO @using Newtonsoft.Json @using TechHelper.Client.Exam @@ -8,13 +8,10 @@ @* @Question.Id *@ 问题属性 - - +@* @foreach (var item in QuestionTypes) { var qt = item; - @* Style = "@($"background - color:{ item.Value.Color} ")"*@ - } - + *@ + + @@ -35,7 +34,7 @@ [Parameter] public QuestionDto Question { get; set; } = new QuestionDto(); public int diffi = 0; - Dictionary QuestionTypes = new Dictionary(); + // Dictionary QuestionTypes = new Dictionary(); [Inject] private ILocalStorageService LocalStorageService { get; set; } @@ -43,26 +42,23 @@ { base.OnInitialized(); - var cs = LocalStorageService.GetItem("GlobalInfo"); - var GlobalInfo = JsonConvert.DeserializeObject>(cs); - if (GlobalInfo != null) - { - QuestionTypes = GlobalInfo; - } + // var cs = LocalStorageService.GetItem("GlobalInfo"); + // var GlobalInfo = JsonConvert.DeserializeObject>(cs); + // if (GlobalInfo != null) + // { + // } } private void HandleSelectedValueChanged(QuestionType type) { - Question.Type = type; } private void HandleSelected(int num) { - Question.DifficultyLevel = (DifficultyLevel)num; + // Question.DifficultyLevel = (DifficultyLevel)num; } private void HandleQTSelectedValueChanged(string type) { - Question.QType = type; StateHasChanged(); } } diff --git a/TechHelper.Client/Pages/Home.razor b/TechHelper.Client/Pages/Home.razor index 94a006a..c4b63d7 100644 --- a/TechHelper.Client/Pages/Home.razor +++ b/TechHelper.Client/Pages/Home.razor @@ -1,12 +1,17 @@ @page "/" @using Microsoft.AspNetCore.Authorization @using TechHelper.Client.Pages.Common.Exam - +@* + +

Loading...

+
-
+ *@ + +Hello @code { [CascadingParameter] private Task authenticationStateTask { get; set; } @@ -14,6 +19,5 @@ protected override Task OnInitializedAsync() { return base.OnInitializedAsync(); - Console.WriteLine(authenticationStateTask.Result.User.IsInRole("Student")); } } \ No newline at end of file diff --git a/TechHelper.Client/Pages/Manage/Class.razor b/TechHelper.Client/Pages/Manage/Class.razor index e524ecd..90b69e0 100644 --- a/TechHelper.Client/Pages/Manage/Class.razor +++ b/TechHelper.Client/Pages/Manage/Class.razor @@ -18,7 +18,7 @@ @foreach (UserRoles item in Enum.GetValues(typeof(UserRoles))) { - if (item != UserRoles.Administrator) + if (item != UserRoles.Admin) { @item.ToString() } diff --git a/TechHelper.Client/Pages/Student/BaseInfoCard/StudentSubmissionPreviewTableCard.razor b/TechHelper.Client/Pages/Student/BaseInfoCard/StudentSubmissionPreviewTableCard.razor index 68cec7a..f11f3a3 100644 --- a/TechHelper.Client/Pages/Student/BaseInfoCard/StudentSubmissionPreviewTableCard.razor +++ b/TechHelper.Client/Pages/Student/BaseInfoCard/StudentSubmissionPreviewTableCard.razor @@ -1,5 +1,6 @@ @using TechHelper.Client.Services @inject IStudentSubmissionService StudentSubmissionService +@using Entities.DTO @@ -60,7 +61,7 @@ if (result.Status && result.Result != null) { // 从服务器获取的数据映射到我们的模型 - var submissions = result.Result as List; + var submissions = result.Result as List; if (submissions != null) { diff --git a/TechHelper.Client/Pages/Teacher/StudentCard.razor b/TechHelper.Client/Pages/Teacher/StudentCard.razor index 159f068..2df691b 100644 --- a/TechHelper.Client/Pages/Teacher/StudentCard.razor +++ b/TechHelper.Client/Pages/Teacher/StudentCard.razor @@ -3,7 +3,7 @@ @code { [Parameter] - public StudentDto StudentDto{ get; set; } + public StudentExamDetailDto StudentDto{ get; set; } diff --git a/TechHelper.Client/Pages/Teacher/StudentsView.razor b/TechHelper.Client/Pages/Teacher/StudentsView.razor index e16326f..53aff10 100644 --- a/TechHelper.Client/Pages/Teacher/StudentsView.razor +++ b/TechHelper.Client/Pages/Teacher/StudentsView.razor @@ -16,7 +16,7 @@ [CascadingParameter] private Task authenticationStateTask { get; set; } - private List ClassStudents { get; set; } = new List(); + private List ClassStudents { get; set; } = new List(); [Inject] public IClassServices ClassServices { get; set; } @@ -24,7 +24,7 @@ protected override async Task OnInitializedAsync() { var result = await ClassServices.GetClassStudents(); - ClassStudents = result.Result as List ?? new List(); + ClassStudents = result.Result as List ?? new List(); StateHasChanged(); } } diff --git a/TechHelper.Client/Program.cs b/TechHelper.Client/Program.cs index 9154779..516ea97 100644 --- a/TechHelper.Client/Program.cs +++ b/TechHelper.Client/Program.cs @@ -47,7 +47,6 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddHttpClient("WebApiClient", client => { diff --git a/TechHelper.Client/Services/ClasssServices.cs b/TechHelper.Client/Services/ClasssServices.cs index 44c459e..554d4b2 100644 --- a/TechHelper.Client/Services/ClasssServices.cs +++ b/TechHelper.Client/Services/ClasssServices.cs @@ -1,9 +1,7 @@ -using Entities.Contracts; -using Entities.DTO; +using Entities.DTO; using Newtonsoft.Json; using System.Net.Http.Json; using TechHelper.Client.HttpRepository; -using TechHelper.Services; namespace TechHelper.Client.Services { @@ -38,7 +36,7 @@ namespace TechHelper.Client.Services { var result = await _client.PostAsJsonAsync("class/getClassStudents",""); var content = await result.Content.ReadAsStringAsync(); - var users = JsonConvert.DeserializeObject>(content); + var users = JsonConvert.DeserializeObject>(content); return ApiResponse.Success(result: users); } catch(Exception ex) @@ -63,7 +61,7 @@ namespace TechHelper.Client.Services } } - public StudentDto GetStudents(byte Class) + public StudentExamDetailDto GetStudents(byte Class) { try { @@ -71,18 +69,18 @@ namespace TechHelper.Client.Services var content = result.Result.Content.ReadAsStringAsync(); if (content.Result != null) { - var users = JsonConvert.DeserializeObject(content.Result); + var users = JsonConvert.DeserializeObject(content.Result); return users; } else { - return new StudentDto(); + return new StudentExamDetailDto(); } } catch (Exception ex) { Console.WriteLine($"获取失败,{ex.Message}, InnerException: {ex.InnerException}"); - return new StudentDto(); + return new StudentExamDetailDto(); } } diff --git a/TechHelper.Client/Services/CommonService.cs b/TechHelper.Client/Services/CommonService.cs new file mode 100644 index 0000000..fa37fdc --- /dev/null +++ b/TechHelper.Client/Services/CommonService.cs @@ -0,0 +1,47 @@ +using Entities.Contracts; +using Entities.DTO; +using System.Net.Http.Json; +using TechHelper.Client.HttpRepository; + +namespace TechHelper.Client.Services +{ + + public class CommonService : ICommonService + { + private readonly HttpClient _client; + private readonly IAuthenticationClientService _authenticationClientService; + + public CommonService(HttpClient client, IAuthenticationClientService authenticationClientService) + { + _client = client; + _authenticationClientService = authenticationClientService; + } + public async Task> GetCommonTypesAsync(TypeNameType typeNameType, Guid? SubjectId = null) + { + + switch (typeNameType) + { + case TypeNameType.Subject: + { + var response = await _client.GetAsync("subject"); + var result = await response.Content.ReadFromJsonAsync>(); + return result; + } + case TypeNameType.ExamType: + { + var response = await _client.GetAsync("exam-type"); + var result = await response.Content.ReadFromJsonAsync>(); + return result; + } + case TypeNameType.QuestionType: + { + var response = await _client.GetAsync("question-type"); + var result = await response.Content.ReadFromJsonAsync>(); + return result; + } + } + + throw new NotImplementedException(); + } + } +} diff --git a/TechHelper.Client/Services/ExamService.cs b/TechHelper.Client/Services/ExamService.cs index e1ecbe8..b558901 100644 --- a/TechHelper.Client/Services/ExamService.cs +++ b/TechHelper.Client/Services/ExamService.cs @@ -1,6 +1,5 @@ using System.Xml.Serialization; // 用于 XML 序列化/反序列化 using TechHelper.Client.AI; -using TechHelper.Services; using Entities.DTO; using System.Net.Http.Json; // 用于 PostAsJsonAsync using Newtonsoft.Json; @@ -93,7 +92,7 @@ namespace TechHelper.Client.Services if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); - var result = JsonConvert.DeserializeObject>(content); + var result = JsonConvert.DeserializeObject>(content); return ApiResponse.Success(result: result); } else @@ -112,7 +111,7 @@ namespace TechHelper.Client.Services if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); - var exam = JsonConvert.DeserializeObject(content); + var exam = JsonConvert.DeserializeObject(content); return ApiResponse.Success(); } return ApiResponse.Error(message: "获取失败"); @@ -130,7 +129,7 @@ namespace TechHelper.Client.Services if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); - var exam = JsonConvert.DeserializeObject(content); + var exam = JsonConvert.DeserializeObject(content); return ApiResponse.Success(result: exam); } else @@ -162,7 +161,7 @@ namespace TechHelper.Client.Services } } - public async Task SaveParsedExam(AssignmentDto assiDto) + public async Task SaveParsedExam(ExamDto assiDto) { // 直接使用注入的 _client 实例 var response = await _client.PostAsJsonAsync("exam/add", assiDto); diff --git a/TechHelper.Client/Services/IClassServices.cs b/TechHelper.Client/Services/IClassServices.cs index 9733f95..5a2fd69 100644 --- a/TechHelper.Client/Services/IClassServices.cs +++ b/TechHelper.Client/Services/IClassServices.cs @@ -1,6 +1,5 @@ using Entities.DTO; using System.Net; -using TechHelper.Services; namespace TechHelper.Client.Services { @@ -10,6 +9,6 @@ namespace TechHelper.Client.Services public Task CreateClass(UserRegistrationToClassDto userClass); public Task GetClassStudents(); public Task GetGradeClasses(byte grade); - public StudentDto GetStudents(byte Class); + public StudentExamDetailDto GetStudents(byte Class); } } diff --git a/TechHelper.Client/Services/ICommonService.cs b/TechHelper.Client/Services/ICommonService.cs new file mode 100644 index 0000000..c234b37 --- /dev/null +++ b/TechHelper.Client/Services/ICommonService.cs @@ -0,0 +1,10 @@ +using Entities.Contracts; +using Entities.DTO; + +namespace TechHelper.Client.Services +{ + public interface ICommonService + { + public Task> GetCommonTypesAsync(TypeNameType typeNameType, Guid? SubjectId = null); + } +} diff --git a/TechHelper.Client/Services/IExamService.cs b/TechHelper.Client/Services/IExamService.cs index f04c733..21d1f85 100644 --- a/TechHelper.Client/Services/IExamService.cs +++ b/TechHelper.Client/Services/IExamService.cs @@ -1,5 +1,4 @@ using Entities.DTO; -using TechHelper.Services; namespace TechHelper.Client.Services { @@ -7,7 +6,7 @@ namespace TechHelper.Client.Services { public Task FormatExam(string examContent); public Task DividExam(string examContent); - public Task SaveParsedExam(AssignmentDto assiDto); + public Task SaveParsedExam(ExamDto assiDto); public Task ParseSingleQuestionGroup(string examContent); public ApiResponse ConvertToXML(string xmlContent); diff --git a/TechHelper.Client/Services/INoteService.cs b/TechHelper.Client/Services/INoteService.cs deleted file mode 100644 index 729e29a..0000000 --- a/TechHelper.Client/Services/INoteService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Entities.DTO; -using TechHelper.Services; - -namespace TechHelper.Client.Services -{ - public interface INoteService - { - public Task AddNote(GlobalDto dto); - public Task DeleteNote(byte id); - public Task GetAllNotes(); - public Task GetNote(byte id); - public Task UpdateNote(GlobalDto dto); - } -} diff --git a/TechHelper.Client/Services/IStudentSubmissionService.cs b/TechHelper.Client/Services/IStudentSubmissionService.cs index ca15a6c..b6d9580 100644 --- a/TechHelper.Client/Services/IStudentSubmissionService.cs +++ b/TechHelper.Client/Services/IStudentSubmissionService.cs @@ -1,5 +1,4 @@ using Entities.DTO; -using TechHelper.Services; namespace TechHelper.Client.Services { diff --git a/TechHelper.Client/Services/IUserServices.cs b/TechHelper.Client/Services/IUserServices.cs index 9159fab..ab29475 100644 --- a/TechHelper.Client/Services/IUserServices.cs +++ b/TechHelper.Client/Services/IUserServices.cs @@ -1,4 +1,4 @@ -using TechHelper.Services; +using Entities.DTO; namespace TechHelper.Client.Services { diff --git a/TechHelper.Client/Services/NoteService.cs b/TechHelper.Client/Services/NoteService.cs deleted file mode 100644 index a73e0d7..0000000 --- a/TechHelper.Client/Services/NoteService.cs +++ /dev/null @@ -1,151 +0,0 @@ -using Entities.DTO; -using System.Net.Http.Json; -using TechHelper.Client.AI; -using TechHelper.Services; - -namespace TechHelper.Client.Services -{ - public class NoteService : INoteService - { - private readonly HttpClient _client; - - public NoteService(HttpClient client) - { - _client = client; - } - - /// - /// 添加一个新笔记 - /// - /// 包含笔记数据的数据传输对象 - /// 操作结果 - public async Task AddNote(GlobalDto dto) - { - try - { - var response = await _client.PostAsJsonAsync("note", dto); - - if (response.IsSuccessStatusCode) - { - var result = await response.Content.ReadFromJsonAsync(); - return result ?? ApiResponse.Success("操作成功。"); - } - else - { - var errorContent = await response.Content.ReadAsStringAsync(); - return ApiResponse.Error($"添加失败。状态码: {response.StatusCode}。详情: {errorContent}"); - } - } - catch (HttpRequestException ex) - { - return ApiResponse.Error($"网络请求错误: {ex.Message}"); - } - } - - /// - /// 根据 ID 删除一个笔记 - /// - /// 要删除的笔记的 ID - /// 操作结果 - public async Task DeleteNote(byte id) - { - try - { - var response = await _client.DeleteAsync($"note/{id}"); - - if (response.IsSuccessStatusCode) - { - var result = await response.Content.ReadFromJsonAsync(); - return result ?? ApiResponse.Success("删除成功。"); - } - else - { - var errorContent = await response.Content.ReadAsStringAsync(); - return ApiResponse.Error($"删除失败。状态码: {response.StatusCode}。详情: {errorContent}"); - } - } - catch (HttpRequestException ex) - { - return ApiResponse.Error($"网络请求错误: {ex.Message}"); - } - } - - /// - /// 获取所有笔记 - /// - /// 包含所有笔记列表的操作结果 - public async Task GetAllNotes() - { - try - { - var response = await _client.GetAsync("note"); - - if (response.IsSuccessStatusCode) - { - var result = await response.Content.ReadFromJsonAsync(); - return result ?? ApiResponse.Success("获取成功。"); - } - else - { - var errorContent = await response.Content.ReadAsStringAsync(); - return ApiResponse.Error($"获取失败。状态码: {response.StatusCode}。详情: {errorContent}"); - } - } - catch (HttpRequestException ex) - { - return ApiResponse.Error($"网络请求错误: {ex.Message}"); - } - } - - /// - /// 根据 ID 获取单个笔记 - /// - /// 要获取的笔记的 ID - /// 包含单个笔记数据的操作结果 - public async Task GetNote(byte id) - { - try - { - var response = await _client.GetAsync($"note/{id}"); - - if (response.IsSuccessStatusCode) - { - var result = await response.Content.ReadFromJsonAsync(); - return result ?? ApiResponse.Success("获取成功。"); - } - else - { - var errorContent = await response.Content.ReadAsStringAsync(); - return ApiResponse.Error($"获取失败。状态码: {response.StatusCode}。详情: {errorContent}"); - } - } - catch (HttpRequestException ex) - { - return ApiResponse.Error($"网络请求错误: {ex.Message}"); - } - } - - public async Task UpdateNote(GlobalDto dto) - { - try - { - var response = await _client.PutAsJsonAsync("note", dto); - - if (response.IsSuccessStatusCode) - { - var result = await response.Content.ReadFromJsonAsync(); - return result ?? ApiResponse.Success("更新成功。"); - } - else - { - var errorContent = await response.Content.ReadAsStringAsync(); - return ApiResponse.Error($"更新失败。状态码: {response.StatusCode}。详情: {errorContent}"); - } - } - catch (HttpRequestException ex) - { - return ApiResponse.Error($"网络请求错误: {ex.Message}"); - } - } - } -} diff --git a/TechHelper.Client/Services/StudentSubmissionDetailService.cs b/TechHelper.Client/Services/StudentSubmissionDetailService.cs index 6282dce..f8a5943 100644 --- a/TechHelper.Client/Services/StudentSubmissionDetailService.cs +++ b/TechHelper.Client/Services/StudentSubmissionDetailService.cs @@ -1,5 +1,4 @@ using Entities.DTO; -using TechHelper.Client.HttpRepository; using System.Net.Http.Json; namespace TechHelper.Client.Services diff --git a/TechHelper.Client/Services/StudentSubmissionService.cs b/TechHelper.Client/Services/StudentSubmissionService.cs index 620256e..516c02a 100644 --- a/TechHelper.Client/Services/StudentSubmissionService.cs +++ b/TechHelper.Client/Services/StudentSubmissionService.cs @@ -1,7 +1,5 @@ -using Entities.DTO; -using TechHelper.Services; -using System.Net.Http.Json; using Newtonsoft.Json; +using Entities.DTO; namespace TechHelper.Client.Services { diff --git a/TechHelper.Client/Services/UserServices.cs b/TechHelper.Client/Services/UserServices.cs index 3096755..951aa57 100644 --- a/TechHelper.Client/Services/UserServices.cs +++ b/TechHelper.Client/Services/UserServices.cs @@ -1,4 +1,4 @@ -using TechHelper.Services; +using Entities.DTO; namespace TechHelper.Client.Services { diff --git a/TechHelper.Client/wwwroot/index.html b/TechHelper.Client/wwwroot/index.html index 9db845f..1577b9c 100644 --- a/TechHelper.Client/wwwroot/index.html +++ b/TechHelper.Client/wwwroot/index.html @@ -36,10 +36,10 @@ - + --> diff --git a/TechHelper.Server.Tests/Services/User/UserServicesTests.cs b/TechHelper.Server.Tests/Services/User/UserServicesTests.cs new file mode 100644 index 0000000..4c22710 --- /dev/null +++ b/TechHelper.Server.Tests/Services/User/UserServicesTests.cs @@ -0,0 +1,340 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Identity; +using Moq; +using SharedDATA.Api; +using TechHelper.Features; +using TechHelper.Services.Beta; +using Xunit; + +namespace TechHelper.Server.Tests +{ + public class UserServicesTests + { + private readonly Mock _unitOfWorkMock; + private readonly Mock _classServiceMock; + private readonly Mock> _userManagerMock; + private readonly Mock _mapperMock; + private readonly Mock _emailSenderMock; + private readonly UserServices _userServices; + + public UserServicesTests() + { + _unitOfWorkMock = new Mock(); + _classServiceMock = new Mock(); + _userManagerMock = new Mock>( + Mock.Of>(), + null, null, null, null, null, null, null, null); + _mapperMock = new Mock(); + _emailSenderMock = new Mock(); + + _userServices = new UserServices( + _unitOfWorkMock.Object, + _classServiceMock.Object, + _userManagerMock.Object, + _mapperMock.Object, + _emailSenderMock.Object); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenEmailAlreadyExists_ReturnsErrorMessage() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "user@example.com", + Password = "wx1998WX!", + ConfirmPassword = "wx1998WX!", + DisplayName = "Test User", + Roles = UserRoles.Student + }; + + var existingUser = new User { Email = "user@example.com" }; + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync(existingUser); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.Contains("此电子邮件地址已被注册", result.Message); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenUserCreationFails_ReturnsErrorWithErrors() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Password too weak" })); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.NotNull(result.Result); + Assert.IsType>(result.Result); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenUserCreatedButNotFound_ReturnsErrorMessage() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + var identityResult = IdentityResult.Success; + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ReturnsAsync(identityResult); + + _userManagerMock.Setup(x => x.FindByEmailAsync(user.Email)) + .ReturnsAsync((User)null!); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.Contains("注册失败,请联系管理员", result.Message); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenRoleAssignmentFails_ReturnsError() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + var identityResult = IdentityResult.Success; + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ReturnsAsync(identityResult); + + var createdUser = new User { Id = Guid.NewGuid(), Email = registrationDto.Email }; + _userManagerMock.Setup(x => x.FindByEmailAsync(user.Email)) + .ReturnsAsync(createdUser); + + _userManagerMock.Setup(x => x.AddToRoleAsync(createdUser, registrationDto.Roles.ToString())) + .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Role assignment failed" })); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.NotNull(result.Result); + Assert.IsType>(result.Result); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenClassRegistrationFails_DeletesUserAndReturnsError() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student, + RegisterUserToClassDto = new RegisterUserToClassDto + { + UserId = Guid.NewGuid(), + ClassId = Guid.NewGuid() + } + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + var identityResult = IdentityResult.Success; + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ReturnsAsync(identityResult); + + var createdUser = new User { Id = Guid.NewGuid(), Email = registrationDto.Email }; + _userManagerMock.Setup(x => x.FindByEmailAsync(user.Email)) + .ReturnsAsync(createdUser); + + _userManagerMock.Setup(x => x.AddToRoleAsync(createdUser, registrationDto.Roles.ToString())) + .ReturnsAsync(IdentityResult.Success); + + _classServiceMock.Setup(x => x.UserRegister(registrationDto.RegisterUserToClassDto)) + .ReturnsAsync(new ApiResponse(false, "Class registration failed")); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.Contains("Class registration failed", result.Message); + + // Verify that the user was deleted + _userManagerMock.Verify(x => x.DeleteAsync(createdUser), Times.Once); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenAllStepsSucceed_ReturnsSuccess() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student, + RegisterUserToClassDto = new RegisterUserToClassDto + { + UserId = Guid.NewGuid(), + ClassId = Guid.NewGuid() + } + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + var identityResult = IdentityResult.Success; + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ReturnsAsync(identityResult); + + var createdUser = new User { Id = Guid.NewGuid(), Email = registrationDto.Email }; + _userManagerMock.Setup(x => x.FindByEmailAsync(user.Email)) + .ReturnsAsync(createdUser); + + _userManagerMock.Setup(x => x.AddToRoleAsync(createdUser, registrationDto.Roles.ToString())) + .ReturnsAsync(IdentityResult.Success); + + _classServiceMock.Setup(x => x.UserRegister(registrationDto.RegisterUserToClassDto)) + .ReturnsAsync(new ApiResponse(true, "操作成功。")); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.True(result.Status); + Assert.Equal("操作成功。", result.Message); + } + + [Fact] + public async Task RegisterNewUserAsync_WhenExceptionOccurs_DeletesUserAndReturnsError() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Student + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var user = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(user); + + _userManagerMock.Setup(x => x.CreateAsync(user, registrationDto.Password)) + .ThrowsAsync(new Exception("Database error")); + + var createdUser = new User { Id = Guid.NewGuid(), Email = registrationDto.Email }; + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync(createdUser); + + // Act + var result = await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.False(result.Status); + Assert.Contains("注册过程中发生错误", result.Message); + + // Verify that the user was deleted + _userManagerMock.Verify(x => x.DeleteAsync(createdUser), Times.Once); + } + + [Fact] + public async Task RegisterNewUserAsync_SetsCorrectUserProperties() + { + // Arrange + var registrationDto = new UserForRegistrationDto + { + Email = "test@example.com", + Password = "Password123!", + ConfirmPassword = "Password123!", + DisplayName = "Test User", + Roles = UserRoles.Teacher + }; + + _userManagerMock.Setup(x => x.FindByEmailAsync(registrationDto.Email)) + .ReturnsAsync((User)null!); + + var mappedUser = new User(); + _mapperMock.Setup(x => x.Map(registrationDto)) + .Returns(mappedUser); + + // Act + await _userServices.RegisterNewUserAsync(registrationDto); + + // Assert + Assert.Equal(registrationDto.Email, mappedUser.UserName); + Assert.Equal(registrationDto.DisplayName, mappedUser.DisplayName); + Assert.Equal(registrationDto.Roles, mappedUser.Role); + Assert.False(mappedUser.EmailConfirmed); + } + } +} diff --git a/TechHelper.Server.Tests/TechHelper.Server.Tests.csproj b/TechHelper.Server.Tests/TechHelper.Server.Tests.csproj new file mode 100644 index 0000000..c55694c --- /dev/null +++ b/TechHelper.Server.Tests/TechHelper.Server.Tests.csproj @@ -0,0 +1,32 @@ + + + + net9.0 + enable + enable + false + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/TechHelper.Server.Tests/UnitTest1.cs b/TechHelper.Server.Tests/UnitTest1.cs new file mode 100644 index 0000000..e2f5633 --- /dev/null +++ b/TechHelper.Server.Tests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace TechHelper.Server.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} diff --git a/TechHelper.Server/Context/ApplicationContext.cs b/TechHelper.Server/Context/ApplicationContext.cs index 678c56e..feb1a01 100644 --- a/TechHelper.Server/Context/ApplicationContext.cs +++ b/TechHelper.Server/Context/ApplicationContext.cs @@ -1,5 +1,4 @@ -using TechHelper.Context.Configuration; -using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Entities.Contracts; @@ -11,31 +10,29 @@ namespace TechHelper.Context public ApplicationContext(DbContextOptions options) : base(options) { } - public DbSet AssignmentClasses { get; set; } - public DbSet Assignments { get; set; } - public DbSet AssignmentQuestions { get; set; } + public DbSet Schools { get; set; } + public DbSet Grades { get; set; } public DbSet Classes { get; set; } - public DbSet ClassStudents { get; set; } - public DbSet ClassTeachers { get; set; } + public DbSet Exams { get; set; } + public DbSet ExamQuestions { get; set; } + public DbSet ExamAttachments{ get; set; } + public DbSet ExamTypes { get; set; } public DbSet Questions { get; set; } public DbSet Submissions { get; set; } public DbSet SubmissionDetails { get; set; } public DbSet QuestionContexts { get; set; } - public DbSet Globals { get; set; } - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); - builder.ApplyConfiguration(new RoleConfiguration()); - builder.ApplyConfiguration(new AssignmentConfiguration()); - builder.ApplyConfiguration(new AssignmentClassConfiguration()); - builder.ApplyConfiguration(new AssignmentQuestionConfiguration()); - builder.ApplyConfiguration(new ClassConfiguration()); - builder.ApplyConfiguration(new ClassStudentConfiguration()); - builder.ApplyConfiguration(new ClassTeacherConfiguration()); - builder.ApplyConfiguration(new QuestionConfiguration()); - builder.ApplyConfiguration(new SubmissionConfiguration()); - builder.ApplyConfiguration(new SubmissionDetailConfiguration()); - } + //protected override void OnModelCreating(ModelBuilder builder) + //{ + // base.OnModelCreating(builder); + // builder.ApplyConfiguration(new RoleConfiguration()); + // builder.ApplyConfiguration(new AssignmentConfiguration()); + // builder.ApplyConfiguration(new AssignmentClassConfiguration()); + // builder.ApplyConfiguration(new AssignmentQuestionConfiguration()); + // builder.ApplyConfiguration(new ClassConfiguration()); + // builder.ApplyConfiguration(new QuestionConfiguration()); + // builder.ApplyConfiguration(new SubmissionConfiguration()); + // builder.ApplyConfiguration(new SubmissionDetailConfiguration()); + //} } } diff --git a/TechHelper.Server/Context/AutoMapperProFile.cs b/TechHelper.Server/Context/AutoMapperProFile.cs index 20ecde1..ecb3d7f 100644 --- a/TechHelper.Server/Context/AutoMapperProFile.cs +++ b/TechHelper.Server/Context/AutoMapperProFile.cs @@ -1,11 +1,7 @@ using AutoMapper; -using AutoMapper.Internal.Mappers; using Entities.Contracts; using Entities.DTO; -using Newtonsoft.Json; -using System.Net.Http.Json; -using System.Text.Json; -using System.Text.Json.Serialization; +using Entities.DTO.Class; namespace TechHelper.Context { @@ -28,53 +24,91 @@ namespace TechHelper.Context { CreateMap() .ForMember(dest => dest.Id, opt => opt.Ignore()) - .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Name)) + .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.DisplayName)) .ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email)) .ForMember(dest => dest.PhoneNumber, opt => opt.MapFrom(src => src.PhoneNumber)) - .ForMember(dest => dest.Address, opt => opt.MapFrom(src => src.HomeAddress)) + .ForMember(dest => dest.HomeAddress, opt => opt.MapFrom(src => src.HomeAddress)) .ForMember(dest => dest.PasswordHash, opt => opt.Ignore()) .ForMember(dest => dest.EmailConfirmed, opt => opt.Ignore()); - CreateMap() - .ForMember(d => d.Number, o => o.MapFrom(src => src.Class)) - .ReverseMap(); + // Subject + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // ExamType + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // QuestionType + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + // Exam + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); - // Assignment - CreateMap().ReverseMap(); - - CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap().ReverseMap(); - CreateMap().ReverseMap(); - - - - // Submission CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); // Student Submission Detail CreateMap() - .ForMember(dest => dest.AssignmentId, opt => opt.MapFrom(src => src.AssignmentId)) + .ForMember(dest => dest.AssignmentId, opt => opt.MapFrom(src => src.ExamId)) .ForMember(dest => dest.StudentId, opt => opt.MapFrom(src => src.StudentId)) .ForMember(dest => dest.SubmissionTime, opt => opt.MapFrom(src => src.SubmissionTime)) .ForMember(dest => dest.OverallGrade, opt => opt.MapFrom(src => src.OverallGrade)) .ForMember(dest => dest.OverallFeedback, opt => opt.MapFrom(src => src.OverallFeedback)) .ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.Status)); - CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); - CreateMap() - .ForMember(dest => dest.Info, opt => opt.MapFrom(src => JsonConvert.SerializeObject(src.Data))); - CreateMap() - .ForMember(dest => dest.Data, opt => opt.MapFrom(src => JsonConvert.DeserializeObject>(src.Info))); + // School + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + // Grade + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + + // Class + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + + // User + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // KeyPoint + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // Lesson + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + + // Textbook + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap() + .ForMember(dest => dest.LessonCount, opt => opt.MapFrom(src => src.Lessons.Count)) + .ForMember(dest => dest.LessonTitles, opt => opt.MapFrom(src => src.Lessons.Select(l => l.Title).ToList())); } } diff --git a/TechHelper.Server/Context/Configuration/AssignmentAttachmentConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentAttachmentConfiguration.cs index 8085f51..03a0bb2 100644 --- a/TechHelper.Server/Context/Configuration/AssignmentAttachmentConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/AssignmentAttachmentConfiguration.cs @@ -4,9 +4,9 @@ using Microsoft.EntityFrameworkCore; namespace TechHelper.Context.Configuration { - public class AssignmentAttachmentConfiguration : IEntityTypeConfiguration + public class AssignmentAttachmentConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { builder.ToTable("assignment_attachments"); @@ -38,8 +38,8 @@ namespace TechHelper.Context.Configuration .HasDefaultValue(false); // Configure the relationship explicitly - builder.HasOne(aa => aa.Assignment) // An AssignmentAttachment has one Assignment - .WithMany(a => a.AssignmentAttachments) // An Assignment has many AssignmentAttachments (assuming 'Attachments' collection in Assignment) + builder.HasOne(aa => aa.Exam) // An AssignmentAttachment has one Assignment + .WithMany(a => a.ExamAttachments) // An Assignment has many AssignmentAttachments (assuming 'Attachments' collection in Assignment) .HasForeignKey(aa => aa.AssignmentId) // The foreign key is AssignmentAttachment.AssignmentId .IsRequired() // It's a required relationship based on your [Required] attribute .OnDelete(DeleteBehavior.Cascade); // If an Assignment is deleted, its attachments should also be deleted diff --git a/TechHelper.Server/Context/Configuration/AssignmentClassConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentClassConfiguration.cs index f47fbcd..eb5e5f8 100644 --- a/TechHelper.Server/Context/Configuration/AssignmentClassConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/AssignmentClassConfiguration.cs @@ -4,18 +4,18 @@ using Microsoft.EntityFrameworkCore; namespace TechHelper.Context.Configuration { - public class AssignmentClassConfiguration : IEntityTypeConfiguration + public class AssignmentClassConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { // 设置表名为 "assignment_class" builder.ToTable("assignment_class"); // 设置复合主键 - builder.HasKey(ac => new { ac.AssignmentId, ac.ClassId }); + builder.HasKey(ac => new { ac.ExamId, ac.ClassId }); // 配置 AssignmentId 列名 - builder.Property(ac => ac.AssignmentId) + builder.Property(ac => ac.ExamId) .HasColumnName("assignment_id"); // 配置 ClassId 列名 @@ -34,15 +34,15 @@ namespace TechHelper.Context.Configuration // 配置到 Assignment 的关系 (多对一) // 假设 Assignment 类中有一个名为 AssignmentClasses 的集合属性 - builder.HasOne(ac => ac.Assignment) // AssignmentClass 有一个 Assignment + builder.HasOne(ac => ac.Exam) // AssignmentClass 有一个 Assignment .WithMany(a => a.AssignmentClasses) // Assignment 有多个 AssignmentClass 记录 - .HasForeignKey(ac => ac.AssignmentId) // 通过 AssignmentId 建立外键 + .HasForeignKey(ac => ac.ExamId) // 通过 AssignmentId 建立外键 .OnDelete(DeleteBehavior.Cascade); // 当 Assignment 被删除时,相关的 AssignmentClass 记录也级联删除 // 配置到 Class 的关系 (多对一) // 假设 Class 类中有一个名为 AssignmentClasses 的集合属性 builder.HasOne(ac => ac.Class) // AssignmentClass 有一个 Class - .WithMany(c => c.AssignmentClasses) // Class 有多个 AssignmentClass 记录 + .WithMany(c => c.ExamClasses) // Class 有多个 AssignmentClass 记录 .HasForeignKey(ac => ac.ClassId) // 通过 ClassId 建立外键 .OnDelete(DeleteBehavior.Cascade); // 当 Class 被删除时,相关的 AssignmentClass 记录也级联删除 } diff --git a/TechHelper.Server/Context/Configuration/AssignmentConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentConfiguration.cs index 4192749..2cd601a 100644 --- a/TechHelper.Server/Context/Configuration/AssignmentConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/AssignmentConfiguration.cs @@ -5,9 +5,9 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace TechHelper.Context.Configuration { - public class AssignmentConfiguration : IEntityTypeConfiguration + public class AssignmentConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { builder.ToTable("assignments"); @@ -61,7 +61,7 @@ namespace TechHelper.Context.Configuration builder.HasOne(a=>a.ExamStruct) .WithOne() - .HasForeignKey(a=>a.ExamStructId) + .HasForeignKey(a=>a.ExamStructId) .OnDelete(DeleteBehavior.Cascade); } diff --git a/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs b/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs index 0d435f2..6273635 100644 --- a/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/AssignmentQuestionConfiguration.cs @@ -4,9 +4,9 @@ using Microsoft.EntityFrameworkCore; namespace TechHelper.Context.Configuration { - public class AssignmentQuestionConfiguration : IEntityTypeConfiguration + public class AssignmentQuestionConfiguration : IEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public void Configure(EntityTypeBuilder builder) { // 1. 设置表名 builder.ToTable("assignment_questions"); @@ -44,13 +44,13 @@ namespace TechHelper.Context.Configuration builder.HasOne(aq => aq.Question) - .WithMany(q => q.AssignmentQuestions) + .WithMany(q => q.ExamQuestions) .HasForeignKey(aq => aq.QuestionId) .OnDelete(DeleteBehavior.Cascade); - builder.HasOne(aq => aq.ParentAssignmentQuestion) + builder.HasOne(aq => aq.ParentExamQuestion) .WithMany(aq => aq.ChildrenAssignmentQuestion) - .HasForeignKey(aq => aq.ParentAssignmentQuestionId) + .HasForeignKey(aq => aq.ParentExamQuestionId) .OnDelete(DeleteBehavior.Cascade); builder.HasOne(aq => aq.QuestionContext) diff --git a/TechHelper.Server/Context/Configuration/ClassConfiguration.cs b/TechHelper.Server/Context/Configuration/ClassConfiguration.cs index 421794c..767e002 100644 --- a/TechHelper.Server/Context/Configuration/ClassConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/ClassConfiguration.cs @@ -86,7 +86,7 @@ namespace TechHelper.Context.Configuration // 11. 与 AssignmentClass 的关系 (多对多中间表或一对多) // 一对多:一个 Class 有多个 AssignmentClass。一个 AssignmentClass 属于一个 Class。 // 假设 AssignmentClass 有 'ClassId' 外键和 'Class' 导航属性。 - builder.HasMany(c => c.AssignmentClasses) // Class 中的集合导航属性 + builder.HasMany(c => c.ExamClasses) // Class 中的集合导航属性 .WithOne(ac => ac.Class) // 假设 AssignmentClass 中有 'public Class Class { get; set; }' .HasForeignKey(ac => ac.ClassId) // 假设 AssignmentClass 中有 'public Guid ClassId { get; set; }' .OnDelete(DeleteBehavior.Cascade); // 常见:如果一个班级被删除,其作业关联也应被删除。 diff --git a/TechHelper.Server/Context/Configuration/ClassStudentConfiguration.cs b/TechHelper.Server/Context/Configuration/ClassStudentConfiguration.cs deleted file mode 100644 index f251dea..0000000 --- a/TechHelper.Server/Context/Configuration/ClassStudentConfiguration.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore; - -namespace TechHelper.Context.Configuration -{ - public class ClassStudentConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - // 1. 设置表名 - // 将此实体映射到数据库中名为 "class_student" 的表。 - builder.ToTable("class_student"); - - // 2. 设置复合主键 - // ClassId 和 StudentId 的组合作为主键,确保一个班级中一个学生只有一条入学记录。 - builder.HasKey(cs => new { cs.ClassId, cs.StudentId }); - - // 3. 配置列名和属性特性 - - // 配置 ClassId 属性对应的数据库列名为 "class_id"。 - builder.Property(cs => cs.ClassId) - .HasColumnName("class_id"); - - // 配置 StudentId 属性对应的数据库列名为 "student_id"。 - builder.Property(cs => cs.StudentId) - .HasColumnName("student_id"); - - // 配置 EnrollmentDate 属性对应的数据库列名为 "enrollment_date",并设置为必需字段。 - builder.Property(cs => cs.EnrollmentDate) - .HasColumnName("enrollment_date") - .IsRequired(); - - // 配置 IsDeleted 属性对应的数据库列名为 "deleted",并设置默认值为 false。 - builder.Property(cs => cs.IsDeleted) - .HasColumnName("deleted") - .HasDefaultValue(false); // 常用作软删除标记 - - // 4. 配置导航属性和外键关系 - - // --- - // 配置 ClassStudent 到 Class 的关系 (多对一) - // 一个 ClassStudent 联结记录属于一个 Class。 - // - // 假设 `Class` 实体中有一个名为 `ClassStudents` 的 `ICollection` 集合属性。 - builder.HasOne(cs => cs.Class) // 当前 ClassStudent 链接到一个 Class - .WithMany(c => c.ClassStudents) // 那个 Class 可以有多个 ClassStudent 记录 - .HasForeignKey(cs => cs.ClassId) // 外键是 ClassStudent.ClassId - .OnDelete(DeleteBehavior.Cascade); // 当 Class 被删除时,相关的 ClassStudent 记录也级联删除。 - - // --- - // 配置 ClassStudent 到 User (Student) 的关系 (多对一) - // 一个 ClassStudent 联结记录属于一个 User (作为 Student)。 - // - // 假设 `User` 实体中有一个名为 `EnrolledClassesLink` 的 `ICollection` 集合属性, - // 用于表示该用户所注册的班级联结记录 (与 `ClassTeacherConfiguration` 中的模式类似)。 - builder.HasOne(cs => cs.Student) // 当前 ClassStudent 链接到一个 User (学生) - .WithMany(u => u.EnrolledClassesLink) // 那个 User (学生) 可以有多个 ClassStudent 记录 - .HasForeignKey(cs => cs.StudentId) // 外键是 ClassStudent.StudentId - .OnDelete(DeleteBehavior.Restrict); // 当 User (学生) 被删除时,如果还有相关的 ClassStudent 记录,则会阻止删除。 - // 这是更安全的做法,以避免意外数据丢失。如果你希望学生被删除时,其所有注册关系也一并删除,可改为 DeleteBehavior.Cascade。 - } - } -} diff --git a/TechHelper.Server/Context/Configuration/ClassTeacherConfiguration.cs b/TechHelper.Server/Context/Configuration/ClassTeacherConfiguration.cs deleted file mode 100644 index ffed8b3..0000000 --- a/TechHelper.Server/Context/Configuration/ClassTeacherConfiguration.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore; - -namespace TechHelper.Context.Configuration -{ - public class ClassTeacherConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - // 1. 设置表名 - // 将此实体映射到数据库中名为 "class_teachers" 的表。 - builder.ToTable("class_teachers"); - - // 2. 设置复合主键 - // ClassId 和 TeacherId 的组合作为主键,确保一个班级中一个老师只有一条任教记录。 - // 这要求 ClassTeacher 类中的 ClassId 和 TeacherId 属性上都添加了 [Key] 特性。 - builder.HasKey(ct => new { ct.ClassId, ct.TeacherId }); - - // 3. 配置列名和属性特性 - - // 配置 ClassId 属性对应的数据库列名为 "class_id"。 - builder.Property(ct => ct.ClassId) - .HasColumnName("class_id"); - - // 配置 TeacherId 属性对应的数据库列名为 "teacher_id"。 - builder.Property(ct => ct.TeacherId) - .HasColumnName("teacher_id"); - - // 配置 SubjectTaught 属性对应的数据库列名为 "subject_taught"。 - // 假设 SubjectTaught 可以为空,所以没有 .IsRequired() - builder.Property(ct => ct.SubjectTaught) - .HasColumnName("subject_taught"); - - // 4. 配置导航属性和外键关系 - - // --- - // 配置 ClassTeacher 到 Class 的关系 (多对一) - // 一个 ClassTeacher 联结记录属于一个 Class。 - // - // 假设 `Class` 实体中有一个名为 `ClassTeachers` 的 `ICollection` 集合属性。 - builder.HasOne(ct => ct.Class) // 当前 ClassTeacher 链接到一个 Class - .WithMany(c => c.ClassTeachers) // 那个 Class 可以有多个 ClassTeacher 记录 - .HasForeignKey(ct => ct.ClassId) // 外键是 ClassTeacher.ClassId - .OnDelete(DeleteBehavior.Cascade); // 当 Class 被删除时,相关的 ClassTeacher 记录也级联删除。 - - // --- - // 配置 ClassTeacher 到 User (Teacher) 的关系 (多对一) - // 一个 ClassTeacher 联结记录属于一个 User (作为 Teacher)。 - // - // 假设 `User` 实体中有一个名为 `TaughtClassesLink` 的 `ICollection` 集合属性, - // 用于表示该用户所教授的班级联结记录。 - builder.HasOne(ct => ct.Teacher) // 当前 ClassTeacher 链接到一个 User (老师) - .WithMany(u => u.TaughtClassesLink) // 那个 User (老师) 可以有多个 ClassTeacher 记录 (为所教授的班级) - .HasForeignKey(ct => ct.TeacherId) // 外键是 ClassTeacher.TeacherId - .OnDelete(DeleteBehavior.Cascade); // 当 User (老师) 被删除时,如果还有相关的 ClassTeacher 记录,则会阻止删除。 - // 这通常是防止数据丢失的更安全选择。如果你希望老师被删除时,其所有任教关系也一并删除,可改为 DeleteBehavior.Cascade。 - } - } - -} diff --git a/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs b/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs index ab3df97..d55eca5 100644 --- a/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/QuestionConfiguration.cs @@ -95,7 +95,7 @@ namespace TechHelper.Context.Configuration // // 这个关系的外键配置通常在 "多" 的一方(`AssignmentQuestion` 实体)进行。 // 假设 `AssignmentQuestion` 实体有一个 `QuestionId` 外键和 `Question` 导航属性。 - builder.HasMany(q => q.AssignmentQuestions) // 当前 Question 有多个 AssignmentQuestion + builder.HasMany(q => q.ExamQuestions) // 当前 Question 有多个 AssignmentQuestion .WithOne(aq => aq.Question); // 每一个 AssignmentQuestion 都有一个 Question // .HasForeignKey(aq => aq.QuestionId); // 外键的配置应在 `AssignmentQuestionConfiguration` 中进行 diff --git a/TechHelper.Server/Context/Configuration/SubmissionConfiguration.cs b/TechHelper.Server/Context/Configuration/SubmissionConfiguration.cs index ccb3d72..018ee69 100644 --- a/TechHelper.Server/Context/Configuration/SubmissionConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/SubmissionConfiguration.cs @@ -21,7 +21,7 @@ namespace TechHelper.Context.Configuration .HasColumnName("id"); // AssignmentId - builder.Property(s => s.AssignmentId) + builder.Property(s => s.ExamId) .HasColumnName("assignment_id") .IsRequired(); @@ -67,9 +67,9 @@ namespace TechHelper.Context.Configuration - builder.HasOne(s => s.Assignment) // 当前 Submission 有一个 Assignment + builder.HasOne(s => s.Exam) // 当前 Submission 有一个 Assignment .WithMany(a => a.Submissions) // 那个 Assignment 可以有多个 Submission - .HasForeignKey(s => s.AssignmentId) // 外键是 Submission.AssignmentId + .HasForeignKey(s => s.ExamId) // 外键是 Submission.AssignmentId .OnDelete(DeleteBehavior.Cascade); // 当 Assignment 被删除时,相关的 Submission 也级联删除。 diff --git a/TechHelper.Server/Context/Configuration/SubmissionDetailConfiguration.cs b/TechHelper.Server/Context/Configuration/SubmissionDetailConfiguration.cs index 3d495fb..a60ca02 100644 --- a/TechHelper.Server/Context/Configuration/SubmissionDetailConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/SubmissionDetailConfiguration.cs @@ -23,7 +23,7 @@ namespace TechHelper.Context.Configuration .HasColumnName("student_id") .IsRequired(); - builder.Property(sd => sd.AssignmentQuestionId) + builder.Property(sd => sd.ExamQuestionId) .HasColumnName("assignment_question_id") .IsRequired(); @@ -67,9 +67,9 @@ namespace TechHelper.Context.Configuration .OnDelete(DeleteBehavior.Cascade); // 当 User (学生) 被删除时,如果他/她还有提交详情,则会阻止删除。 // 这是一个更安全的选择,以防止意外数据丢失。 - builder.HasOne(sd => sd.AssignmentQuestion) // 当前 SubmissionDetail 有一个 AssignmentQuestion + builder.HasOne(sd => sd.ExamQuestion) // 当前 SubmissionDetail 有一个 AssignmentQuestion .WithMany(aq => aq.SubmissionDetails) // 那个 AssignmentQuestion 可以有多个 SubmissionDetail 记录 - .HasForeignKey(sd => sd.AssignmentQuestionId) // 外键是 SubmissionDetail.AssignmentQuestionId + .HasForeignKey(sd => sd.ExamQuestionId) // 外键是 SubmissionDetail.AssignmentQuestionId .OnDelete(DeleteBehavior.Cascade); // 当 AssignmentQuestion 被删除时,相关的 SubmissionDetail 记录也级联删除。 } } diff --git a/TechHelper.Server/Context/Configuration/UserConfiguration.cs b/TechHelper.Server/Context/Configuration/UserConfiguration.cs index beaaaee..8b78b8b 100644 --- a/TechHelper.Server/Context/Configuration/UserConfiguration.cs +++ b/TechHelper.Server/Context/Configuration/UserConfiguration.cs @@ -38,7 +38,7 @@ namespace TechHelper.Context.Configuration .OnDelete(DeleteBehavior.Restrict); // 限制删除:如果创建者有题目,则不允许删除 // User 作为创建者,与 Assignment 的关系 (一对多) - builder.HasMany(u => u.CreatedAssignments) // 一个 User 可以创建多个作业 + builder.HasMany(u => u.CreatedExams) // 一个 User 可以创建多个作业 .WithOne(a => a.Creator) // 一个 Assignment 对应一个 Creator .HasForeignKey(a => a.CreatorId) // 外键在 Assignment.CreatedBy .OnDelete(DeleteBehavior.Restrict); // 限制删除:如果创建者有作业,则不允许删除 diff --git a/TechHelper.Server/Context/DbInitializer.cs b/TechHelper.Server/Context/DbInitializer.cs new file mode 100644 index 0000000..32060ad --- /dev/null +++ b/TechHelper.Server/Context/DbInitializer.cs @@ -0,0 +1,22 @@ +using Entities.Contracts; +using Microsoft.AspNetCore.Identity; + +namespace TechHelper.Server.Context +{ + public class DbInitializer + { + public static async Task SeedRoles(RoleManager> roleManager) + { + string[] defaultRoleName = { "Admin", "Teacher", "Student" }; + + foreach (var roleName in defaultRoleName) + { + if (!await roleManager.RoleExistsAsync(roleName)) + { + await roleManager.CreateAsync(new IdentityRole(roleName)); + Console.WriteLine($"Default role '{roleName}' created successfully."); + } + } + } + } +} diff --git a/TechHelper.Server/Controllers/AccountController.cs b/TechHelper.Server/Controllers/AccountController.cs index 3750f23..ce98b7d 100644 --- a/TechHelper.Server/Controllers/AccountController.cs +++ b/TechHelper.Server/Controllers/AccountController.cs @@ -1,12 +1,10 @@ -using TechHelper.Context; -using TechHelper.Services; -using Entities.DTO; -using Microsoft.AspNetCore.Http; +using Entities.DTO; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using TechHelper.Features; using Microsoft.AspNetCore.WebUtilities; using Entities.Contracts; +using TechHelper.Services.Beta; namespace TechHelper.Controllers { @@ -19,9 +17,9 @@ namespace TechHelper.Controllers public class AccountController : ControllerBase { private readonly UserManager _userManager; - private readonly IUserRegistrationService _userRegistrationService; private IAuthenticationService _authenticationService; private readonly IEmailSender _emailSender; + private readonly IUserSerivces _userSerivces; /// /// 初始化账户控制器 @@ -31,13 +29,13 @@ namespace TechHelper.Controllers /// 邮件发送服务 /// 认证服务 public AccountController(UserManager userManager, - IUserRegistrationService userRegistrationService, IEmailSender emailSender, + IUserSerivces userSerivces, IAuthenticationService authenticationService) { _userManager = userManager; - this._userRegistrationService = userRegistrationService; _emailSender = emailSender; + _userSerivces = userSerivces; _authenticationService = authenticationService; } @@ -98,7 +96,7 @@ namespace TechHelper.Controllers if (!ModelState.IsValid) return BadRequest(new ApiResponse(false, ModelState)); - var response = await _userRegistrationService.RegisterNewUserAsync(userForRegistrationDto); + var response = await _userSerivces.RegisterNewUserAsync(userForRegistrationDto); if (response.Status) { @@ -184,6 +182,17 @@ namespace TechHelper.Controllers }); } + [HttpPost("initadmin")] + public async Task InitAdmin([FromBody] UserForAdmin admin) + { + var result = await _userSerivces.InitAdminUser(admin); + if(result.Status) + { + return Ok(result.Message); + } + return BadRequest(result.Message); + } + /// /// 生成两步验证的OTP令牌 /// diff --git a/TechHelper.Server/Controllers/ClassController.cs b/TechHelper.Server/Controllers/ClassController.cs index be9ec2d..041b64b 100644 --- a/TechHelper.Server/Controllers/ClassController.cs +++ b/TechHelper.Server/Controllers/ClassController.cs @@ -1,11 +1,15 @@ using Entities.Contracts; using Entities.DTO; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; using System.Net; using System.Security.Claims; +using TechHelper.Services.Beta; using TechHelper.Services; +using Entities.DTO.Class; namespace TechHelper.Server.Controllers { @@ -17,7 +21,7 @@ namespace TechHelper.Server.Controllers [ApiController] public class ClassController : ControllerBase { - private IClassService _classService; + private TechHelper.Services.Beta.IClassService _classService; private UserManager _userManager; /// @@ -25,12 +29,159 @@ namespace TechHelper.Server.Controllers /// /// 班级服务 /// 用户管理服务 - public ClassController(IClassService classService, UserManager userManager) + public ClassController(TechHelper.Services.Beta.IClassService classService, UserManager userManager) { _classService = classService; _userManager = userManager; } + #region 班级基本信息CRUD操作 + + /// + /// 获取班级列表(支持搜索) + /// + /// 查询参数 + /// 班级列表 + /// 成功获取班级列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _classService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取班级详细信息 + /// + /// 班级ID + /// 班级详细信息 + /// 成功获取班级信息 + /// 班级未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _classService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新班级 + /// + /// 班级数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + public async Task Create([FromBody] ClassDto model) + { + var result = await _classService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + + return Ok(result.Result); + } + + + [HttpPost("AdminCreate")] + [Authorize(Roles = "Admin")] + public async Task Create([FromBody] ClassCreateDto dto) + { + var result = await _classService.AdminAddAsync(dto); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + + return Ok(result.Result); + } + + + /// + /// 更新班级信息 + /// + /// 班级数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] ClassDto model) + { + var result = await _classService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除班级 + /// + /// 班级ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _classService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + #region 班级用户管理 + + /// + /// 验证班级信息是否存在 + /// + /// 包含学校名称、年级和班级名称的数据传输对象 + /// 验证结果和班级信息 + /// 验证成功,返回班级信息 + /// 验证失败 + [HttpPost("validate")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task ValidateClassInfo( + [FromBody] ClassValidDto toClass) + { + var result = await _classService.ValidateClassRegistration(toClass); + + if (!result.Status) return BadRequest(result.Message); + + return Ok(result.Result); + } + /// /// 用户注册到班级 /// @@ -39,107 +190,68 @@ namespace TechHelper.Server.Controllers /// 注册成功 /// 注册失败 [HttpPost("userRegiste")] + [Authorize(Roles = "Student,Teacher,Admin")] public async Task UserRegisterToClass( - [FromBody] UserRegistrationToClassDto toClass) + [FromBody] RegisterUserToClassDto toClass) { - var result = await _classService.UserRegister(toClass); if (!result.Status) return BadRequest(result.Message); - return Ok(); + return Ok(result.Message); } - - - /// - /// 获取班级学生列表 - /// 仅限教师角色访问,根据教师所在班级信息获取学生列表 + /// 根据班级ID获取班级学生列表 /// + /// 班级ID /// 班级学生列表 /// 成功获取学生列表 - /// 权限不足或班级信息缺失 - [HttpPost("getClassStudents")] - public async Task GetClassStudents() + /// 班级未找到或获取失败 + [HttpGet("students/{classId}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetClassStudentsById(Guid classId) { - if (User.IsInRole("Teacher")) + var result = await _classService.GetClassStudentsAsync(classId); + + if (!result.Status) { - var gradeClaim = User.FindFirst("Grade")?.Value; - var classClaim = User.FindFirst("Class")?.Value; - - if (string.IsNullOrEmpty(gradeClaim) || string.IsNullOrEmpty(classClaim)) - { - return BadRequest("未识别到你加入的班级信息(年级或班级声明缺失)。"); - } - - if (!byte.TryParse(gradeClaim, out byte grade) || !byte.TryParse(classClaim, out byte cla)) - { - return BadRequest("你班级或年级信息格式不正确。"); - } - - var classDto = new ClassDto - { - Grade = grade, - Class = cla - }; - - var result = await _classService.GetClassStudents(classDto); - var css = result.Result as ICollection; - if (css == null) return BadRequest("你还没有学生"); - - - List sts = new List(); - css?.ToList().ForEach(s => sts.Add(new StudentDto - { - DisplayName = s.Student.DisplayName, - Id = s.Student.Id, - })); - - if (!result.Status) - { - return BadRequest(result.Message); - } - return Ok(sts); + return BadRequest(result.Message); } - else - { - return BadRequest("你没有权限查看,未识别到你的教师身份。"); - } - } - - /// - /// 创建新班级 - /// - /// 班级数据传输对象 - /// 操作结果 - /// 班级创建成功 - /// 班级创建失败 - [HttpPost("Create")] - public async Task Create( - [FromBody] ClassDto classDto) - { - var result = await _classService.AddAsync(classDto); - if (!result.Status) return BadRequest(result.Message); - - return Ok(); - } - - /// - /// 获取指定年级的所有班级列表 - /// - /// 年级编号 - /// 班级列表 - /// 成功获取班级列表 - /// 获取失败 - [HttpPost("GetGradeClasses")] - public async Task GetGradeClasses( - [FromBody] byte classDto) - { - var result = await _classService.GetGradeClasses(classDto); - if (!result.Status) return BadRequest(result.Message); - return Ok(result.Result); } + + + [HttpGet("classes")] + [Authorize(Roles = "Teacher, Student")] + public async Task GetUserInjoinedClass() + { + var user = await _userManager.FindByEmailAsync(User.Identity.Name); + var userid = user.Id; + + var result = await _classService.GetUserInjoinedClasses(userid); + if (result.Status) + return Ok(result.Result); + else + return BadRequest(result.Message); + } + + [HttpGet("injoint/{id:guid}")] + [Authorize(Roles = "Teacher, Student")] + public async Task InjoinClass(Guid id) + { + var user = await _userManager.FindByEmailAsync(User.Identity.Name); + var userid = user.Id; + + var registerClass = new RegisterUserToClassDto { ClassId = id, UserId = userid, Role = user.Role ?? UserRoles.Student }; + + var result = await _classService.UserRegister(registerClass); + if (result.Status) + return Ok(result.Result); + else + return BadRequest(result.Message); + } + + #endregion } } diff --git a/TechHelper.Server/Controllers/CommonController.cs b/TechHelper.Server/Controllers/CommonController.cs new file mode 100644 index 0000000..13549b7 --- /dev/null +++ b/TechHelper.Server/Controllers/CommonController.cs @@ -0,0 +1,28 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; + +namespace TechHelper.Server.Controllers +{ + [Route("api/common")] + [ApiController] + public class CommonController : Controller + { + private readonly UserManager _userManager; + + public CommonController(UserManager userManager) + { + _userManager = userManager; + } + + [HttpGet("GetCommonType")] + public IActionResult GetCommonType(TypeCommonRequest typeCommon) + { + return Ok(); + } + + + + } +} diff --git a/TechHelper.Server/Controllers/ExamController.cs b/TechHelper.Server/Controllers/ExamController.cs index 509f186..4974edd 100644 --- a/TechHelper.Server/Controllers/ExamController.cs +++ b/TechHelper.Server/Controllers/ExamController.cs @@ -4,9 +4,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using TechHelper.Server.Services; -using System.Security.Claims; using TechHelper.Services; +using TechHelper.Services.Beta; namespace TechHelper.Server.Controllers @@ -30,13 +29,14 @@ namespace TechHelper.Server.Controllers /// /// 考试/作业的数据传输对象。 /// 新创建的考试/作业信息或错误信息。 - [HttpPost("add")] - public async Task AddExam([FromBody] AssignmentDto examDto) + [HttpPost()] + [Authorize(Roles = "Teacher")] + public async Task AddExam([FromBody] ExamDto examDto) { var user = await _userManager.FindByEmailAsync(User.Identity.Name); if (user == null) return NotFound("没有找到用户"); examDto.CreatorId = user.Id; - var result = await _examService.CreateExamAsync(examDto); + var result = await _examService.AddAsync(examDto); if (result.Status) { @@ -48,17 +48,12 @@ namespace TechHelper.Server.Controllers } } - /// - /// 提交作业。 - /// - /// 提交的数据传输对象。 - /// 提交结果或错误信息。 - [HttpPost("submission")] - public async Task SubmissionAssignment([FromBody] SubmissionDto submissionDto) + [HttpGet] + public async Task GetAllExams([FromQuery] QueryParameter queryParameter) { - var result = await _examService.SubmissionAssignment(submissionDto); + var result = await _examService.GetAllAsync(queryParameter); - if (result.Status) + if(result.Status) { return Ok(result.Result); } @@ -96,70 +91,7 @@ namespace TechHelper.Server.Controllers } } - /// - /// 获取所有考试/作业的预览信息(教师获取自己创建的,学生获取自己需要提交的)。 - /// - /// 考试/作业预览列表或错误信息。 - [HttpGet("getAllPreview")] - public async Task GetAllExamPreview() - { - var user = await _userManager.FindByEmailAsync(User.Identity.Name); - if (user == null) return NotFound("没有找到用户"); - - ApiResponse result; - - if (User.IsInRole("Teacher")) - { - result = await _examService.GetAllExamPreviewsAsync(user.Id); - } - else if (User.IsInRole("Student")) - { - result = await _examService.GetAllSubmissionAsync(user.Id); - } - else - { - return Forbid("你没有查看考试预览的权限。"); - } - - if (result.Status) - { - return Ok(result.Result); - } - else - { - return BadRequest(result.Message); - } - } - - /// - /// 获取学生的所有提交记录。 - /// - /// 提交记录列表或错误信息。 - [HttpGet("getAllSubmissions")] - [Authorize(Roles = "Student")] - public async Task GetAllSubmission() - { - var user = await _userManager.FindByEmailAsync(User.Identity.Name); - if (user == null) return NotFound("没有找到用户"); - - var result = await _examService.GetAllSubmissionAsync(user.Id); - - if (result.Status) - { - return Ok(result.Result); - } - else - { - return BadRequest(result.Message); - } - } - - /// - /// 逻辑删除指定ID的考试/作业。 - /// - /// 要删除的考试/作业ID。 - /// 操作结果。 - [HttpDelete("delete/{id:guid}")] + [HttpDelete("{id:guid}")] [Authorize(Roles = "Teacher")] public async Task DeleteAsync(Guid id) { @@ -179,13 +111,32 @@ namespace TechHelper.Server.Controllers } } + [HttpPost("GetTotalDistributionInClass")] + [Authorize(Roles = "Teacher")] + public async Task GetTotalDistributionInClass(AssigExamToClassDto dto) + { + var result = await _examService.GetExamTotalErrorDistributionInClassAsync(dto); + + if (result.Status) + { + return Ok(result.Result); + } + else + { + if (result.Message.Contains("未找到") || result.Message.Contains("not found", StringComparison.OrdinalIgnoreCase)) + { + return NotFound(result.Message); + } + return BadRequest(result.Message); + } + } /// /// 为指定学生指派作业 /// /// /// - [HttpPost("assignmentExamToStudent")] + [HttpPost("assignmentExamToStudents")] [Authorize(Roles = "Teacher")] public async Task AssignmentExamToStudent([FromBody] AssigExamToStudentsDto AETSdto) { @@ -206,12 +157,28 @@ namespace TechHelper.Server.Controllers /// /// /// - [HttpPost("assignmentExamToStudent/{id:guid}")] + [HttpPost("assignmentExamToClass")] [Authorize(Roles = "Teacher")] - public async Task AssignmentExamToAllStudentsAsync(Guid id) + public async Task AssignmentExamToClassAsync([FromBody] AssigExamToClassDto AETSdto) { var user = await _userManager.FindByEmailAsync(User.Identity.Name ?? ""); - var result = await _examService.AssignmentToAllStudentsAsync(id, user.Id); + var result = await _examService.AssignmentToClassAsync(user.Id, AETSdto.examId, AETSdto.classId); + if (result.Status) + { + return Ok(result.Result); + } + else + { + return BadRequest(result.Message); + } + } + + + + [HttpGet("GetExamSubmissionDetailInClassAsync")] + public async Task GetExamSubmissionDetailInClassAsync([FromBody] AssigExamToClassDto model) + { + var result = await _examService.GetExamSubmissionDetailInClassAsync(model); if (result.Status) { return Ok(result.Result); diff --git a/TechHelper.Server/Controllers/ExamQuestionController.cs b/TechHelper.Server/Controllers/ExamQuestionController.cs new file mode 100644 index 0000000..7fb2363 --- /dev/null +++ b/TechHelper.Server/Controllers/ExamQuestionController.cs @@ -0,0 +1,161 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Net; +using System.Security.Claims; +using TechHelper.Services; +using TechHelper.Services.Beta; +using static TechHelper.Services.Beta.IExamQuestionService; + +namespace TechHelper.Server.Controllers +{ + /// + /// 考试题目管理控制器 + /// 处理考试题目相关的操作,如创建、更新、删除考试题目等 + /// + [Route("api/exam-question")] + [ApiController] + public class ExamQuestionController : ControllerBase + { + private readonly IExamQuestionService _examQuestionService; + private readonly UserManager _userManager; + + /// + /// 初始化考试题目控制器 + /// + /// 考试题目服务 + /// 用户管理服务 + public ExamQuestionController(IExamQuestionService examQuestionService, UserManager userManager) + { + _examQuestionService = examQuestionService; + _userManager = userManager; + } + + #region 考试题目基本信息CRUD操作 + + /// + /// 获取考试题目列表(支持搜索) + /// + /// 查询参数 + /// 考试题目列表 + /// 成功获取考试题目列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _examQuestionService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取考试题目详细信息 + /// + /// 考试题目ID + /// 考试题目详细信息 + /// 成功获取考试题目信息 + /// 考试题目未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _examQuestionService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新考试题目 + /// + /// 考试题目数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Admin,Teacher")] + public async Task Create([FromBody] ExamQuestionDto model) + { + var result = await _examQuestionService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新考试题目信息 + /// + /// 考试题目数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin, Teacher")] + public async Task Update([FromBody] ExamQuestionDto model) + { + var result = await _examQuestionService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除考试题目 + /// + /// 考试题目ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _examQuestionService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + + [HttpPost("GetQuestionDependy")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetQuestionDependy(QuesitionDenpendceyRequst request) + { + var result = await _examQuestionService.GetQuestionDependy(request); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + } +} diff --git a/TechHelper.Server/Controllers/ExamTypeController.cs b/TechHelper.Server/Controllers/ExamTypeController.cs new file mode 100644 index 0000000..0fa5317 --- /dev/null +++ b/TechHelper.Server/Controllers/ExamTypeController.cs @@ -0,0 +1,145 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Net; +using System.Security.Claims; +using TechHelper.Services.Beta; +using TechHelper.Services; + +namespace TechHelper.Server.Controllers +{ + /// + /// 考试类型管理控制器 + /// 处理考试类型相关的操作,如创建、更新、删除考试类型等 + /// + [Route("api/exam-type")] + [ApiController] + public class ExamTypeController : ControllerBase + { + private readonly IExamTypeService _examTypeService; + private readonly UserManager _userManager; + + /// + /// 初始化考试类型控制器 + /// + /// 考试类型服务 + /// 用户管理服务 + public ExamTypeController(IExamTypeService examTypeService, UserManager userManager) + { + _examTypeService = examTypeService; + _userManager = userManager; + } + + #region 考试类型基本信息CRUD操作 + + /// + /// 获取考试类型列表(支持搜索) + /// + /// 查询参数 + /// 考试类型列表 + /// 成功获取考试类型列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _examTypeService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取考试类型详细信息 + /// + /// 考试类型ID + /// 考试类型详细信息 + /// 成功获取考试类型信息 + /// 考试类型未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _examTypeService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新考试类型 + /// + /// 考试类型数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Admin, Teacher")] + public async Task Create([FromBody] ExamTypeDto model) + { + var result = await _examTypeService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新考试类型信息 + /// + /// 考试类型数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] ExamTypeDto model) + { + var result = await _examTypeService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除考试类型 + /// + /// 考试类型ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _examTypeService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/GradeController.cs b/TechHelper.Server/Controllers/GradeController.cs new file mode 100644 index 0000000..675f8cf --- /dev/null +++ b/TechHelper.Server/Controllers/GradeController.cs @@ -0,0 +1,144 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Net; +using System.Security.Claims; +using TechHelper.Services.Beta; +using TechHelper.Services; + +namespace TechHelper.Server.Controllers +{ + /// + /// 年级管理控制器 + /// 处理年级相关的操作,如创建、更新、删除年级等 + /// + [Route("api/grade")] + [ApiController] + public class GradeController : ControllerBase + { + private TechHelper.Services.Beta.IGradeService _gradeService; + private UserManager _userManager; + + /// + /// 初始化年级控制器 + /// + /// 年级服务 + /// 用户管理服务 + public GradeController(TechHelper.Services.Beta.IGradeService gradeService, UserManager userManager) + { + _gradeService = gradeService; + _userManager = userManager; + } + + #region 年级基本信息CRUD操作 + + /// + /// 获取年级列表(支持搜索) + /// + /// 查询参数 + /// 年级列表 + /// 成功获取年级列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _gradeService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取年级详细信息 + /// + /// 年级ID + /// 年级详细信息 + /// 成功获取年级信息 + /// 年级未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _gradeService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新年级 + /// + /// 年级数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + public async Task Create([FromBody] GradeDto model) + { + var result = await _gradeService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新年级信息 + /// + /// 年级数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] GradeDto model) + { + var result = await _gradeService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除年级 + /// + /// 年级ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _gradeService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/KeyPointController.cs b/TechHelper.Server/Controllers/KeyPointController.cs new file mode 100644 index 0000000..2a91388 --- /dev/null +++ b/TechHelper.Server/Controllers/KeyPointController.cs @@ -0,0 +1,167 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; +using TechHelper.Services.Beta; + +namespace TechHelper.Server.Controllers +{ + /// + /// 知识点管理控制器 + /// 处理知识点相关的操作,如创建、更新、删除知识点等 + /// + [Route("api/keypoint")] + [ApiController] + public class KeyPointController : ControllerBase + { + private readonly IKeyPointService _keyPointService; + private readonly UserManager _userManager; + + /// + /// 初始化知识点控制器 + /// + /// 知识点服务 + /// 用户管理服务 + public KeyPointController(IKeyPointService keyPointService, UserManager userManager) + { + _keyPointService = keyPointService; + _userManager = userManager; + } + + #region 知识点基本信息CRUD操作 + + /// + /// 获取知识点列表(支持搜索) + /// + /// 查询参数 + /// 知识点列表 + /// 成功获取知识点列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _keyPointService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取知识点详细信息 + /// + /// 知识点ID + /// 知识点详细信息 + /// 成功获取知识点信息 + /// 知识点未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _keyPointService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新知识点 + /// + /// 知识点数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Teacher,Admin")] + public async Task Create([FromBody] KeyPointDto model) + { + var result = await _keyPointService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新知识点信息 + /// + /// 知识点数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Teacher,Admin")] + public async Task Update([FromBody] KeyPointDto model) + { + var result = await _keyPointService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除知识点 + /// + /// 知识点ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task Delete(Guid id) + { + var result = await _keyPointService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + #region 知识点扩展操作 + + /// + /// 根据课程ID获取知识点列表 + /// + /// 课程ID + /// 知识点列表 + /// 成功获取知识点列表 + /// 获取失败 + [HttpGet("lesson/{lessonId}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetByLessonId(Guid lessonId) + { + var result = await _keyPointService.GetKeyPointsByLessonIdAsync(lessonId); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/LessonController.cs b/TechHelper.Server/Controllers/LessonController.cs new file mode 100644 index 0000000..fc1e845 --- /dev/null +++ b/TechHelper.Server/Controllers/LessonController.cs @@ -0,0 +1,167 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; +using TechHelper.Services.Beta; + +namespace TechHelper.Server.Controllers +{ + /// + /// 课程管理控制器 + /// 处理课程相关的操作,如创建、更新、删除课程等 + /// + [Route("api/Lesson")] + [ApiController] + public class LessonController : ControllerBase + { + private readonly ILessonService _lessonService; + private readonly UserManager _userManager; + + /// + /// 初始化课程控制器 + /// + /// 课程服务 + /// 用户管理服务 + public LessonController(ILessonService lessonService, UserManager userManager) + { + _lessonService = lessonService; + _userManager = userManager; + } + + #region 课程基本信息CRUD操作 + + /// + /// 获取课程列表(支持搜索) + /// + /// 查询参数 + /// 课程列表 + /// 成功获取课程列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _lessonService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取课程详细信息 + /// + /// 课程ID + /// 课程详细信息 + /// 成功获取课程信息 + /// 课程未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _lessonService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新课程 + /// + /// 课程数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Teacher,Admin")] + public async Task Create([FromBody] LessonDto model) + { + var result = await _lessonService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新课程信息 + /// + /// 课程数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Teacher,Admin")] + public async Task Update([FromBody] LessonDto model) + { + var result = await _lessonService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除课程 + /// + /// 课程ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task Delete(Guid id) + { + var result = await _lessonService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + #region 课程扩展操作 + + /// + /// 根据教材ID获取课程列表 + /// + /// 教材ID + /// 课程列表 + /// 成功获取课程列表 + /// 获取失败 + [HttpGet("textbook/{textbookId}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetByTextbookId(Guid textbookId) + { + var result = await _lessonService.GetAllAsync(new QueryParameter { Search = textbookId.ToString() }); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/NoteController.cs b/TechHelper.Server/Controllers/NoteController.cs deleted file mode 100644 index 08658d9..0000000 --- a/TechHelper.Server/Controllers/NoteController.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Entities.DTO; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using TechHelper.Services; - -namespace TechHelper.Server.Controllers -{ - [Route("api/note")] - [ApiController] - public class NoteController : ControllerBase - { - private readonly INoteService _noteService; - - // 通过依赖注入获取 NoteService - public NoteController(INoteService noteService) - { - _noteService = noteService; - } - - /// - /// 获取所有全局数据。 - /// GET: api/Note - /// - [HttpGet] - public async Task GetAll([FromQuery] QueryParameter query) - { - var response = await _noteService.GetAllAsync(query); - return Ok(response); - } - - /// - /// 根据 ID 获取单个全局数据。 - /// GET: api/Note/{id} - /// - [HttpGet("{id}")] - public async Task Get(byte id) - { - var response = await _noteService.GetAsync(id); - if (!response.Status) - { - return NotFound(response); - } - return Ok(response); - } - - /// - /// 添加新的全局数据。 - /// POST: api/Note - /// - [HttpPost] - public async Task Add([FromBody] GlobalDto model) - { - var response = await _noteService.AddAsync(model); - if (!response.Status) - { - return BadRequest(response); - } - return Ok(response); - } - - /// - /// 更新已存在的全局数据。 - /// PUT: api/Note - /// - [HttpPut] - public async Task Update([FromBody] GlobalDto model) - { - var response = await _noteService.UpdateAsync(model); - if (!response.Status) - { - return NotFound(response); - } - return Ok(response); - } - - /// - /// 根据 ID 删除全局数据。 - /// DELETE: api/Note/{id} - /// - [HttpDelete("{id}")] - public async Task Delete(byte id) - { - var response = await _noteService.DeleteAsync(id); - if (!response.Status) - { - return NotFound(response); - } - return Ok(response); - } - } -} diff --git a/TechHelper.Server/Controllers/QuestionController.cs b/TechHelper.Server/Controllers/QuestionController.cs new file mode 100644 index 0000000..0642910 --- /dev/null +++ b/TechHelper.Server/Controllers/QuestionController.cs @@ -0,0 +1,188 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; +using TechHelper.Services.Beta; + +namespace TechHelper.Server.Controllers +{ + /// + /// 题目管理控制器 + /// 处理题目相关的操作,如CRUD、按标题查找等 + /// + [Route("api/question")] + [ApiController] + public class QuestionController : ControllerBase + { + private readonly IQuestionService _questionService; + private readonly UserManager _userManager; + + /// + /// 初始化题目控制器 + /// + /// 题目服务 + /// 用户管理服务 + public QuestionController(IQuestionService questionService, UserManager userManager) + { + _questionService = questionService; + _userManager = userManager; + } + + #region 题目基本信息CRUD操作 + + /// + /// 获取题目列表(支持搜索和分页) + /// + /// 查询参数 + /// 题目列表 + /// 成功获取题目列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _questionService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取题目详细信息 + /// + /// 题目ID + /// 题目详细信息 + /// 成功获取题目信息 + /// 题目未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _questionService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新题目 + /// + /// 题目数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Teacher,Admin")] + public async Task Create([FromBody] QuestionDto model) + { + var result = await _questionService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新题目信息 + /// + /// 题目数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Teacher,Admin")] + public async Task Update([FromBody] QuestionDto model) + { + var result = await _questionService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除题目(软删除) + /// + /// 题目ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _questionService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + #region 题目业务逻辑操作 + + /// + /// 根据标题查找题目 + /// + /// 题目标题 + /// 题目信息 + /// 成功找到题目 + /// 题目未找到或查找失败 + [HttpGet("by-title/{title}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetByTitle(string title) + { + var result = await _questionService.FindByTitle(title); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 批量检查题目标题是否存在 + /// + /// 题目标题集合 + /// 标题存在性检查结果 + /// 检查成功 + /// 检查失败 + [HttpPost("check-titles")] + [Authorize(Roles = "Teacher,Admin")] + public async Task CheckTitlesExistence([FromBody] List titles) + { + var result = await _questionService.CheckTitlesExistence(titles); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/QuestionTypeController.cs b/TechHelper.Server/Controllers/QuestionTypeController.cs new file mode 100644 index 0000000..4fdfdeb --- /dev/null +++ b/TechHelper.Server/Controllers/QuestionTypeController.cs @@ -0,0 +1,145 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Net; +using System.Security.Claims; +using TechHelper.Services.Beta; +using TechHelper.Services; + +namespace TechHelper.Server.Controllers +{ + /// + /// 题型管理控制器 + /// 处理题型相关的操作,如创建、更新、删除题型等 + /// + [Route("api/question-type")] + [ApiController] + public class QuestionTypeController : ControllerBase + { + private readonly IQuestionTypeService _questionTypeService; + private readonly UserManager _userManager; + + /// + /// 初始化题型控制器 + /// + /// 题型服务 + /// 用户管理服务 + public QuestionTypeController(IQuestionTypeService questionTypeService, UserManager userManager) + { + _questionTypeService = questionTypeService; + _userManager = userManager; + } + + #region 题型基本信息CRUD操作 + + /// + /// 获取题型列表(支持搜索) + /// + /// 查询参数 + /// 题型列表 + /// 成功获取题型列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _questionTypeService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取题型详细信息 + /// + /// 题型ID + /// 题型详细信息 + /// 成功获取题型信息 + /// 题型未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _questionTypeService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新题型 + /// + /// 题型数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Admin, Teacher")] + public async Task Create([FromBody] QuestionTypeDto model) + { + var result = await _questionTypeService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新题型信息 + /// + /// 题型数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] QuestionTypeDto model) + { + var result = await _questionTypeService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除题型 + /// + /// 题型ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _questionTypeService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/SchoolController.cs b/TechHelper.Server/Controllers/SchoolController.cs new file mode 100644 index 0000000..901d48f --- /dev/null +++ b/TechHelper.Server/Controllers/SchoolController.cs @@ -0,0 +1,161 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; + +namespace TechHelper.Server.Controllers +{ + /// + /// 学校管理控制器 + /// 处理学校相关的操作,如创建、更新、删除学校等 + /// + [Route("api/school")] + [ApiController] + public class SchoolController : ControllerBase + { + private TechHelper.Services.Beta.ISchoolService _schoolService; + private UserManager _userManager; + + /// + /// 初始化学校控制器 + /// + /// 学校服务 + /// 用户管理服务 + public SchoolController(TechHelper.Services.Beta.ISchoolService schoolService, UserManager userManager) + { + _schoolService = schoolService; + _userManager = userManager; + } + + #region 学校基本信息CRUD操作 + + /// + /// 获取学校列表(支持搜索) + /// + /// 查询参数 + /// 学校列表 + /// 成功获取学校列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _schoolService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取学校详细信息 + /// + /// 学校ID + /// 学校详细信息 + /// 成功获取学校信息 + /// 学校未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _schoolService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新学校 + /// + /// 学校数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + public async Task Create([FromBody] SchoolDto model) + { + var result = await _schoolService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新学校信息 + /// + /// 学校数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] SchoolDto model) + { + var result = await _schoolService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除学校 + /// + /// 学校ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _schoolService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + /// + /// 根据学校名称获取学校信息 + /// + /// 学校名称 + /// 学校信息 + /// 成功获取学校信息 + /// 学校未找到或获取失败 + [HttpGet("byname/{schoolName}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetByName(string schoolName) + { + var result = await _schoolService.GetSchoolByNameAsync(schoolName); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/StudentSubmissionController.cs b/TechHelper.Server/Controllers/StudentSubmissionController.cs index 160b350..d241e0f 100644 --- a/TechHelper.Server/Controllers/StudentSubmissionController.cs +++ b/TechHelper.Server/Controllers/StudentSubmissionController.cs @@ -3,8 +3,7 @@ using Entities.DTO; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using TechHelper.Server.Services; -using System.Security.Claims; +using TechHelper.Services.Beta; namespace TechHelper.Server.Controllers { @@ -13,11 +12,11 @@ namespace TechHelper.Server.Controllers [Authorize] public class StudentSubmissionController : ControllerBase { - private readonly IStudentSubmissionService _studentSubmissionService; + private readonly ISubmissionService _studentSubmissionService; private readonly UserManager _userManager; public StudentSubmissionController( - IStudentSubmissionService studentSubmissionService, + ISubmissionService studentSubmissionService, UserManager userManager) { _studentSubmissionService = studentSubmissionService; @@ -35,7 +34,7 @@ namespace TechHelper.Server.Controllers if (user == null) return NotFound("未找到用户信息"); - var result = await _studentSubmissionService.GetStudentSubmissionsAsync(user.Id); + var result = await _studentSubmissionService.GetStudentSubmissionDetailAsync(user.Id); if (result.Status) { @@ -64,7 +63,7 @@ namespace TechHelper.Server.Controllers if (user == null) return NotFound("未找到用户信息"); - var result = await _studentSubmissionService.GetStudentSubmissionsPagedAsync(user.Id, pageNumber, pageSize); + var result = await _studentSubmissionService.GetStudentSubmissionSummariesAsync(user.Id); if (result.Status) { @@ -85,7 +84,7 @@ namespace TechHelper.Server.Controllers [Authorize(Roles = "Teacher")] public async Task GetStudentSubmissions(Guid studentId) { - var result = await _studentSubmissionService.GetStudentSubmissionsAsync(studentId); + var result = await _studentSubmissionService.GetStudentSubmissionSummariesAsync(studentId); if (result.Status) { @@ -112,7 +111,7 @@ namespace TechHelper.Server.Controllers if (pageSize < 1) pageSize = 10; if (pageSize > 100) pageSize = 100; // 限制最大页面大小 - var result = await _studentSubmissionService.GetStudentSubmissionsPagedAsync(studentId, pageNumber, pageSize); + var result = await _studentSubmissionService.GetStudentSubmissionSummariesAsync(studentId); if (result.Status) { diff --git a/TechHelper.Server/Controllers/StudentSubmissionDetailController.cs b/TechHelper.Server/Controllers/StudentSubmissionDetailController.cs index 3b0823f..eeffed3 100644 --- a/TechHelper.Server/Controllers/StudentSubmissionDetailController.cs +++ b/TechHelper.Server/Controllers/StudentSubmissionDetailController.cs @@ -3,11 +3,11 @@ using Entities.DTO; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using TechHelper.Server.Services; using TechHelper.Context; using TechHelper.Repository; using SharedDATA.Api; using System.Security.Claims; +using TechHelper.Services.Beta; namespace TechHelper.Server.Controllers { @@ -16,12 +16,12 @@ namespace TechHelper.Server.Controllers [Authorize] public class StudentSubmissionDetailController : ControllerBase { - private readonly IStudentSubmissionDetailService _studentSubmissionDetailService; + private readonly ISubmissionDetailService _studentSubmissionDetailService; private readonly UserManager _userManager; private readonly IUnitOfWork _unitOfWork; public StudentSubmissionDetailController( - IStudentSubmissionDetailService studentSubmissionDetailService, + ISubmissionDetailService studentSubmissionDetailService, UserManager userManager, IUnitOfWork unitOfWork) { @@ -61,7 +61,7 @@ namespace TechHelper.Server.Controllers return Forbid("您没有权限查看此提交记录"); } - var result = await _studentSubmissionDetailService.GetSubmissionDetailAsync(submissionId); + var result = await _studentSubmissionDetailService.GetBySubmissionIdAsync(submissionId); if (result.Status) { diff --git a/TechHelper.Server/Controllers/SubjectController.cs b/TechHelper.Server/Controllers/SubjectController.cs new file mode 100644 index 0000000..6e0b4f5 --- /dev/null +++ b/TechHelper.Server/Controllers/SubjectController.cs @@ -0,0 +1,145 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using System.Diagnostics; +using System.Net; +using System.Security.Claims; +using TechHelper.Services.Beta; +using TechHelper.Services; + +namespace TechHelper.Server.Controllers +{ + /// + /// 科目管理控制器 + /// 处理科目相关的操作,如创建、更新、删除科目等 + /// + [Route("api/subject")] + [ApiController] + public class SubjectController : ControllerBase + { + private readonly ISubjectService _subjectService; + private readonly UserManager _userManager; + + /// + /// 初始化科目控制器 + /// + /// 科目服务 + /// 用户管理服务 + public SubjectController(ISubjectService subjectService, UserManager userManager) + { + _subjectService = subjectService; + _userManager = userManager; + } + + #region 科目基本信息CRUD操作 + + /// + /// 获取科目列表(支持搜索) + /// + /// 查询参数 + /// 科目列表 + /// 成功获取科目列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _subjectService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取科目详细信息 + /// + /// 科目ID + /// 科目详细信息 + /// 成功获取科目信息 + /// 科目未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _subjectService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新科目 + /// + /// 科目数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Admin,Teacher")] + public async Task Create([FromBody] SubjectDto model) + { + var result = await _subjectService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新科目信息 + /// + /// 科目数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] SubjectDto model) + { + var result = await _subjectService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除科目 + /// + /// 科目ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _subjectService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/SubmissionController.cs b/TechHelper.Server/Controllers/SubmissionController.cs index 3519d2a..d68d25c 100644 --- a/TechHelper.Server/Controllers/SubmissionController.cs +++ b/TechHelper.Server/Controllers/SubmissionController.cs @@ -4,8 +4,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using TechHelper.Server.Services; using TechHelper.Services; +using TechHelper.Services.Beta; namespace TechHelper.Server.Controllers { @@ -16,15 +16,16 @@ namespace TechHelper.Server.Controllers public class SubmissionController : ControllerBase { private readonly UserManager _userManager; - private readonly ISubmissionServices _submissionServices; + private readonly ISubmissionService _submissionServices; - public SubmissionController(UserManager userManager, ISubmissionServices submissionServices) + public SubmissionController(UserManager userManager, ISubmissionService submissionServices) { _userManager = userManager; _submissionServices = submissionServices; } + /// /// 获取当前用户的所有错题。 /// @@ -35,7 +36,7 @@ namespace TechHelper.Server.Controllers var user = await _userManager.FindByEmailAsync(User.Identity.Name); if (user == null) { - return NotFound("未找到当前用户信息。"); + return NotFound("未找到当前用户信息。"); } var result = await _submissionServices.GetAllErrorQuestionsAsync(user.Id); @@ -55,7 +56,7 @@ namespace TechHelper.Server.Controllers /// /// 作业ID。 /// 错题列表或错误信息。 - [HttpGet("getAssignmentErrorQuestions/{assignmentId:guid}")] + [HttpGet("getAssignmentErrorQuestions/{assignmentId:guid}")] public async Task GetAssignmentErrorQuestionsAsync(Guid assignmentId) { var user = await _userManager.FindByEmailAsync(User.Identity.Name); @@ -138,7 +139,7 @@ namespace TechHelper.Server.Controllers /// 作业ID。 /// 按题目分组的学生错题列表。 [HttpGet("getQuestionErrorStudents/{assignmentId:guid}")] - [Authorize(Roles = "Teacher")] + [Authorize(Roles = "Teacher")] public async Task GetQuestionErrorStudents(Guid assignmentId) { var result = await _submissionServices.GetQuestionErrorStudents(assignmentId); @@ -158,8 +159,8 @@ namespace TechHelper.Server.Controllers /// /// 提交的数据模型。 /// 新创建的提交记录或错误信息。 - [HttpPost("add")] - public async Task AddAsync([FromBody] Submission model) + [HttpPost()] + public async Task AddAsync([FromBody] SubmissionDto model) { // 可以在这里获取当前用户ID并赋值给 model.StudentId,确保提交人信息正确 // var user = await _userManager.FindByEmailAsync(User.Identity.Name); @@ -209,7 +210,7 @@ namespace TechHelper.Server.Controllers /// /// 查询参数,包含分页信息。 /// 分页的提交记录列表。 - [HttpGet("getAll")] + [HttpGet()] [Authorize(Roles = "Admin,Teacher")] public async Task GetAllAsync([FromQuery] QueryParameter query) { @@ -252,7 +253,7 @@ namespace TechHelper.Server.Controllers /// 要更新的提交数据。 /// 更新后的提交记录或错误信息。 [HttpPut("update/{id:guid}")] - public async Task UpdateAsync(Guid id, [FromBody] Submission model) + public async Task UpdateAsync(Guid id, [FromBody] SubmissionDto model) { if (id != model.Id) // 确保路径中的ID和模型中的ID一致 { @@ -275,5 +276,90 @@ namespace TechHelper.Server.Controllers return BadRequest(result.Message); } } + + + [HttpPost("GradeExam")] + [Authorize(Roles = "Teacher")] + public async Task GradeExam([FromBody] SubmissionTeacherUpdateDto model) + { + var result = await _submissionServices.GradeExam(model); + if (result.Status) + { + return Ok(result); + } + else + { + return BadRequest(result.Message); + } + } + + /// + /// 获取学生提交摘要。 + /// + /// 用户ID。 + /// 学生提交摘要列表或错误信息。 + [HttpGet("getStudentSubmissionSummaries")] + [Authorize(Roles = "Student")] + public async Task GetStudentSubmissionSummariesAsync() + { + var user = await _userManager.FindByEmailAsync(User.Identity.Name); + if (user == null) + { + return NotFound("未找到当前用户信息。"); + } + + var userId = user.Id; // 假设当前用户是学生,获取其ID + var result = await _submissionServices.GetStudentSubmissionSummariesAsync(userId); + + if (result.Status) + { + return Ok(result); + } + else + { + return BadRequest(result.Message); + } + } + + /// + /// 获取学生提交摘要。 + /// + /// 用户ID。 + /// 学生提交摘要列表或错误信息。 + [HttpGet("getStudentSubmissionSummaries/{userId:guid}")] + [Authorize(Roles = "Teacher")] + public async Task GetStudentSubmissionSummariesAsync(Guid userId) + { + var result = await _submissionServices.GetStudentSubmissionSummariesAsync(userId); + + if (result.Status) + { + return Ok(result); + } + else + { + return BadRequest(result.Message); + } + } + + /// + /// 获取学生提交详情。 + /// + /// 提交ID。 + /// 学生提交详情或错误信息。 + [HttpGet("getStudentSubmissionDetail/{submissionId:guid}")] + public async Task GetStudentSubmissionDetailAsync(Guid submissionId) + { + var result = await _submissionServices.GetStudentSubmissionDetailAsync(submissionId); + + if (result.Status) + { + return Ok(result); + } + else + { + return BadRequest(result.Message); + } + } } } diff --git a/TechHelper.Server/Controllers/SubmissionDetailController.cs b/TechHelper.Server/Controllers/SubmissionDetailController.cs new file mode 100644 index 0000000..1d667e8 --- /dev/null +++ b/TechHelper.Server/Controllers/SubmissionDetailController.cs @@ -0,0 +1,223 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; +using TechHelper.Services.Beta; + +namespace TechHelper.Server.Controllers +{ + [Route("api/submission-detail")] + [ApiController] + [Authorize] + public class SubmissionDetailController : ControllerBase + { + private readonly UserManager _userManager; + private readonly ISubmissionDetailService _submissionDetailService; + + public SubmissionDetailController(UserManager userManager, ISubmissionDetailService submissionDetailService) + { + _userManager = userManager; + _submissionDetailService = submissionDetailService; + } + + #region 基本CRUD操作 + + /// + /// 获取所有提交详情 + /// + /// 查询参数 + /// 提交详情列表 + [HttpGet()] + [Authorize(Roles = "Admin,Teacher")] + public async Task GetAllAsync([FromQuery] QueryParameter query) + { + var result = await _submissionDetailService.GetAllAsync(query); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 根据ID获取提交详情 + /// + /// 提交详情ID + /// 提交详情详情 + [HttpGet("{id:guid}")] + public async Task GetAsync(Guid id) + { + var result = await _submissionDetailService.GetAsync(id); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 创建提交详情 + /// + /// 提交详情数据传输对象 + /// 创建结果 + [HttpPost()] + public async Task AddAsync([FromBody] SubmissionDetailDto model) + { + var result = await _submissionDetailService.AddAsync(model); + return result.Status ? StatusCode(201, result) : BadRequest(result.Message); + } + + /// + /// 更新提交详情 + /// + /// 提交详情ID + /// 提交详情数据传输对象 + /// 更新结果 + [HttpPut("{id:guid}")] + public async Task UpdateAsync(Guid id, [FromBody] SubmissionDetailDto model) + { + if (id != model.Id) + { + return BadRequest("路由ID与请求体中的ID不匹配。"); + } + + var result = await _submissionDetailService.UpdateAsync(model); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 删除提交详情 + /// + /// 提交详情ID + /// 删除结果 + [HttpDelete("delete/{id:guid}")] + public async Task DeleteAsync(Guid id) + { + var result = await _submissionDetailService.DeleteAsync(id); + return result.Status ? NoContent() : BadRequest(result.Message); + } + + #endregion + + #region 特殊操作 + + /// + /// 根据提交ID获取提交详情列表 + /// + /// 提交ID + /// 提交详情列表 + [HttpGet("by-submission/{submissionId:guid}")] + public async Task GetBySubmissionIdAsync(Guid submissionId) + { + var result = await _submissionDetailService.GetBySubmissionIdAsync(submissionId); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 根据学生ID和考试ID获取提交详情 + /// + /// 学生ID + /// 考试ID + /// 提交详情列表 + [HttpGet("by-student-exam")] + public async Task GetByStudentAndExamAsync([FromQuery] Guid studentId, [FromQuery] Guid examId) + { + var result = await _submissionDetailService.GetByStudentAndExamAsync(studentId, examId); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 批量创建提交详情 + /// + /// 提交ID + /// 提交详情列表 + /// 创建结果 + [HttpPost("batch-create/{submissionId:guid}")] + public async Task BatchCreateAsync(Guid submissionId, [FromBody] List details) + { + var result = await _submissionDetailService.BatchCreateAsync(submissionId, details); + return result.Status ? StatusCode(201, result) : BadRequest(result.Message); + } + + /// + /// 批量更新提交详情 + /// + /// 提交详情列表 + /// 更新结果 + [HttpPut("batch-update")] + public async Task BatchUpdateAsync([FromBody] List details) + { + var result = await _submissionDetailService.BatchUpdateAsync(details); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 更新提交详情评分 + /// + /// 提交详情ID + /// 分数 + /// 反馈 + /// 更新结果 + [HttpPut("{detailId:guid}/score")] + public async Task UpdateScoreAsync(Guid detailId, [FromQuery] float? points, [FromQuery] string? feedback) + { + var result = await _submissionDetailService.UpdateScoreAsync(detailId, points, feedback); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 获取错题详情 + /// + /// 学生ID + /// 考试ID + /// 错题详情列表 + [HttpGet("error-details")] + [Authorize(Roles = "Student,Teacher")] + public async Task GetErrorDetailsAsync([FromQuery] Guid studentId, [FromQuery] Guid examId) + { + var result = await _submissionDetailService.GetErrorDetailsAsync(studentId, examId); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 获取正确题详情 + /// + /// 学生ID + /// 考试ID + /// 正确题详情列表 + [HttpGet("correct-details")] + [Authorize(Roles = "Student,Teacher")] + public async Task GetCorrectDetailsAsync([FromQuery] Guid studentId, [FromQuery] Guid examId) + { + var result = await _submissionDetailService.GetCorrectDetailsAsync(studentId, examId); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 获取未批改的提交详情 + /// + /// 未批改的提交详情列表 + [HttpGet("ungraded")] + [Authorize(Roles = "Teacher")] + public async Task GetUngradedDetailsAsync() + { + var user = await _userManager.FindByEmailAsync(User.Identity.Name); + if (user == null) + { + return NotFound("未找到当前用户信息。"); + } + + var result = await _submissionDetailService.GetUngradedDetailsAsync(user.Id); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + /// + /// 批量更新提交详情状态 + /// + /// 提交ID + /// 状态 + /// 更新结果 + [HttpPut("{submissionId:guid}/status")] + public async Task UpdateStatusAsync(Guid submissionId, [FromQuery] SubmissionStatus status) + { + var result = await _submissionDetailService.UpdateStatusAsync(submissionId, status); + return result.Status ? Ok(result) : BadRequest(result.Message); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/TextbookController.cs b/TechHelper.Server/Controllers/TextbookController.cs new file mode 100644 index 0000000..620f572 --- /dev/null +++ b/TechHelper.Server/Controllers/TextbookController.cs @@ -0,0 +1,209 @@ +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using TechHelper.Services; +using TechHelper.Services.Beta; + +namespace TechHelper.Server.Controllers +{ + /// + /// 教材管理控制器 + /// 处理教材相关的操作,如创建、更新、删除教材等 + /// + [Route("api/textbook")] + [ApiController] + public class TextbookController : ControllerBase + { + private readonly ITextbookService _textbookService; + private readonly UserManager _userManager; + + /// + /// 初始化教材控制器 + /// + /// 教材服务 + /// 用户管理服务 + public TextbookController(ITextbookService textbookService, UserManager userManager) + { + _textbookService = textbookService; + _userManager = userManager; + } + + #region 教材基本信息CRUD操作 + + /// + /// 获取教材列表(支持搜索) + /// + /// 查询参数 + /// 教材列表 + /// 成功获取教材列表 + /// 获取失败 + [HttpGet] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetAll([FromQuery] QueryParameter query) + { + var result = await _textbookService.GetAllAsync(query); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据ID获取教材详细信息 + /// + /// 教材ID + /// 教材详细信息 + /// 成功获取教材信息 + /// 教材未找到或获取失败 + [HttpGet("{id}")] + [Authorize(Roles = "Teacher,Admin")] + public async Task GetById(Guid id) + { + var result = await _textbookService.GetAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 创建新教材 + /// + /// 教材数据传输对象 + /// 创建结果 + /// 创建成功 + /// 创建失败 + [HttpPost] + [Authorize(Roles = "Admin,Teacher")] + public async Task Create([FromBody] TextbookDto model) + { + var result = await _textbookService.AddAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 更新教材信息 + /// + /// 教材数据传输对象 + /// 更新结果 + /// 更新成功 + /// 更新失败 + [HttpPut] + [Authorize(Roles = "Admin")] + public async Task Update([FromBody] TextbookDto model) + { + var result = await _textbookService.UpdateAsync(model); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 删除教材 + /// + /// 教材ID + /// 删除结果 + /// 删除成功 + /// 删除失败 + [HttpDelete("{id}")] + [Authorize(Roles = "Admin")] + public async Task Delete(Guid id) + { + var result = await _textbookService.DeleteAsync(id); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Message); + } + + #endregion + + #region 教材扩展操作 + + /// + /// 根据年级获取教材列表 + /// + /// 年级 + /// 教材列表 + /// 成功获取教材列表 + /// 获取失败 + [HttpGet("grade/{grade}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetByGrade(string grade) + { + var result = await _textbookService.GetAllAsync(new QueryParameter { Search = grade }); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据出版社获取教材列表 + /// + /// 出版社 + /// 教材列表 + /// 成功获取教材列表 + /// 获取失败 + [HttpGet("publisher/{publisher}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetByPublisher(string publisher) + { + var result = await _textbookService.GetAllAsync(new QueryParameter { Search = publisher }); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + /// + /// 根据学科领域获取教材列表 + /// + /// 学科领域 + /// 教材列表 + /// 成功获取教材列表 + /// 获取失败 + [HttpGet("subjectArea/{subjectArea}")] + [Authorize(Roles = "Student,Teacher,Admin")] + public async Task GetBySubjectArea(string subjectArea) + { + var result = await _textbookService.GetAllAsync(new QueryParameter { Search = subjectArea }); + + if (!result.Status) + { + return BadRequest(result.Message); + } + + return Ok(result.Result); + } + + #endregion + } +} diff --git a/TechHelper.Server/Controllers/TokenController.cs b/TechHelper.Server/Controllers/TokenController.cs index 8f028bf..24ac854 100644 --- a/TechHelper.Server/Controllers/TokenController.cs +++ b/TechHelper.Server/Controllers/TokenController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Entities.Contracts; +using TechHelper.Services.Beta; namespace TechHelper.Controllers { diff --git a/TechHelper.Server/Controllers/UserController.cs b/TechHelper.Server/Controllers/UserController.cs index 6b18c5c..28bff7c 100644 --- a/TechHelper.Server/Controllers/UserController.cs +++ b/TechHelper.Server/Controllers/UserController.cs @@ -1,20 +1,23 @@ using Entities.Contracts; using Entities.DTO; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using TechHelper.Server.Services; using TechHelper.Services; +using TechHelper.Services.Beta; namespace TechHelper.Server.Controllers { [Route("api/user")] [ApiController] + [Authorize] public class UserController : ControllerBase { - private IUserSerivces _userSerivces; - private IClassService _classService; - private UserManager _userManager; + private readonly IUserSerivces _userSerivces; + private readonly IClassService _classService; + private readonly UserManager _userManager; + public UserController(IClassService classService, UserManager userManager, IUserSerivces userSerivces) { _classService = classService; @@ -22,29 +25,186 @@ namespace TechHelper.Server.Controllers _userSerivces = userSerivces; } - - [HttpPost("get")] - public async Task GetAsync( - [FromBody] UserRegistrationToClassDto toClass) + /// + /// 获取指定用户信息 + /// + /// 用户ID + /// 用户信息 + [HttpGet("{id}")] + public async Task GetUserById(Guid id) { - return Ok(); + var result = await _userSerivces.GetAsync(id); + if (!result.Status) + { + return NotFound(result); + } + return Ok(result); } + /// + /// 获取所有用户列表 + /// + /// 查询参数 + /// 用户列表 + [HttpGet] + public async Task GetAllUsers([FromQuery] QueryParameter query) + { + var result = await _userSerivces.GetAllAsync(query); + if (!result.Status) + { + return BadRequest(result); + } + return Ok(result); + } + /// + /// 添加新用户 + /// + /// 用户数据 + /// 操作结果 + [HttpPost] + public async Task AddUser([FromBody] UserDto userDto) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + var result = await _userSerivces.AddAsync(userDto); + if (!result.Status) + { + return BadRequest(result); + } + return CreatedAtAction(nameof(GetUserById), new { id = userDto.Id }, result); + } + + /// + /// 更新用户信息 + /// + /// 用户ID + /// 用户数据 + /// 操作结果 + [HttpPut("{id}")] + public async Task UpdateUser(Guid id, [FromBody] UserDto userDto) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + if (id != userDto.Id) + { + return BadRequest("用户ID不匹配"); + } + + var result = await _userSerivces.UpdateAsync(userDto); + if (!result.Status) + { + return BadRequest(result); + } + return Ok(result); + } + + /// + /// 删除用户 + /// + /// 用户ID + /// 操作结果 + [HttpDelete("{id}")] + public async Task DeleteUser(Guid id) + { + var result = await _userSerivces.DeleteAsync(id); + if (!result.Status) + { + return BadRequest(result); + } + return Ok(result); + } + + /// + /// 获取学生详细信息 + /// + /// 用户ID + /// 学生详细信息 + [HttpGet("student/{userId}")] + public async Task GetStudentDetailInfo(Guid userId) + { + var result = await _userSerivces.GetStudentDetailInfo(userId); + if (!result.Status) + { + return NotFound(result); + } + return Ok(result); + } + + /// + /// 验证用户信息 + /// + /// 用户ID + /// 验证结果 + [HttpPost("verify/{userId}")] + public async Task VerifyUserInformation(Guid userId) + { + var result = await _userSerivces.VerifyUserInformation(userId); + if (!result.Status) + { + return BadRequest(result); + } + return Ok(result); + } + + /// + /// 恢复用户角色信息 + /// + /// 操作结果 [HttpGet("restoreUserRole")] public async Task RestoreUserRole() { var user = await _userManager.FindByEmailAsync(User.Identity.Name); - - if (user == null) return NotFound(); + if (user == null) return NotFound("用户不存在"); + if (User.IsInRole("Teacher") || User.IsInRole("Student")) - return Ok(); + return Ok(new ApiResponse(true, "用户角色已正确设置")); + var result = await _userSerivces.RestoreUserRoleInformation(user); if (result.Status) - return Ok(); + return Ok(result); else - return Unauthorized(); + return Unauthorized(result); + } + + /// + /// 注册新用户 + /// + /// 注册数据 + /// 注册结果 + [HttpPost("register")] + [AllowAnonymous] + public async Task RegisterNewUser([FromBody] UserForRegistrationDto registrationDto) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var result = await _userSerivces.RegisterNewUserAsync(registrationDto); + if (!result.Status) + { + return BadRequest(result); + } + return Ok(result); + } + + /// + /// 获取指定用户信息(旧接口) + /// + /// 班级注册数据 + /// 操作结果 + [HttpPost("get")] + [Obsolete("请使用 GET /api/user/{id} 接口")] + public async Task GetAsync([FromBody] UserRegistrationToClassDto toClass) + { + return Ok(new ApiResponse(false, "此接口已弃用,请使用新的接口")); } } } diff --git a/TechHelper.Server/Controllers/WeatherForecastController.cs b/TechHelper.Server/Controllers/WeatherForecastController.cs deleted file mode 100644 index 730f190..0000000 --- a/TechHelper.Server/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace TechHelper.Server.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} diff --git a/TechHelper.Server/Migrations/20250626073834_init.Designer.cs b/TechHelper.Server/Migrations/20250626073834_init.Designer.cs deleted file mode 100644 index b0f9267..0000000 --- a/TechHelper.Server/Migrations/20250626073834_init.Designer.cs +++ /dev/null @@ -1,1235 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250626073834_init")] - partial class init - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("char(36)") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne("Assignment") - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId"); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("Assignment"); - - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250627101025_upd.Designer.cs b/TechHelper.Server/Migrations/20250627101025_upd.Designer.cs deleted file mode 100644 index 5cab7e3..0000000 --- a/TechHelper.Server/Migrations/20250627101025_upd.Designer.cs +++ /dev/null @@ -1,1241 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250627101025_upd")] - partial class upd - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("char(36)") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne("Assignment") - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("Assignment"); - - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250627101025_upd.cs b/TechHelper.Server/Migrations/20250627101025_upd.cs deleted file mode 100644 index 849e9ec..0000000 --- a/TechHelper.Server/Migrations/20250627101025_upd.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class upd : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_assignment_questions_assignment_questions_parent_question_gr~", - table: "assignment_questions"); - - migrationBuilder.DropForeignKey( - name: "FK_submission_details_AspNetUsers_student_id", - table: "submission_details"); - - migrationBuilder.DropForeignKey( - name: "FK_submissions_AspNetUsers_student_id", - table: "submissions"); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("3cfe35e8-73d5-4170-9856-f1d078554822")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("8546457c-185c-4b79-bece-bc21e41d02e7")); - - migrationBuilder.AddColumn( - name: "sequence", - table: "assignment_questions", - type: "longtext", - nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"), null, "Teacher", "TEACHER" }, - { new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"), null, "Student", "STUDENT" } - }); - - migrationBuilder.AddForeignKey( - name: "FK_assignment_questions_assignment_questions_parent_question_gr~", - table: "assignment_questions", - column: "parent_question_group_id", - principalTable: "assignment_questions", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_submission_details_AspNetUsers_student_id", - table: "submission_details", - column: "student_id", - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_submissions_AspNetUsers_student_id", - table: "submissions", - column: "student_id", - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_assignment_questions_assignment_questions_parent_question_gr~", - table: "assignment_questions"); - - migrationBuilder.DropForeignKey( - name: "FK_submission_details_AspNetUsers_student_id", - table: "submission_details"); - - migrationBuilder.DropForeignKey( - name: "FK_submissions_AspNetUsers_student_id", - table: "submissions"); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9")); - - migrationBuilder.DropColumn( - name: "sequence", - table: "assignment_questions"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"), null, "Student", "STUDENT" }, - { new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"), null, "Teacher", "TEACHER" }, - { new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"), null, "Administrator", "ADMINISTRATOR" } - }); - - migrationBuilder.AddForeignKey( - name: "FK_assignment_questions_assignment_questions_parent_question_gr~", - table: "assignment_questions", - column: "parent_question_group_id", - principalTable: "assignment_questions", - principalColumn: "id"); - - migrationBuilder.AddForeignKey( - name: "FK_submission_details_AspNetUsers_student_id", - table: "submission_details", - column: "student_id", - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - - migrationBuilder.AddForeignKey( - name: "FK_submissions_AspNetUsers_student_id", - table: "submissions", - column: "student_id", - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - } - } -} diff --git a/TechHelper.Server/Migrations/20250627101514_upde.Designer.cs b/TechHelper.Server/Migrations/20250627101514_upde.Designer.cs deleted file mode 100644 index b6b8e47..0000000 --- a/TechHelper.Server/Migrations/20250627101514_upde.Designer.cs +++ /dev/null @@ -1,1241 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250627101514_upde")] - partial class upde - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("char(36)") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("f282e759-deb5-4366-aaf1-51366131cf75"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne("Assignment") - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("Assignment"); - - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250627101514_upde.cs b/TechHelper.Server/Migrations/20250627101514_upde.cs deleted file mode 100644 index 14a72e6..0000000 --- a/TechHelper.Server/Migrations/20250627101514_upde.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class upde : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9")); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"), null, "Student", "STUDENT" }, - { new Guid("f282e759-deb5-4366-aaf1-51366131cf75"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"), null, "Teacher", "TEACHER" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f282e759-deb5-4366-aaf1-51366131cf75")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a")); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("5f0c1b3c-ad05-4ca9-b9fd-a359cb518236"), null, "Teacher", "TEACHER" }, - { new Guid("a81f5de2-9691-45fa-8d31-ae4ffeb34453"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("c310acf7-9605-4c55-8b9f-9bf9cd2dadb9"), null, "Student", "STUDENT" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250627105626_updedd.Designer.cs b/TechHelper.Server/Migrations/20250627105626_updedd.Designer.cs deleted file mode 100644 index e1bfbb3..0000000 --- a/TechHelper.Server/Migrations/20250627105626_updedd.Designer.cs +++ /dev/null @@ -1,1250 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250627105626_updedd")] - partial class updedd - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("char(36)") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250627105626_updedd.cs b/TechHelper.Server/Migrations/20250627105626_updedd.cs deleted file mode 100644 index b85fc51..0000000 --- a/TechHelper.Server/Migrations/20250627105626_updedd.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class updedd : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f282e759-deb5-4366-aaf1-51366131cf75")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a")); - - migrationBuilder.AddColumn( - name: "AssignmentId", - table: "assignment_questions", - type: "char(36)", - nullable: true, - collation: "ascii_general_ci"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"), null, "Student", "STUDENT" }, - { new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"), null, "Teacher", "TEACHER" } - }); - - migrationBuilder.CreateIndex( - name: "IX_assignment_questions_AssignmentId", - table: "assignment_questions", - column: "AssignmentId"); - - migrationBuilder.AddForeignKey( - name: "FK_assignment_questions_assignments_AssignmentId", - table: "assignment_questions", - column: "AssignmentId", - principalTable: "assignments", - principalColumn: "id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_assignment_questions_assignments_AssignmentId", - table: "assignment_questions"); - - migrationBuilder.DropIndex( - name: "IX_assignment_questions_AssignmentId", - table: "assignment_questions"); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("cf16c215-63f8-4962-8ad0-058274ecf944")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849")); - - migrationBuilder.DropColumn( - name: "AssignmentId", - table: "assignment_questions"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("c0f247ab-b12a-432e-8ce7-d0e28811957e"), null, "Student", "STUDENT" }, - { new Guid("f282e759-deb5-4366-aaf1-51366131cf75"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("f9eeea07-eeda-4bbe-a2e4-6aef2f3c7c9a"), null, "Teacher", "TEACHER" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.Designer.cs b/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.Designer.cs deleted file mode 100644 index 1a4119e..0000000 --- a/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.Designer.cs +++ /dev/null @@ -1,1254 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250630090135__update_submisstion_detail")] - partial class _update_submisstion_detail - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("char(36)") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.cs b/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.cs deleted file mode 100644 index 70d6ba4..0000000 --- a/TechHelper.Server/Migrations/20250630090135__update_submisstion_detail.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class _update_submisstion_detail : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("cf16c215-63f8-4962-8ad0-058274ecf944")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849")); - - migrationBuilder.AddColumn( - name: "status", - table: "submission_details", - type: "int", - nullable: false, - defaultValue: 0); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"), null, "Teacher", "TEACHER" }, - { new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"), null, "Student", "STUDENT" }, - { new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"), null, "Administrator", "ADMINISTRATOR" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc")); - - migrationBuilder.DropColumn( - name: "status", - table: "submission_details"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("cf16c215-63f8-4962-8ad0-058274ecf944"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("e3bff43c-36af-497a-971c-ed0a487bdd38"), null, "Student", "STUDENT" }, - { new Guid("f05c125e-e70f-40eb-9e19-6e69c3426849"), null, "Teacher", "TEACHER" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.Designer.cs b/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.Designer.cs deleted file mode 100644 index fd51de4..0000000 --- a/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.Designer.cs +++ /dev/null @@ -1,1254 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250701095424_atemp_number_convert_to_byte")] - partial class atemp_number_convert_to_byte - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.cs b/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.cs deleted file mode 100644 index d218e43..0000000 --- a/TechHelper.Server/Migrations/20250701095424_atemp_number_convert_to_byte.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class atemp_number_convert_to_byte : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc")); - - migrationBuilder.AlterColumn( - name: "attempt_number", - table: "submissions", - type: "tinyint unsigned", - nullable: false, - oldClrType: typeof(Guid), - oldType: "char(36)") - .OldAnnotation("Relational:Collation", "ascii_general_ci"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"), null, "Student", "STUDENT" }, - { new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"), null, "Teacher", "TEACHER" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f")); - - migrationBuilder.AlterColumn( - name: "attempt_number", - table: "submissions", - type: "char(36)", - nullable: false, - collation: "ascii_general_ci", - oldClrType: typeof(byte), - oldType: "tinyint unsigned"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("14b8854f-a38b-4e72-878e-31ba2f7528b2"), null, "Teacher", "TEACHER" }, - { new Guid("69c3cc0c-b284-433e-8493-9b1e7bd1eb1f"), null, "Student", "STUDENT" }, - { new Guid("6ef4d2bb-05da-4c17-9152-4467d86939fc"), null, "Administrator", "ADMINISTRATOR" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250828025055_score_in_submission.Designer.cs b/TechHelper.Server/Migrations/20250828025055_score_in_submission.Designer.cs deleted file mode 100644 index 814ffc3..0000000 --- a/TechHelper.Server/Migrations/20250828025055_score_in_submission.Designer.cs +++ /dev/null @@ -1,1263 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250828025055_score_in_submission")] - partial class score_in_submission - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("bbea7915-e27c-4ddc-b06c-1f579fc8104e"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("53307917-63c4-468a-ab05-a03882a69ef8"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("789b7819-685f-4a2b-9adf-463f397f24d1"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250828025055_score_in_submission.cs b/TechHelper.Server/Migrations/20250828025055_score_in_submission.cs deleted file mode 100644 index ad6533b..0000000 --- a/TechHelper.Server/Migrations/20250828025055_score_in_submission.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class score_in_submission : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f")); - - migrationBuilder.AddColumn( - name: "ErrorQuesNum", - table: "submissions", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.AddColumn( - name: "TotalQuesNum", - table: "submissions", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.AddColumn( - name: "TotalScore", - table: "submissions", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("53307917-63c4-468a-ab05-a03882a69ef8"), null, "Teacher", "TEACHER" }, - { new Guid("789b7819-685f-4a2b-9adf-463f397f24d1"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("bbea7915-e27c-4ddc-b06c-1f579fc8104e"), null, "Student", "STUDENT" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("53307917-63c4-468a-ab05-a03882a69ef8")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("789b7819-685f-4a2b-9adf-463f397f24d1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("bbea7915-e27c-4ddc-b06c-1f579fc8104e")); - - migrationBuilder.DropColumn( - name: "ErrorQuesNum", - table: "submissions"); - - migrationBuilder.DropColumn( - name: "TotalQuesNum", - table: "submissions"); - - migrationBuilder.DropColumn( - name: "TotalScore", - table: "submissions"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("379143a2-8d7f-4ef7-b7c0-14701b710f87"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("6d49bb08-97d6-4a38-88a7-8080925b589b"), null, "Student", "STUDENT" }, - { new Guid("e330c745-f422-43e3-bcdf-1439ace3c52f"), null, "Teacher", "TEACHER" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250829043403_up_assign_data.Designer.cs b/TechHelper.Server/Migrations/20250829043403_up_assign_data.Designer.cs deleted file mode 100644 index 197ebdc..0000000 --- a/TechHelper.Server/Migrations/20250829043403_up_assign_data.Designer.cs +++ /dev/null @@ -1,1270 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250829043403_up_assign_data")] - partial class up_assign_data - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("37f41430-0cb7-44e5-988b-976200bd602d"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250829043403_up_assign_data.cs b/TechHelper.Server/Migrations/20250829043403_up_assign_data.cs deleted file mode 100644 index df6349a..0000000 --- a/TechHelper.Server/Migrations/20250829043403_up_assign_data.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class up_assign_data : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("53307917-63c4-468a-ab05-a03882a69ef8")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("789b7819-685f-4a2b-9adf-463f397f24d1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("bbea7915-e27c-4ddc-b06c-1f579fc8104e")); - - migrationBuilder.AddColumn( - name: "ExamType", - table: "assignments", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.AddColumn( - name: "Name", - table: "assignments", - type: "longtext", - nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"), null, "Teacher", "TEACHER" }, - { new Guid("37f41430-0cb7-44e5-988b-976200bd602d"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"), null, "Student", "STUDENT" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("0775702a-5db7-4747-94d0-4376fad2b58b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("37f41430-0cb7-44e5-988b-976200bd602d")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70")); - - migrationBuilder.DropColumn( - name: "ExamType", - table: "assignments"); - - migrationBuilder.DropColumn( - name: "Name", - table: "assignments"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("53307917-63c4-468a-ab05-a03882a69ef8"), null, "Teacher", "TEACHER" }, - { new Guid("789b7819-685f-4a2b-9adf-463f397f24d1"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("bbea7915-e27c-4ddc-b06c-1f579fc8104e"), null, "Student", "STUDENT" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250901072725_question_qt_update.Designer.cs b/TechHelper.Server/Migrations/20250901072725_question_qt_update.Designer.cs deleted file mode 100644 index c732281..0000000 --- a/TechHelper.Server/Migrations/20250901072725_question_qt_update.Designer.cs +++ /dev/null @@ -1,1277 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250901072725_question_qt_update")] - partial class question_qt_update - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250901072725_question_qt_update.cs b/TechHelper.Server/Migrations/20250901072725_question_qt_update.cs deleted file mode 100644 index fc93975..0000000 --- a/TechHelper.Server/Migrations/20250901072725_question_qt_update.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class question_qt_update : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("0775702a-5db7-4747-94d0-4376fad2b58b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("37f41430-0cb7-44e5-988b-976200bd602d")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70")); - - migrationBuilder.AddColumn( - name: "QType", - table: "questions", - type: "longtext", - nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.AddColumn( - name: "Type", - table: "assignment_questions", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"), null, "Teacher", "TEACHER" }, - { new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"), null, "Student", "STUDENT" }, - { new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"), null, "Administrator", "ADMINISTRATOR" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274")); - - migrationBuilder.DropColumn( - name: "QType", - table: "questions"); - - migrationBuilder.DropColumn( - name: "Type", - table: "assignment_questions"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("0775702a-5db7-4747-94d0-4376fad2b58b"), null, "Teacher", "TEACHER" }, - { new Guid("37f41430-0cb7-44e5-988b-976200bd602d"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("df89b9a0-65ef-42dd-b2cb-e59997a72e70"), null, "Student", "STUDENT" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.Designer.cs b/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.Designer.cs deleted file mode 100644 index 769e685..0000000 --- a/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.Designer.cs +++ /dev/null @@ -1,1296 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250901080732_question_qt_update_2")] - partial class question_qt_update_2 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Area") - .HasColumnType("tinyint unsigned"); - - b.Property("Info") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("global"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.cs b/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.cs deleted file mode 100644 index 2603b32..0000000 --- a/TechHelper.Server/Migrations/20250901080732_question_qt_update_2.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class question_qt_update_2 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274")); - - migrationBuilder.CreateTable( - name: "global", - columns: table => new - { - id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - Area = table.Column(type: "tinyint unsigned", nullable: false), - Info = table.Column(type: "longtext", nullable: false) - .Annotation("MySql:CharSet", "utf8mb4") - }, - constraints: table => - { - table.PrimaryKey("PK_global", x => x.id); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"), null, "Teacher", "TEACHER" }, - { new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"), null, "Student", "STUDENT" }, - { new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"), null, "Administrator", "ADMINISTRATOR" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "global"); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5")); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("67de6514-79a5-4a9c-b54c-13cac296b0c6"), null, "Teacher", "TEACHER" }, - { new Guid("94f0d8d9-ffba-4e28-b578-8596363d42ae"), null, "Student", "STUDENT" }, - { new Guid("bf46ed67-2dc9-40f8-8717-37dd3572f274"), null, "Administrator", "ADMINISTRATOR" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.Designer.cs b/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.Designer.cs deleted file mode 100644 index 3135303..0000000 --- a/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.Designer.cs +++ /dev/null @@ -1,1299 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250901083708_question_qt_update_3")] - partial class question_qt_update_3 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Area") - .HasColumnType("tinyint unsigned"); - - b.Property("Info") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("global"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.cs b/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.cs deleted file mode 100644 index cb7e822..0000000 --- a/TechHelper.Server/Migrations/20250901083708_question_qt_update_3.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class question_qt_update_3 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5")); - - migrationBuilder.AddColumn( - name: "SubjectArea", - table: "AspNetUsers", - type: "tinyint unsigned", - nullable: false, - defaultValue: (byte)0); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"), null, "Teacher", "TEACHER" }, - { new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"), null, "Student", "STUDENT" }, - { new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"), null, "Administrator", "ADMINISTRATOR" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("2670f35a-df0c-4071-8879-80eb99d138a1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db")); - - migrationBuilder.DropColumn( - name: "SubjectArea", - table: "AspNetUsers"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("49854839-b861-4d42-bdbe-96b1a66c25ef"), null, "Teacher", "TEACHER" }, - { new Guid("5c7a7971-2610-4bce-9e41-0caffd5a5558"), null, "Student", "STUDENT" }, - { new Guid("83ff7de8-edc9-47f8-8de8-22f892ca6bb5"), null, "Administrator", "ADMINISTRATOR" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250904101811_submission_up_2.Designer.cs b/TechHelper.Server/Migrations/20250904101811_submission_up_2.Designer.cs deleted file mode 100644 index 5aa201a..0000000 --- a/TechHelper.Server/Migrations/20250904101811_submission_up_2.Designer.cs +++ /dev/null @@ -1,1299 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using TechHelper.Context; - -#nullable disable - -namespace TechHelper.Server.Migrations -{ - [DbContext(typeof(ApplicationContext))] - [Migration("20250904101811_submission_up_2")] - partial class submission_up_2 - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "8.0.16") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("DueDate") - .HasColumnType("datetime(6)") - .HasColumnName("due_date"); - - b.Property("ExamStructId") - .HasColumnType("char(36)") - .HasColumnName("exam_struct_id"); - - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("Name") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("title"); - - b.Property("TotalQuestions") - .HasColumnType("tinyint unsigned") - .HasColumnName("total_points"); - - b.Property("UpdatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("ExamStructId") - .IsUnique(); - - b.HasIndex("UserId"); - - b.ToTable("assignments", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("FileName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_name"); - - b.Property("FilePath") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)") - .HasColumnName("file_path"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("UploadedAt") - .HasColumnType("datetime(6)") - .HasColumnName("uploaded_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.ToTable("assignment_attachments"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("CreatedAt") - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - b.Property("Index") - .HasColumnType("tinyint unsigned") - .HasColumnName("question_number"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("ParentAssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("parent_question_group_id"); - - b.Property("QuestionContextId") - .HasColumnType("char(36)") - .HasColumnName("description"); - - b.Property("QuestionId") - .HasColumnType("char(36)") - .HasColumnName("question_id"); - - b.Property("Score") - .HasColumnType("float") - .HasColumnName("score"); - - b.Property("Sequence") - .IsRequired() - .HasColumnType("longtext") - .HasColumnName("sequence"); - - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - - b.Property("Title") - .HasMaxLength(1024) - .HasColumnType("varchar(1024)") - .HasColumnName("title"); - - b.Property("Type") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); - - b.HasIndex("QuestionContextId"); - - b.HasIndex("QuestionId"); - - b.ToTable("assignment_questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("Description") - .HasColumnType("longtext") - .HasColumnName("description"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); - - b.HasKey("Id"); - - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Area") - .HasColumnType("tinyint unsigned"); - - b.Property("Info") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("global"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Key") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("key_point"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("TextbookID") - .HasColumnType("char(36)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("varchar(255)"); - - b.HasKey("Id"); - - b.HasIndex("TextbookID"); - - b.ToTable("lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("LessonID") - .HasColumnType("char(36)"); - - b.Property("Question") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.HasIndex("LessonID"); - - b.ToTable("lesson_question"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("Answer") - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("correct_answer"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("KeyPointId") - .HasColumnType("char(36)") - .HasColumnName("key_point"); - - b.Property("LessonId") - .HasColumnType("char(36)") - .HasColumnName("lesson"); - - b.Property("Options") - .HasColumnType("longtext") - .HasColumnName("options"); - - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(65535) - .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("KeyPointId"); - - b.HasIndex("LessonId"); - - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); - - b.ToTable("questions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Description") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("QuestionContexts"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - - b.Property("AttemptNumber") - .HasColumnType("tinyint unsigned") - .HasColumnName("attempt_number"); - - b.Property("ErrorQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("GradedAt") - .HasColumnType("datetime(6)") - .HasColumnName("graded_at"); - - b.Property("GraderId") - .HasColumnType("char(36)") - .HasColumnName("graded_by"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("OverallFeedback") - .HasColumnType("longtext") - .HasColumnName("overall_feedback"); - - b.Property("OverallGrade") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("overall_grade"); - - b.Property("Status") - .HasMaxLength(15) - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionTime") - .HasColumnType("datetime(6)") - .HasColumnName("submission_time"); - - b.Property("TotalQuesNum") - .HasColumnType("tinyint unsigned"); - - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentId"); - - b.HasIndex("GraderId"); - - b.HasIndex("StudentId"); - - b.ToTable("submissions", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)") - .HasColumnName("id"); - - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("IsCorrect") - .HasColumnType("tinyint(1)") - .HasColumnName("is_correct"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("PointsAwarded") - .HasPrecision(5, 2) - .HasColumnType("float") - .HasColumnName("points_awarded"); - - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - - b.Property("StudentAnswer") - .HasColumnType("longtext") - .HasColumnName("student_answer"); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id"); - - b.Property("SubmissionId") - .HasColumnType("char(36)") - .HasColumnName("submission_id"); - - b.Property("TeacherFeedback") - .HasColumnType("longtext") - .HasColumnName("teacher_feedback"); - - b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - b.HasKey("Id"); - - b.HasIndex("AssignmentQuestionId"); - - b.HasIndex("StudentId"); - - b.HasIndex("SubmissionId"); - - b.ToTable("submission_details", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("Grade") - .HasColumnType("tinyint unsigned"); - - b.Property("Publisher") - .HasColumnType("tinyint unsigned"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("Title") - .IsRequired() - .HasColumnType("longtext"); - - b.HasKey("Id"); - - b.ToTable("textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("AccessFailedCount") - .HasColumnType("int"); - - b.Property("Address") - .HasColumnType("longtext"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("DisplayName") - .HasColumnType("longtext"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("IsDeleted") - .HasColumnType("tinyint(1)") - .HasColumnName("deleted"); - - b.Property("LockoutEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("LockoutEnd") - .HasColumnType("datetime(6)"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("PasswordHash") - .HasColumnType("longtext"); - - b.Property("PhoneNumber") - .HasColumnType("longtext"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("tinyint(1)"); - - b.Property("RefreshToken") - .HasColumnType("longtext"); - - b.Property("RefreshTokenExpiryTime") - .HasColumnType("datetime(6)"); - - b.Property("SecurityStamp") - .HasColumnType("longtext"); - - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); - - b.Property("TwoFactorEnabled") - .HasColumnType("tinyint(1)"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("char(36)"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("varchar(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("longtext"); - - b.Property("ClaimValue") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("ProviderKey") - .HasColumnType("varchar(255)"); - - b.Property("ProviderDisplayName") - .HasColumnType("longtext"); - - b.Property("UserId") - .HasColumnType("char(36)"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("RoleId") - .HasColumnType("char(36)"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("char(36)"); - - b.Property("LoginProvider") - .HasColumnType("varchar(255)"); - - b.Property("Name") - .HasColumnType("varchar(255)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.HasOne("Entities.Contracts.User", "HeadTeacher") - .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("HeadTeacher"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Class"); - - b.Navigation("Teacher"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("KeyPoints") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.HasOne("Entities.Contracts.Textbook", "Textbook") - .WithMany("Lessons") - .HasForeignKey("TextbookID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Textbook"); - }); - - modelBuilder.Entity("Entities.Contracts.LessonQuestion", b => - { - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("LessonQuestions") - .HasForeignKey("LessonID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") - .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Lesson", "Lesson") - .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); - - b.Navigation("Creator"); - - b.Navigation("KeyPoint"); - - b.Navigation("Lesson"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("Submissions") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Grader") - .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Grader"); - - b.Navigation("Student"); - }); - - modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => - { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") - .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionDetails") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Submission", "Submission") - .WithMany("SubmissionDetails") - .HasForeignKey("SubmissionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("AssignmentQuestion"); - - b.Navigation("Student"); - - b.Navigation("Submission"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Entities.Contracts.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.Navigation("AssignmentAttachments"); - - b.Navigation("AssignmentClasses"); - - b.Navigation("Submissions"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.Navigation("ChildrenAssignmentQuestion"); - - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Class", b => - { - b.Navigation("AssignmentClasses"); - - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); - }); - - modelBuilder.Entity("Entities.Contracts.KeyPoint", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Lesson", b => - { - b.Navigation("KeyPoints"); - - b.Navigation("LessonQuestions"); - - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Question", b => - { - b.Navigation("AssignmentQuestions"); - }); - - modelBuilder.Entity("Entities.Contracts.QuestionContext", b => - { - b.Navigation("Questions"); - }); - - modelBuilder.Entity("Entities.Contracts.Submission", b => - { - b.Navigation("SubmissionDetails"); - }); - - modelBuilder.Entity("Entities.Contracts.Textbook", b => - { - b.Navigation("Lessons"); - }); - - modelBuilder.Entity("Entities.Contracts.User", b => - { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); - - b.Navigation("GradedSubmissions"); - - b.Navigation("SubmissionDetails"); - - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/TechHelper.Server/Migrations/20250904101811_submission_up_2.cs b/TechHelper.Server/Migrations/20250904101811_submission_up_2.cs deleted file mode 100644 index 8011f05..0000000 --- a/TechHelper.Server/Migrations/20250904101811_submission_up_2.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class submission_up_2 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("2670f35a-df0c-4071-8879-80eb99d138a1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db")); - - migrationBuilder.AlterColumn( - name: "overall_grade", - table: "submissions", - type: "float", - precision: 5, - scale: 2, - nullable: false, - defaultValue: 0f, - oldClrType: typeof(float), - oldType: "float", - oldPrecision: 5, - oldScale: 2, - oldNullable: true); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"), null, "Teacher", "TEACHER" }, - { new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"), null, "Student", "STUDENT" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc")); - - migrationBuilder.AlterColumn( - name: "overall_grade", - table: "submissions", - type: "float", - precision: 5, - scale: 2, - nullable: true, - oldClrType: typeof(float), - oldType: "float", - oldPrecision: 5, - oldScale: 2); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("2670f35a-df0c-4071-8879-80eb99d138a1"), null, "Teacher", "TEACHER" }, - { new Guid("8c6c5e8e-ef00-444c-9c7c-cba5cd6f7043"), null, "Student", "STUDENT" }, - { new Guid("9eda9d90-0cd2-4fbe-b07e-f90bd01f32db"), null, "Administrator", "ADMINISTRATOR" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250904102023_submission_up_3.cs b/TechHelper.Server/Migrations/20250904102023_submission_up_3.cs deleted file mode 100644 index 33a33c3..0000000 --- a/TechHelper.Server/Migrations/20250904102023_submission_up_3.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class submission_up_3 : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc")); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"), null, "Teacher", "TEACHER" }, - { new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"), null, "Student", "STUDENT" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9")); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("264e4290-9d15-478d-8c49-8d0935e5a6e1"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("73cafcee-3e99-43ae-86c5-c01a1cbc6124"), null, "Teacher", "TEACHER" }, - { new Guid("f06927ff-4bba-4ab6-8f0a-e45a765c2fcc"), null, "Student", "STUDENT" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250905101308_tee.cs b/TechHelper.Server/Migrations/20250905101308_tee.cs deleted file mode 100644 index 760aaa8..0000000 --- a/TechHelper.Server/Migrations/20250905101308_tee.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace TechHelper.Server.Migrations -{ - /// - public partial class tee : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9")); - - migrationBuilder.AddColumn( - name: "BCorrect", - table: "assignment_questions", - type: "tinyint(1)", - nullable: false, - defaultValue: false); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"), null, "Student", "STUDENT" }, - { new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"), null, "Teacher", "TEACHER" }, - { new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"), null, "Administrator", "ADMINISTRATOR" } - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d")); - - migrationBuilder.DeleteData( - table: "AspNetRoles", - keyColumn: "Id", - keyValue: new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b")); - - migrationBuilder.DropColumn( - name: "BCorrect", - table: "assignment_questions"); - - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"), null, "Administrator", "ADMINISTRATOR" }, - { new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"), null, "Teacher", "TEACHER" }, - { new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"), null, "Student", "STUDENT" } - }); - } - } -} diff --git a/TechHelper.Server/Migrations/20250905101308_tee.Designer.cs b/TechHelper.Server/Migrations/20250929035019_init.Designer.cs similarity index 73% rename from TechHelper.Server/Migrations/20250905101308_tee.Designer.cs rename to TechHelper.Server/Migrations/20250929035019_init.Designer.cs index e6518af..5bcb2d9 100644 --- a/TechHelper.Server/Migrations/20250905101308_tee.Designer.cs +++ b/TechHelper.Server/Migrations/20250929035019_init.Designer.cs @@ -12,8 +12,8 @@ using TechHelper.Context; namespace TechHelper.Server.Migrations { [DbContext(typeof(ApplicationContext))] - [Migration("20250905101308_tee")] - partial class tee + [Migration("20250929035019_init")] + partial class init { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -21,11 +21,87 @@ namespace TechHelper.Server.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("class_id"); + + b.Property("ClassName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("class_name"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("created_at"); + + b.Property("GradeId") + .HasColumnType("char(36)") + .HasColumnName("grade_id"); + + b.Property("HeadTeacherId") + .HasColumnType("char(36)") + .HasColumnName("head_teacher_id"); + + b.Property("Index") + .HasColumnType("tinyint unsigned") + .HasColumnName("index"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("updated_at"); + + b.HasKey("Id"); + + b.HasIndex("GradeId"); + + b.HasIndex("HeadTeacherId"); + + b.ToTable("classes"); + }); + + modelBuilder.Entity("Entities.Contracts.ClassUser", b => + { + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id") + .HasColumnOrder(0); + + b.Property("UserId") + .HasColumnType("char(36)") + .HasColumnName("student_id") + .HasColumnOrder(1); + + b.Property("EnrollmentDate") + .HasColumnType("datetime(6)") + .HasColumnName("enrollment_date"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.HasKey("ClassId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("class_user"); + }); + + modelBuilder.Entity("Entities.Contracts.Exam", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -53,8 +129,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("exam_struct_id"); - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); + b.Property("ExamTypeId") + .HasColumnType("char(36)") + .HasColumnName("exam_type_id"); b.Property("IsDeleted") .HasColumnType("tinyint(1)") @@ -62,15 +139,16 @@ namespace TechHelper.Server.Migrations b.Property("Name") .IsRequired() - .HasColumnType("longtext"); + .HasColumnType("longtext") + .HasColumnName("name"); b.Property("Score") .HasColumnType("float") .HasColumnName("score"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); b.Property("Title") .IsRequired() @@ -86,9 +164,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("datetime(6)") .HasColumnName("updated_at"); - b.Property("UserId") - .HasColumnType("char(36)"); - b.HasKey("Id"); b.HasIndex("CreatorId"); @@ -96,12 +171,14 @@ namespace TechHelper.Server.Migrations b.HasIndex("ExamStructId") .IsUnique(); - b.HasIndex("UserId"); + b.HasIndex("ExamTypeId"); - b.ToTable("assignments", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("assignments"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -139,48 +216,13 @@ namespace TechHelper.Server.Migrations b.ToTable("assignment_attachments"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("BCorrect") - .HasColumnType("tinyint(1)"); - b.Property("CreatedAt") .HasColumnType("datetime(6)") .HasColumnName("created_at"); @@ -190,12 +232,10 @@ namespace TechHelper.Server.Migrations .HasColumnName("question_number"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); - b.Property("ParentAssignmentQuestionId") + b.Property("ParentExamQuestionId") .HasColumnType("char(36)") .HasColumnName("parent_question_group_id"); @@ -207,6 +247,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("question_id"); + b.Property("QuestionTypeId") + .HasColumnType("char(36)"); + b.Property("Score") .HasColumnType("float") .HasColumnName("score"); @@ -216,148 +259,73 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("sequence"); - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - b.Property("Title") .HasMaxLength(1024) .HasColumnType("varchar(1024)") .HasColumnName("title"); - b.Property("Type") - .HasColumnType("tinyint unsigned"); - b.HasKey("Id"); - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); + b.HasIndex("ParentExamQuestionId"); b.HasIndex("QuestionContextId"); b.HasIndex("QuestionId"); - b.ToTable("assignment_questions", (string)null); + b.HasIndex("QuestionTypeId"); + + b.ToTable("assignment_questions"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - b.Property("Description") + .IsRequired() .HasColumnType("longtext") .HasColumnName("description"); - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); b.HasKey("Id"); - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); + b.ToTable("exam_type"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => + modelBuilder.Entity("Entities.Contracts.Grade", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") - .HasColumnName("id"); + .HasColumnName("grade_id"); - b.Property("Area") - .HasColumnType("tinyint unsigned"); + b.Property("GradeLevel") + .HasColumnType("tinyint unsigned") + .HasColumnName("grade_level"); - b.Property("Info") + b.Property("GradeName") .IsRequired() - .HasColumnType("longtext"); + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("grade_name"); + + b.Property("SchoolId") + .HasColumnType("char(36)") + .HasColumnName("school_id"); b.HasKey("Id"); - b.ToTable("global"); + b.HasIndex("SchoolId"); + + b.ToTable("grades"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -437,28 +405,14 @@ namespace TechHelper.Server.Migrations b.Property("Answer") .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("correct_answer"); + .HasColumnName("answer"); b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("KeyPointId") @@ -473,44 +427,35 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("options"); - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); + b.Property("QuestioTypeId") + .HasColumnType("char(36)") + .HasColumnName("type"); - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") + b.Property("SubjectId") + .HasColumnType("char(36)") .HasColumnName("subject_area"); b.Property("Title") .IsRequired() .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); + .HasColumnName("title"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("CreatorId"); - b.HasIndex("KeyPointId"); b.HasIndex("LessonId"); - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); + b.HasIndex("QuestioTypeId"); - b.ToTable("questions", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("questions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -528,6 +473,92 @@ namespace TechHelper.Server.Migrations b.ToTable("QuestionContexts"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.Property("ScoreRule") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("score_rule"); + + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("question_types"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("address"); + + b.Property("CreateTime") + .HasColumnType("datetime(6)") + .HasColumnName("create_time"); + + b.Property("SchoolName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("school_name"); + + b.HasKey("Id"); + + b.ToTable("schools"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.HasKey("Id"); + + b.ToTable("subjects"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Property("Id") @@ -535,17 +566,21 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - b.Property("AttemptNumber") .HasColumnType("tinyint unsigned") .HasColumnName("attempt_number"); + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id"); + b.Property("ErrorQuesNum") .HasColumnType("tinyint unsigned"); + b.Property("ExamId") + .HasColumnType("char(36)") + .HasColumnName("exam_id"); + b.Property("GradedAt") .HasColumnType("datetime(6)") .HasColumnName("graded_at"); @@ -555,9 +590,7 @@ namespace TechHelper.Server.Migrations .HasColumnName("graded_by"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("OverallFeedback") @@ -565,12 +598,10 @@ namespace TechHelper.Server.Migrations .HasColumnName("overall_feedback"); b.Property("OverallGrade") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("overall_grade"); b.Property("Status") - .HasMaxLength(15) .HasColumnType("int") .HasColumnName("status"); @@ -590,13 +621,15 @@ namespace TechHelper.Server.Migrations b.HasKey("Id"); - b.HasIndex("AssignmentId"); + b.HasIndex("ClassId"); + + b.HasIndex("ExamId"); b.HasIndex("GraderId"); b.HasIndex("StudentId"); - b.ToTable("submissions", (string)null); + b.ToTable("submissions"); }); modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => @@ -606,36 +639,26 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); + b.Property("ExamQuestionId") + .HasColumnType("char(36)") + .HasColumnName("assignment_question_id"); b.Property("IsCorrect") .HasColumnType("tinyint(1)") .HasColumnName("is_correct"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("PointsAwarded") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("points_awarded"); - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - b.Property("StudentAnswer") .HasColumnType("longtext") .HasColumnName("student_answer"); @@ -653,20 +676,18 @@ namespace TechHelper.Server.Migrations .HasColumnName("teacher_feedback"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("AssignmentQuestionId"); + b.HasIndex("ExamQuestionId"); b.HasIndex("StudentId"); b.HasIndex("SubmissionId"); - b.ToTable("submission_details", (string)null); + b.ToTable("submission_details"); }); modelBuilder.Entity("Entities.Contracts.Textbook", b => @@ -702,9 +723,6 @@ namespace TechHelper.Server.Migrations b.Property("AccessFailedCount") .HasColumnType("int"); - b.Property("Address") - .HasColumnType("longtext"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("longtext"); @@ -719,6 +737,9 @@ namespace TechHelper.Server.Migrations b.Property("EmailConfirmed") .HasColumnType("tinyint(1)"); + b.Property("HomeAddress") + .HasColumnType("longtext"); + b.Property("IsDeleted") .HasColumnType("tinyint(1)") .HasColumnName("deleted"); @@ -752,11 +773,14 @@ namespace TechHelper.Server.Migrations b.Property("RefreshTokenExpiryTime") .HasColumnType("datetime(6)"); + b.Property("Role") + .HasColumnType("int"); + b.Property("SecurityStamp") .HasColumnType("longtext"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); + b.Property("TeachSubjectId") + .HasColumnType("char(36)"); b.Property("TwoFactorEnabled") .HasColumnType("tinyint(1)"); @@ -774,6 +798,8 @@ namespace TechHelper.Server.Migrations .IsUnique() .HasDatabaseName("UserNameIndex"); + b.HasIndex("TeachSubjectId"); + b.ToTable("AspNetUsers", (string)null); }); @@ -802,26 +828,6 @@ namespace TechHelper.Server.Migrations .HasDatabaseName("RoleNameIndex"); b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => @@ -927,136 +933,126 @@ namespace TechHelper.Server.Migrations b.ToTable("AspNetUserTokens", (string)null); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - modelBuilder.Entity("Entities.Contracts.Class", b => { + b.HasOne("Entities.Contracts.Grade", "Grade") + .WithMany("Classes") + .HasForeignKey("GradeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Entities.Contracts.User", "HeadTeacher") .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); + .HasForeignKey("HeadTeacherId"); + + b.Navigation("Grade"); b.Navigation("HeadTeacher"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => + modelBuilder.Entity("Entities.Contracts.ClassUser", b => { b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") + .WithMany("ClassUsers") .HasForeignKey("ClassId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) + b.HasOne("Entities.Contracts.User", "User") + .WithMany("UserInjoinedClass") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Class"); - b.Navigation("Student"); + b.Navigation("User"); }); - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => + modelBuilder.Entity("Entities.Contracts.Exam", b => { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") + b.HasOne("Entities.Contracts.User", "Creator") + .WithMany("CreatedExams") + .HasForeignKey("CreatorId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamStruct") + .WithOne("Exam") + .HasForeignKey("Entities.Contracts.Exam", "ExamStructId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Class"); + b.HasOne("Entities.Contracts.ExamType", "ExamType") + .WithMany("Exams") + .HasForeignKey("ExamTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.Navigation("Teacher"); + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("ExamStruct"); + + b.Navigation("ExamType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => + { + b.HasOne("Entities.Contracts.Exam", "Exam") + .WithMany("ExamAttachments") + .HasForeignKey("AssignmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Exam"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => + { + b.HasOne("Entities.Contracts.ExamQuestion", "ParentExamQuestion") + .WithMany("ChildExamQuestions") + .HasForeignKey("ParentExamQuestionId"); + + b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") + .WithMany("Questions") + .HasForeignKey("QuestionContextId"); + + b.HasOne("Entities.Contracts.Question", "Question") + .WithMany("ExamQuestions") + .HasForeignKey("QuestionId"); + + b.HasOne("Entities.Contracts.QuestionType", "Type") + .WithMany() + .HasForeignKey("QuestionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParentExamQuestion"); + + b.Navigation("Question"); + + b.Navigation("QuestionContext"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.HasOne("Entities.Contracts.School", "School") + .WithMany("Grades") + .HasForeignKey("SchoolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("School"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1094,49 +1090,73 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("KeyPointId"); b.HasOne("Entities.Contracts.Lesson", "Lesson") .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("LessonId"); - b.Navigation("Creator"); + b.HasOne("Entities.Contracts.QuestionType", "QuestionType") + .WithMany("Questions") + .HasForeignKey("QuestioTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("Questions") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("KeyPoint"); b.Navigation("Lesson"); + + b.Navigation("QuestionType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("QuestionTypes") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => { - b.HasOne("Entities.Contracts.Assignment", "Assignment") + b.HasOne("Entities.Contracts.Class", "Class") + .WithMany() + .HasForeignKey("ClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Exam", "Exam") .WithMany("Submissions") - .HasForeignKey("AssignmentId") + .HasForeignKey("ExamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("Entities.Contracts.User", "Grader") .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("GraderId"); b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") + .WithMany("StudentSubmissions") .HasForeignKey("StudentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Assignment"); + b.Navigation("Class"); + + b.Navigation("Exam"); b.Navigation("Grader"); @@ -1145,9 +1165,9 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamQuestion") .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") + .HasForeignKey("ExamQuestionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1163,13 +1183,22 @@ namespace TechHelper.Server.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("AssignmentQuestion"); + b.Navigation("ExamQuestion"); b.Navigation("Student"); b.Navigation("Submission"); }); + modelBuilder.Entity("Entities.Contracts.User", b => + { + b.HasOne("Entities.Contracts.Subject", "TeachSubject") + .WithMany("SubjectTeachers") + .HasForeignKey("TeachSubjectId"); + + b.Navigation("TeachSubject"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) @@ -1221,29 +1250,35 @@ namespace TechHelper.Server.Migrations .IsRequired(); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => { - b.Navigation("AssignmentAttachments"); + b.Navigation("ClassUsers"); + }); - b.Navigation("AssignmentClasses"); + modelBuilder.Entity("Entities.Contracts.Exam", b => + { + b.Navigation("ExamAttachments"); b.Navigation("Submissions"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { - b.Navigation("ChildrenAssignmentQuestion"); + b.Navigation("ChildExamQuestions"); + + b.Navigation("Exam"); b.Navigation("SubmissionDetails"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { - b.Navigation("AssignmentClasses"); + b.Navigation("Exams"); + }); - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.Navigation("Classes"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1262,7 +1297,7 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.Navigation("AssignmentQuestions"); + b.Navigation("ExamQuestions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -1270,6 +1305,25 @@ namespace TechHelper.Server.Migrations b.Navigation("Questions"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Navigation("Grades"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Navigation("QuestionTypes"); + + b.Navigation("Questions"); + + b.Navigation("SubjectTeachers"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Navigation("SubmissionDetails"); @@ -1282,19 +1336,15 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.User", b => { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); + b.Navigation("CreatedExams"); b.Navigation("GradedSubmissions"); + b.Navigation("StudentSubmissions"); + b.Navigation("SubmissionDetails"); - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); + b.Navigation("UserInjoinedClass"); }); #pragma warning restore 612, 618 } diff --git a/TechHelper.Server/Migrations/20250626073834_init.cs b/TechHelper.Server/Migrations/20250929035019_init.cs similarity index 77% rename from TechHelper.Server/Migrations/20250626073834_init.cs rename to TechHelper.Server/Migrations/20250929035019_init.cs index eebadc0..08d194f 100644 --- a/TechHelper.Server/Migrations/20250626073834_init.cs +++ b/TechHelper.Server/Migrations/20250929035019_init.cs @@ -4,8 +4,6 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - namespace TechHelper.Server.Migrations { /// @@ -36,44 +34,18 @@ namespace TechHelper.Server.Migrations .Annotation("MySql:CharSet", "utf8mb4"); migrationBuilder.CreateTable( - name: "AspNetUsers", + name: "exam_type", columns: table => new { - Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - RefreshToken = table.Column(type: "longtext", nullable: true) + id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + name = table.Column(type: "varchar(20)", maxLength: 20, nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), - RefreshTokenExpiryTime = table.Column(type: "datetime(6)", nullable: true), - Address = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - DisplayName = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - deleted = table.Column(type: "tinyint(1)", nullable: false), - UserName = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - NormalizedUserName = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - Email = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - NormalizedEmail = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - EmailConfirmed = table.Column(type: "tinyint(1)", nullable: false), - PasswordHash = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - SecurityStamp = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - ConcurrencyStamp = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - PhoneNumber = table.Column(type: "longtext", nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - PhoneNumberConfirmed = table.Column(type: "tinyint(1)", nullable: false), - TwoFactorEnabled = table.Column(type: "tinyint(1)", nullable: false), - LockoutEnd = table.Column(type: "datetime(6)", nullable: true), - LockoutEnabled = table.Column(type: "tinyint(1)", nullable: false), - AccessFailedCount = table.Column(type: "int", nullable: false) + description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") }, constraints: table => { - table.PrimaryKey("PK_AspNetUsers", x => x.Id); + table.PrimaryKey("PK_exam_type", x => x.id); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -91,6 +63,39 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "schools", + columns: table => new + { + id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + school_name = table.Column(type: "varchar(50)", maxLength: 50, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + address = table.Column(type: "varchar(100)", maxLength: 100, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + create_time = table.Column(type: "datetime(6)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_schools", x => x.id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "subjects", + columns: table => new + { + id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + name = table.Column(type: "varchar(20)", maxLength: 20, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_subjects", x => x.id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "textbook", columns: table => new @@ -132,6 +137,125 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "grades", + columns: table => new + { + grade_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + school_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + grade_name = table.Column(type: "varchar(20)", maxLength: 20, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + grade_level = table.Column(type: "tinyint unsigned", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_grades", x => x.grade_id); + table.ForeignKey( + name: "FK_grades_schools_school_id", + column: x => x.school_id, + principalTable: "schools", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + RefreshToken = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + RefreshTokenExpiryTime = table.Column(type: "datetime(6)", nullable: true), + HomeAddress = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + DisplayName = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Role = table.Column(type: "int", nullable: true), + TeachSubjectId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + deleted = table.Column(type: "tinyint(1)", nullable: false), + UserName = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + NormalizedUserName = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + Email = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + NormalizedEmail = table.Column(type: "varchar(256)", maxLength: 256, nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + EmailConfirmed = table.Column(type: "tinyint(1)", nullable: false), + PasswordHash = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + SecurityStamp = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + ConcurrencyStamp = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + PhoneNumber = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + PhoneNumberConfirmed = table.Column(type: "tinyint(1)", nullable: false), + TwoFactorEnabled = table.Column(type: "tinyint(1)", nullable: false), + LockoutEnd = table.Column(type: "datetime(6)", nullable: true), + LockoutEnabled = table.Column(type: "tinyint(1)", nullable: false), + AccessFailedCount = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUsers_subjects_TeachSubjectId", + column: x => x.TeachSubjectId, + principalTable: "subjects", + principalColumn: "id"); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "question_types", + columns: table => new + { + id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + name = table.Column(type: "varchar(20)", maxLength: 20, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + subject_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + score_rule = table.Column(type: "varchar(20)", maxLength: 20, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_question_types", x => x.id); + table.ForeignKey( + name: "FK_question_types_subjects_subject_id", + column: x => x.subject_id, + principalTable: "subjects", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "lesson", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Title = table.Column(type: "varchar(255)", maxLength: 255, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + TextbookID = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") + }, + constraints: table => + { + table.PrimaryKey("PK_lesson", x => x.Id); + table.ForeignKey( + name: "FK_lesson_textbook_TextbookID", + column: x => x.TextbookID, + principalTable: "textbook", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "AspNetUserClaims", columns: table => new @@ -233,102 +357,29 @@ namespace TechHelper.Server.Migrations name: "classes", columns: table => new { - id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - grade = table.Column(type: "tinyint unsigned", nullable: false), - @class = table.Column(name: "class", type: "tinyint unsigned", nullable: false), - description = table.Column(type: "longtext", nullable: true) + class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + grade_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + index = table.Column(type: "tinyint unsigned", nullable: false), + class_name = table.Column(type: "varchar(30)", maxLength: 30, nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), head_teacher_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - created_at = table.Column(type: "datetime(6)", nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - updated_at = table.Column(type: "datetime(6)", nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.ComputedColumn), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) + created_at = table.Column(type: "datetime(6)", nullable: false), + updated_at = table.Column(type: "datetime(6)", nullable: false), + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { - table.PrimaryKey("PK_classes", x => x.id); + table.PrimaryKey("PK_classes", x => x.class_id); table.ForeignKey( name: "FK_classes_AspNetUsers_head_teacher_id", column: x => x.head_teacher_id, principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.CreateTable( - name: "lesson", - columns: table => new - { - Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - Title = table.Column(type: "varchar(255)", maxLength: 255, nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - Description = table.Column(type: "longtext", nullable: false) - .Annotation("MySql:CharSet", "utf8mb4"), - TextbookID = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci") - }, - constraints: table => - { - table.PrimaryKey("PK_lesson", x => x.Id); + principalColumn: "Id"); table.ForeignKey( - name: "FK_lesson_textbook_TextbookID", - column: x => x.TextbookID, - principalTable: "textbook", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.CreateTable( - name: "class_student", - columns: table => new - { - class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - student_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - enrollment_date = table.Column(type: "datetime(6)", nullable: false), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) - }, - constraints: table => - { - table.PrimaryKey("PK_class_student", x => new { x.class_id, x.student_id }); - table.ForeignKey( - name: "FK_class_student_AspNetUsers_student_id", - column: x => x.student_id, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_class_student_classes_class_id", - column: x => x.class_id, - principalTable: "classes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - - migrationBuilder.CreateTable( - name: "class_teachers", - columns: table => new - { - class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - teacher_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - subject_taught = table.Column(type: "tinyint unsigned", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_class_teachers", x => new { x.class_id, x.teacher_id }); - table.ForeignKey( - name: "FK_class_teachers_AspNetUsers_teacher_id", - column: x => x.teacher_id, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_class_teachers_classes_class_id", - column: x => x.class_id, - principalTable: "classes", - principalColumn: "id", + name: "FK_classes_grades_grade_id", + column: x => x.grade_id, + principalTable: "grades", + principalColumn: "grade_id", onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -375,49 +426,77 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( + name: "class_user", + columns: table => new + { + class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + student_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + enrollment_date = table.Column(type: "datetime(6)", nullable: false), + deleted = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_class_user", x => new { x.class_id, x.student_id }); + table.ForeignKey( + name: "FK_class_user_AspNetUsers_student_id", + column: x => x.student_id, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_class_user_classes_class_id", + column: x => x.class_id, + principalTable: "classes", + principalColumn: "class_id", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + migrationBuilder.CreateTable( name: "questions", columns: table => new { id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - question_text = table.Column(type: "longtext", maxLength: 65535, nullable: false) + title = table.Column(type: "longtext", maxLength: 65535, nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), - correct_answer = table.Column(type: "longtext", maxLength: 65535, nullable: true) - .Annotation("MySql:CharSet", "utf8mb4"), - question_type = table.Column(type: "tinyint unsigned", maxLength: 20, nullable: false), - difficulty_level = table.Column(type: "tinyint unsigned", maxLength: 10, nullable: false), - subject_area = table.Column(type: "tinyint unsigned", maxLength: 100, nullable: false), - options = table.Column(type: "longtext", nullable: true) + answer = table.Column(type: "longtext", maxLength: 65535, nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), + type = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + subject_area = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), key_point = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), lesson = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - created_by = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - created_at = table.Column(type: "datetime(6)", nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - updated_at = table.Column(type: "datetime(6)", rowVersion: true, nullable: false), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) + options = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + created_at = table.Column(type: "datetime(6)", nullable: false), + updated_at = table.Column(type: "datetime(6)", nullable: false), + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { table.PrimaryKey("PK_questions", x => x.id); - table.ForeignKey( - name: "FK_questions_AspNetUsers_created_by", - column: x => x.created_by, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); table.ForeignKey( name: "FK_questions_key_point_key_point", column: x => x.key_point, principalTable: "key_point", - principalColumn: "Id", - onDelete: ReferentialAction.SetNull); + principalColumn: "Id"); table.ForeignKey( name: "FK_questions_lesson_lesson", column: x => x.lesson, principalTable: "lesson", - principalColumn: "Id", - onDelete: ReferentialAction.SetNull); + principalColumn: "Id"); + table.ForeignKey( + name: "FK_questions_question_types_type", + column: x => x.type, + principalTable: "question_types", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_questions_subjects_subject_area", + column: x => x.subject_area, + principalTable: "subjects", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -426,16 +505,18 @@ namespace TechHelper.Server.Migrations columns: table => new { id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - question_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), title = table.Column(type: "varchar(1024)", maxLength: 1024, nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), + question_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), description = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), question_number = table.Column(type: "tinyint unsigned", nullable: false), + sequence = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), parent_question_group_id = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), - group_state = table.Column(type: "tinyint unsigned", nullable: false), + QuestionTypeId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), created_at = table.Column(type: "datetime(6)", nullable: false), score = table.Column(type: "float", nullable: true), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { @@ -444,19 +525,23 @@ namespace TechHelper.Server.Migrations name: "FK_assignment_questions_QuestionContexts_description", column: x => x.description, principalTable: "QuestionContexts", - principalColumn: "Id", - onDelete: ReferentialAction.SetNull); + principalColumn: "Id"); table.ForeignKey( name: "FK_assignment_questions_assignment_questions_parent_question_gr~", column: x => x.parent_question_group_id, principalTable: "assignment_questions", principalColumn: "id"); + table.ForeignKey( + name: "FK_assignment_questions_question_types_QuestionTypeId", + column: x => x.QuestionTypeId, + principalTable: "question_types", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_assignment_questions_questions_question_id", column: x => x.question_id, principalTable: "questions", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); + principalColumn: "id"); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -469,25 +554,22 @@ namespace TechHelper.Server.Migrations .Annotation("MySql:CharSet", "utf8mb4"), description = table.Column(type: "longtext", nullable: false) .Annotation("MySql:CharSet", "utf8mb4"), - subject_area = table.Column(type: "tinyint unsigned", nullable: false), + subject_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), exam_struct_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + exam_type_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + created_by = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), due_date = table.Column(type: "datetime(6)", nullable: false), total_points = table.Column(type: "tinyint unsigned", nullable: false), score = table.Column(type: "float", nullable: false), - created_by = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), created_at = table.Column(type: "datetime(6)", nullable: false), updated_at = table.Column(type: "datetime(6)", nullable: false), - deleted = table.Column(type: "tinyint(1)", nullable: false), - UserId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci") + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { table.PrimaryKey("PK_assignments", x => x.id); - table.ForeignKey( - name: "FK_assignments_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id"); table.ForeignKey( name: "FK_assignments_AspNetUsers_created_by", column: x => x.created_by, @@ -500,6 +582,18 @@ namespace TechHelper.Server.Migrations principalTable: "assignment_questions", principalColumn: "id", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_assignments_exam_type_exam_type_id", + column: x => x.exam_type_id, + principalTable: "exam_type", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_assignments_subjects_subject_id", + column: x => x.subject_id, + principalTable: "subjects", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -528,49 +622,26 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); - migrationBuilder.CreateTable( - name: "assignment_class", - columns: table => new - { - assignment_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - assigned_at = table.Column(type: "datetime(6)", nullable: false), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) - }, - constraints: table => - { - table.PrimaryKey("PK_assignment_class", x => new { x.assignment_id, x.class_id }); - table.ForeignKey( - name: "FK_assignment_class_assignments_assignment_id", - column: x => x.assignment_id, - principalTable: "assignments", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_assignment_class_classes_class_id", - column: x => x.class_id, - principalTable: "classes", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }) - .Annotation("MySql:CharSet", "utf8mb4"); - migrationBuilder.CreateTable( name: "submissions", columns: table => new { id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - assignment_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + exam_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), student_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), - attempt_number = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + graded_by = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + class_id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + attempt_number = table.Column(type: "tinyint unsigned", nullable: false), submission_time = table.Column(type: "datetime(6)", nullable: false), - overall_grade = table.Column(type: "float", precision: 5, scale: 2, nullable: true), + overall_grade = table.Column(type: "float", nullable: false), overall_feedback = table.Column(type: "longtext", nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), - graded_by = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), graded_at = table.Column(type: "datetime(6)", nullable: true), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false), - status = table.Column(type: "int", maxLength: 15, nullable: false) + TotalQuesNum = table.Column(type: "tinyint unsigned", nullable: false), + ErrorQuesNum = table.Column(type: "tinyint unsigned", nullable: false), + TotalScore = table.Column(type: "tinyint unsigned", nullable: false), + status = table.Column(type: "int", nullable: false), + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { @@ -579,20 +650,25 @@ namespace TechHelper.Server.Migrations name: "FK_submissions_AspNetUsers_graded_by", column: x => x.graded_by, principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.SetNull); + principalColumn: "Id"); table.ForeignKey( name: "FK_submissions_AspNetUsers_student_id", column: x => x.student_id, principalTable: "AspNetUsers", principalColumn: "Id", - onDelete: ReferentialAction.Restrict); + onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_submissions_assignments_assignment_id", - column: x => x.assignment_id, + name: "FK_submissions_assignments_exam_id", + column: x => x.exam_id, principalTable: "assignments", principalColumn: "id", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_submissions_classes_class_id", + column: x => x.class_id, + principalTable: "classes", + principalColumn: "class_id", + onDelete: ReferentialAction.Cascade); }) .Annotation("MySql:CharSet", "utf8mb4"); @@ -607,13 +683,12 @@ namespace TechHelper.Server.Migrations student_answer = table.Column(type: "longtext", nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), is_correct = table.Column(type: "tinyint(1)", nullable: true), - points_awarded = table.Column(type: "float", precision: 5, scale: 2, nullable: true), + points_awarded = table.Column(type: "float", nullable: true), teacher_feedback = table.Column(type: "longtext", nullable: true) .Annotation("MySql:CharSet", "utf8mb4"), - created_at = table.Column(type: "datetime(6)", nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - updated_at = table.Column(type: "datetime(6)", rowVersion: true, nullable: false), - deleted = table.Column(type: "tinyint(1)", nullable: false, defaultValue: false) + created_at = table.Column(type: "datetime(6)", nullable: false), + updated_at = table.Column(type: "datetime(6)", nullable: false), + deleted = table.Column(type: "tinyint(1)", nullable: false) }, constraints: table => { @@ -623,7 +698,7 @@ namespace TechHelper.Server.Migrations column: x => x.student_id, principalTable: "AspNetUsers", principalColumn: "Id", - onDelete: ReferentialAction.Restrict); + onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_submission_details_assignment_questions_assignment_question_~", column: x => x.assignment_question_id, @@ -639,16 +714,6 @@ namespace TechHelper.Server.Migrations }) .Annotation("MySql:CharSet", "utf8mb4"); - migrationBuilder.InsertData( - table: "AspNetRoles", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { new Guid("3cfe35e8-73d5-4170-9856-f1d078554822"), null, "Student", "STUDENT" }, - { new Guid("754c4967-6af2-4a81-b970-1e90a3a269b3"), null, "Teacher", "TEACHER" }, - { new Guid("8546457c-185c-4b79-bece-bc21e41d02e7"), null, "Administrator", "ADMINISTRATOR" } - }); - migrationBuilder.CreateIndex( name: "IX_AspNetRoleClaims_RoleId", table: "AspNetRoleClaims", @@ -680,6 +745,11 @@ namespace TechHelper.Server.Migrations table: "AspNetUsers", column: "NormalizedEmail"); + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_TeachSubjectId", + table: "AspNetUsers", + column: "TeachSubjectId"); + migrationBuilder.CreateIndex( name: "UserNameIndex", table: "AspNetUsers", @@ -691,11 +761,6 @@ namespace TechHelper.Server.Migrations table: "assignment_attachments", column: "assignment_id"); - migrationBuilder.CreateIndex( - name: "IX_assignment_class_class_id", - table: "assignment_class", - column: "class_id"); - migrationBuilder.CreateIndex( name: "IX_assignment_questions_description", table: "assignment_questions", @@ -711,6 +776,11 @@ namespace TechHelper.Server.Migrations table: "assignment_questions", column: "question_id"); + migrationBuilder.CreateIndex( + name: "IX_assignment_questions_QuestionTypeId", + table: "assignment_questions", + column: "QuestionTypeId"); + migrationBuilder.CreateIndex( name: "IX_assignments_created_by", table: "assignments", @@ -723,25 +793,35 @@ namespace TechHelper.Server.Migrations unique: true); migrationBuilder.CreateIndex( - name: "IX_assignments_UserId", + name: "IX_assignments_exam_type_id", table: "assignments", - column: "UserId"); + column: "exam_type_id"); migrationBuilder.CreateIndex( - name: "IX_class_student_student_id", - table: "class_student", + name: "IX_assignments_subject_id", + table: "assignments", + column: "subject_id"); + + migrationBuilder.CreateIndex( + name: "IX_class_user_student_id", + table: "class_user", column: "student_id"); migrationBuilder.CreateIndex( - name: "IX_class_teachers_teacher_id", - table: "class_teachers", - column: "teacher_id"); + name: "IX_classes_grade_id", + table: "classes", + column: "grade_id"); migrationBuilder.CreateIndex( name: "IX_classes_head_teacher_id", table: "classes", column: "head_teacher_id"); + migrationBuilder.CreateIndex( + name: "IX_grades_school_id", + table: "grades", + column: "school_id"); + migrationBuilder.CreateIndex( name: "IX_key_point_LessonID", table: "key_point", @@ -758,9 +838,9 @@ namespace TechHelper.Server.Migrations column: "LessonID"); migrationBuilder.CreateIndex( - name: "IX_questions_created_by", - table: "questions", - column: "created_by"); + name: "IX_question_types_subject_id", + table: "question_types", + column: "subject_id"); migrationBuilder.CreateIndex( name: "IX_questions_key_point", @@ -773,10 +853,14 @@ namespace TechHelper.Server.Migrations column: "lesson"); migrationBuilder.CreateIndex( - name: "IX_questions_question_text", + name: "IX_questions_subject_area", table: "questions", - column: "question_text") - .Annotation("MySql:IndexPrefixLength", new[] { 20 }); + column: "subject_area"); + + migrationBuilder.CreateIndex( + name: "IX_questions_type", + table: "questions", + column: "type"); migrationBuilder.CreateIndex( name: "IX_submission_details_assignment_question_id", @@ -794,9 +878,14 @@ namespace TechHelper.Server.Migrations column: "submission_id"); migrationBuilder.CreateIndex( - name: "IX_submissions_assignment_id", + name: "IX_submissions_class_id", table: "submissions", - column: "assignment_id"); + column: "class_id"); + + migrationBuilder.CreateIndex( + name: "IX_submissions_exam_id", + table: "submissions", + column: "exam_id"); migrationBuilder.CreateIndex( name: "IX_submissions_graded_by", @@ -831,13 +920,7 @@ namespace TechHelper.Server.Migrations name: "assignment_attachments"); migrationBuilder.DropTable( - name: "assignment_class"); - - migrationBuilder.DropTable( - name: "class_student"); - - migrationBuilder.DropTable( - name: "class_teachers"); + name: "class_user"); migrationBuilder.DropTable( name: "lesson_question"); @@ -848,18 +931,27 @@ namespace TechHelper.Server.Migrations migrationBuilder.DropTable( name: "AspNetRoles"); - migrationBuilder.DropTable( - name: "classes"); - migrationBuilder.DropTable( name: "submissions"); migrationBuilder.DropTable( name: "assignments"); + migrationBuilder.DropTable( + name: "classes"); + migrationBuilder.DropTable( name: "assignment_questions"); + migrationBuilder.DropTable( + name: "exam_type"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + + migrationBuilder.DropTable( + name: "grades"); + migrationBuilder.DropTable( name: "QuestionContexts"); @@ -867,14 +959,20 @@ namespace TechHelper.Server.Migrations name: "questions"); migrationBuilder.DropTable( - name: "AspNetUsers"); + name: "schools"); migrationBuilder.DropTable( name: "key_point"); + migrationBuilder.DropTable( + name: "question_types"); + migrationBuilder.DropTable( name: "lesson"); + migrationBuilder.DropTable( + name: "subjects"); + migrationBuilder.DropTable( name: "textbook"); } diff --git a/TechHelper.Server/Migrations/20250904102023_submission_up_3.Designer.cs b/TechHelper.Server/Migrations/20250929093304_temp_1.Designer.cs similarity index 72% rename from TechHelper.Server/Migrations/20250904102023_submission_up_3.Designer.cs rename to TechHelper.Server/Migrations/20250929093304_temp_1.Designer.cs index 46c6f6c..6eb521d 100644 --- a/TechHelper.Server/Migrations/20250904102023_submission_up_3.Designer.cs +++ b/TechHelper.Server/Migrations/20250929093304_temp_1.Designer.cs @@ -12,8 +12,8 @@ using TechHelper.Context; namespace TechHelper.Server.Migrations { [DbContext(typeof(ApplicationContext))] - [Migration("20250904102023_submission_up_3")] - partial class submission_up_3 + [Migration("20250929093304_temp_1")] + partial class temp_1 { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -21,11 +21,87 @@ namespace TechHelper.Server.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("class_id"); + + b.Property("ClassName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("class_name"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("created_at"); + + b.Property("GradeId") + .HasColumnType("char(36)") + .HasColumnName("grade_id"); + + b.Property("HeadTeacherId") + .HasColumnType("char(36)") + .HasColumnName("head_teacher_id"); + + b.Property("Index") + .HasColumnType("tinyint unsigned") + .HasColumnName("index"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("updated_at"); + + b.HasKey("Id"); + + b.HasIndex("GradeId"); + + b.HasIndex("HeadTeacherId"); + + b.ToTable("classes"); + }); + + modelBuilder.Entity("Entities.Contracts.ClassUser", b => + { + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id") + .HasColumnOrder(0); + + b.Property("UserId") + .HasColumnType("char(36)") + .HasColumnName("student_id") + .HasColumnOrder(1); + + b.Property("EnrollmentDate") + .HasColumnType("datetime(6)") + .HasColumnName("enrollment_date"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.HasKey("ClassId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("class_user"); + }); + + modelBuilder.Entity("Entities.Contracts.Exam", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -53,8 +129,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("exam_struct_id"); - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); + b.Property("ExamTypeId") + .HasColumnType("char(36)") + .HasColumnName("exam_type_id"); b.Property("IsDeleted") .HasColumnType("tinyint(1)") @@ -62,15 +139,16 @@ namespace TechHelper.Server.Migrations b.Property("Name") .IsRequired() - .HasColumnType("longtext"); + .HasColumnType("longtext") + .HasColumnName("name"); b.Property("Score") .HasColumnType("float") .HasColumnName("score"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); b.Property("Title") .IsRequired() @@ -86,9 +164,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("datetime(6)") .HasColumnName("updated_at"); - b.Property("UserId") - .HasColumnType("char(36)"); - b.HasKey("Id"); b.HasIndex("CreatorId"); @@ -96,21 +171,23 @@ namespace TechHelper.Server.Migrations b.HasIndex("ExamStructId") .IsUnique(); - b.HasIndex("UserId"); + b.HasIndex("ExamTypeId"); - b.ToTable("assignments", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("exams"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") + b.Property("ExamId") .HasColumnType("char(36)") - .HasColumnName("assignment_id"); + .HasColumnName("exam_id"); b.Property("FileName") .IsRequired() @@ -134,65 +211,35 @@ namespace TechHelper.Server.Migrations b.HasKey("Id"); - b.HasIndex("AssignmentId"); + b.HasIndex("ExamId"); - b.ToTable("assignment_attachments"); + b.ToTable("exam_attachments"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)"); - b.Property("CreatedAt") .HasColumnType("datetime(6)") .HasColumnName("created_at"); + b.Property("ExamStructType") + .HasColumnType("tinyint unsigned") + .HasColumnName("exam_struct_type"); + b.Property("Index") .HasColumnType("tinyint unsigned") .HasColumnName("question_number"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); - b.Property("ParentAssignmentQuestionId") + b.Property("ParentExamQuestionId") .HasColumnType("char(36)") .HasColumnName("parent_question_group_id"); @@ -204,6 +251,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("question_id"); + b.Property("QuestionTypeId") + .HasColumnType("char(36)"); + b.Property("Score") .HasColumnType("float") .HasColumnName("score"); @@ -213,148 +263,73 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("sequence"); - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - b.Property("Title") .HasMaxLength(1024) .HasColumnType("varchar(1024)") .HasColumnName("title"); - b.Property("Type") - .HasColumnType("tinyint unsigned"); - b.HasKey("Id"); - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); + b.HasIndex("ParentExamQuestionId"); b.HasIndex("QuestionContextId"); b.HasIndex("QuestionId"); - b.ToTable("assignment_questions", (string)null); + b.HasIndex("QuestionTypeId"); + + b.ToTable("exam_questions"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - b.Property("Description") + .IsRequired() .HasColumnType("longtext") .HasColumnName("description"); - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); b.HasKey("Id"); - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); + b.ToTable("exam_type"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => + modelBuilder.Entity("Entities.Contracts.Grade", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") - .HasColumnName("id"); + .HasColumnName("grade_id"); - b.Property("Area") - .HasColumnType("tinyint unsigned"); + b.Property("GradeLevel") + .HasColumnType("tinyint unsigned") + .HasColumnName("grade_level"); - b.Property("Info") + b.Property("GradeName") .IsRequired() - .HasColumnType("longtext"); + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("grade_name"); + + b.Property("SchoolId") + .HasColumnType("char(36)") + .HasColumnName("school_id"); b.HasKey("Id"); - b.ToTable("global"); + b.HasIndex("SchoolId"); + + b.ToTable("grades"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -434,28 +409,14 @@ namespace TechHelper.Server.Migrations b.Property("Answer") .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("correct_answer"); + .HasColumnName("answer"); b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("KeyPointId") @@ -470,44 +431,35 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("options"); - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); + b.Property("QuestioTypeId") + .HasColumnType("char(36)") + .HasColumnName("type"); - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") + b.Property("SubjectId") + .HasColumnType("char(36)") .HasColumnName("subject_area"); b.Property("Title") .IsRequired() .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); + .HasColumnName("title"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("CreatorId"); - b.HasIndex("KeyPointId"); b.HasIndex("LessonId"); - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); + b.HasIndex("QuestioTypeId"); - b.ToTable("questions", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("questions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -525,6 +477,92 @@ namespace TechHelper.Server.Migrations b.ToTable("QuestionContexts"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.Property("ScoreRule") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("score_rule"); + + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("question_types"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("address"); + + b.Property("CreateTime") + .HasColumnType("datetime(6)") + .HasColumnName("create_time"); + + b.Property("SchoolName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("school_name"); + + b.HasKey("Id"); + + b.ToTable("schools"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.HasKey("Id"); + + b.ToTable("subjects"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Property("Id") @@ -532,17 +570,21 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - b.Property("AttemptNumber") .HasColumnType("tinyint unsigned") .HasColumnName("attempt_number"); + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id"); + b.Property("ErrorQuesNum") .HasColumnType("tinyint unsigned"); + b.Property("ExamId") + .HasColumnType("char(36)") + .HasColumnName("exam_id"); + b.Property("GradedAt") .HasColumnType("datetime(6)") .HasColumnName("graded_at"); @@ -552,9 +594,7 @@ namespace TechHelper.Server.Migrations .HasColumnName("graded_by"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("OverallFeedback") @@ -562,12 +602,10 @@ namespace TechHelper.Server.Migrations .HasColumnName("overall_feedback"); b.Property("OverallGrade") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("overall_grade"); b.Property("Status") - .HasMaxLength(15) .HasColumnType("int") .HasColumnName("status"); @@ -582,18 +620,20 @@ namespace TechHelper.Server.Migrations b.Property("TotalQuesNum") .HasColumnType("tinyint unsigned"); - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); + b.Property("TotalScore") + .HasColumnType("float"); b.HasKey("Id"); - b.HasIndex("AssignmentId"); + b.HasIndex("ClassId"); + + b.HasIndex("ExamId"); b.HasIndex("GraderId"); b.HasIndex("StudentId"); - b.ToTable("submissions", (string)null); + b.ToTable("submissions"); }); modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => @@ -603,36 +643,26 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); + b.Property("ExamQuestionId") + .HasColumnType("char(36)") + .HasColumnName("exam_question_id"); b.Property("IsCorrect") .HasColumnType("tinyint(1)") .HasColumnName("is_correct"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("PointsAwarded") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("points_awarded"); - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - b.Property("StudentAnswer") .HasColumnType("longtext") .HasColumnName("student_answer"); @@ -650,20 +680,18 @@ namespace TechHelper.Server.Migrations .HasColumnName("teacher_feedback"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("AssignmentQuestionId"); + b.HasIndex("ExamQuestionId"); b.HasIndex("StudentId"); b.HasIndex("SubmissionId"); - b.ToTable("submission_details", (string)null); + b.ToTable("submission_details"); }); modelBuilder.Entity("Entities.Contracts.Textbook", b => @@ -699,9 +727,6 @@ namespace TechHelper.Server.Migrations b.Property("AccessFailedCount") .HasColumnType("int"); - b.Property("Address") - .HasColumnType("longtext"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("longtext"); @@ -716,6 +741,9 @@ namespace TechHelper.Server.Migrations b.Property("EmailConfirmed") .HasColumnType("tinyint(1)"); + b.Property("HomeAddress") + .HasColumnType("longtext"); + b.Property("IsDeleted") .HasColumnType("tinyint(1)") .HasColumnName("deleted"); @@ -749,11 +777,14 @@ namespace TechHelper.Server.Migrations b.Property("RefreshTokenExpiryTime") .HasColumnType("datetime(6)"); + b.Property("Role") + .HasColumnType("int"); + b.Property("SecurityStamp") .HasColumnType("longtext"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); + b.Property("TeachSubjectId") + .HasColumnType("char(36)"); b.Property("TwoFactorEnabled") .HasColumnType("tinyint(1)"); @@ -771,6 +802,8 @@ namespace TechHelper.Server.Migrations .IsUnique() .HasDatabaseName("UserNameIndex"); + b.HasIndex("TeachSubjectId"); + b.ToTable("AspNetUsers", (string)null); }); @@ -799,26 +832,6 @@ namespace TechHelper.Server.Migrations .HasDatabaseName("RoleNameIndex"); b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("c758a0d2-faea-4cf1-aa14-d162f3d0a1e9"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("ba4054d5-2f8a-4c7f-bd56-0fc864720c7d"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("388fdb1d-8cd5-4e8f-b49c-06dbee60527b"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => @@ -924,136 +937,126 @@ namespace TechHelper.Server.Migrations b.ToTable("AspNetUserTokens", (string)null); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - modelBuilder.Entity("Entities.Contracts.Class", b => { + b.HasOne("Entities.Contracts.Grade", "Grade") + .WithMany("Classes") + .HasForeignKey("GradeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Entities.Contracts.User", "HeadTeacher") .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); + .HasForeignKey("HeadTeacherId"); + + b.Navigation("Grade"); b.Navigation("HeadTeacher"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => + modelBuilder.Entity("Entities.Contracts.ClassUser", b => { b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") + .WithMany("ClassUsers") .HasForeignKey("ClassId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) + b.HasOne("Entities.Contracts.User", "User") + .WithMany("UserInjoinedClass") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Class"); - b.Navigation("Student"); + b.Navigation("User"); }); - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => + modelBuilder.Entity("Entities.Contracts.Exam", b => { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") + b.HasOne("Entities.Contracts.User", "Creator") + .WithMany("CreatedExams") + .HasForeignKey("CreatorId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamStruct") + .WithOne("Exam") + .HasForeignKey("Entities.Contracts.Exam", "ExamStructId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Class"); + b.HasOne("Entities.Contracts.ExamType", "ExamType") + .WithMany("Exams") + .HasForeignKey("ExamTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.Navigation("Teacher"); + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("ExamStruct"); + + b.Navigation("ExamType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => + { + b.HasOne("Entities.Contracts.Exam", "Exam") + .WithMany("ExamAttachments") + .HasForeignKey("ExamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Exam"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => + { + b.HasOne("Entities.Contracts.ExamQuestion", "ParentExamQuestion") + .WithMany("ChildExamQuestions") + .HasForeignKey("ParentExamQuestionId"); + + b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") + .WithMany("Questions") + .HasForeignKey("QuestionContextId"); + + b.HasOne("Entities.Contracts.Question", "Question") + .WithMany("ExamQuestions") + .HasForeignKey("QuestionId"); + + b.HasOne("Entities.Contracts.QuestionType", "Type") + .WithMany() + .HasForeignKey("QuestionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParentExamQuestion"); + + b.Navigation("Question"); + + b.Navigation("QuestionContext"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.HasOne("Entities.Contracts.School", "School") + .WithMany("Grades") + .HasForeignKey("SchoolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("School"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1091,49 +1094,73 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("KeyPointId"); b.HasOne("Entities.Contracts.Lesson", "Lesson") .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("LessonId"); - b.Navigation("Creator"); + b.HasOne("Entities.Contracts.QuestionType", "QuestionType") + .WithMany("Questions") + .HasForeignKey("QuestioTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("Questions") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("KeyPoint"); b.Navigation("Lesson"); + + b.Navigation("QuestionType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("QuestionTypes") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => { - b.HasOne("Entities.Contracts.Assignment", "Assignment") + b.HasOne("Entities.Contracts.Class", "Class") + .WithMany() + .HasForeignKey("ClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Exam", "Exam") .WithMany("Submissions") - .HasForeignKey("AssignmentId") + .HasForeignKey("ExamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("Entities.Contracts.User", "Grader") .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("GraderId"); b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") + .WithMany("StudentSubmissions") .HasForeignKey("StudentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Assignment"); + b.Navigation("Class"); + + b.Navigation("Exam"); b.Navigation("Grader"); @@ -1142,9 +1169,9 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamQuestion") .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") + .HasForeignKey("ExamQuestionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1160,13 +1187,22 @@ namespace TechHelper.Server.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("AssignmentQuestion"); + b.Navigation("ExamQuestion"); b.Navigation("Student"); b.Navigation("Submission"); }); + modelBuilder.Entity("Entities.Contracts.User", b => + { + b.HasOne("Entities.Contracts.Subject", "TeachSubject") + .WithMany("SubjectTeachers") + .HasForeignKey("TeachSubjectId"); + + b.Navigation("TeachSubject"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) @@ -1218,29 +1254,35 @@ namespace TechHelper.Server.Migrations .IsRequired(); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => { - b.Navigation("AssignmentAttachments"); + b.Navigation("ClassUsers"); + }); - b.Navigation("AssignmentClasses"); + modelBuilder.Entity("Entities.Contracts.Exam", b => + { + b.Navigation("ExamAttachments"); b.Navigation("Submissions"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { - b.Navigation("ChildrenAssignmentQuestion"); + b.Navigation("ChildExamQuestions"); + + b.Navigation("Exam"); b.Navigation("SubmissionDetails"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { - b.Navigation("AssignmentClasses"); + b.Navigation("Exams"); + }); - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.Navigation("Classes"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1259,7 +1301,7 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.Navigation("AssignmentQuestions"); + b.Navigation("ExamQuestions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -1267,6 +1309,25 @@ namespace TechHelper.Server.Migrations b.Navigation("Questions"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Navigation("Grades"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Navigation("QuestionTypes"); + + b.Navigation("Questions"); + + b.Navigation("SubjectTeachers"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Navigation("SubmissionDetails"); @@ -1279,19 +1340,15 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.User", b => { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); + b.Navigation("CreatedExams"); b.Navigation("GradedSubmissions"); + b.Navigation("StudentSubmissions"); + b.Navigation("SubmissionDetails"); - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); + b.Navigation("UserInjoinedClass"); }); #pragma warning restore 612, 618 } diff --git a/TechHelper.Server/Migrations/20250929093304_temp_1.cs b/TechHelper.Server/Migrations/20250929093304_temp_1.cs new file mode 100644 index 0000000..21df1d7 --- /dev/null +++ b/TechHelper.Server/Migrations/20250929093304_temp_1.cs @@ -0,0 +1,501 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TechHelper.Server.Migrations +{ + /// + public partial class temp_1 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_assignment_attachments_assignments_assignment_id", + table: "assignment_attachments"); + + migrationBuilder.DropForeignKey( + name: "FK_assignment_questions_QuestionContexts_description", + table: "assignment_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_assignment_questions_assignment_questions_parent_question_gr~", + table: "assignment_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_assignment_questions_question_types_QuestionTypeId", + table: "assignment_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_assignment_questions_questions_question_id", + table: "assignment_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_assignments_AspNetUsers_created_by", + table: "assignments"); + + migrationBuilder.DropForeignKey( + name: "FK_assignments_assignment_questions_exam_struct_id", + table: "assignments"); + + migrationBuilder.DropForeignKey( + name: "FK_assignments_exam_type_exam_type_id", + table: "assignments"); + + migrationBuilder.DropForeignKey( + name: "FK_assignments_subjects_subject_id", + table: "assignments"); + + migrationBuilder.DropForeignKey( + name: "FK_submission_details_assignment_questions_assignment_question_~", + table: "submission_details"); + + migrationBuilder.DropForeignKey( + name: "FK_submissions_assignments_exam_id", + table: "submissions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_assignments", + table: "assignments"); + + migrationBuilder.DropPrimaryKey( + name: "PK_assignment_questions", + table: "assignment_questions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_assignment_attachments", + table: "assignment_attachments"); + + migrationBuilder.RenameTable( + name: "assignments", + newName: "exams"); + + migrationBuilder.RenameTable( + name: "assignment_questions", + newName: "exam_questions"); + + migrationBuilder.RenameTable( + name: "assignment_attachments", + newName: "exam_attachments"); + + migrationBuilder.RenameColumn( + name: "assignment_question_id", + table: "submission_details", + newName: "exam_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_submission_details_assignment_question_id", + table: "submission_details", + newName: "IX_submission_details_exam_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignments_subject_id", + table: "exams", + newName: "IX_exams_subject_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignments_exam_type_id", + table: "exams", + newName: "IX_exams_exam_type_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignments_exam_struct_id", + table: "exams", + newName: "IX_exams_exam_struct_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignments_created_by", + table: "exams", + newName: "IX_exams_created_by"); + + migrationBuilder.RenameIndex( + name: "IX_assignment_questions_QuestionTypeId", + table: "exam_questions", + newName: "IX_exam_questions_QuestionTypeId"); + + migrationBuilder.RenameIndex( + name: "IX_assignment_questions_question_id", + table: "exam_questions", + newName: "IX_exam_questions_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignment_questions_parent_question_group_id", + table: "exam_questions", + newName: "IX_exam_questions_parent_question_group_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignment_questions_description", + table: "exam_questions", + newName: "IX_exam_questions_description"); + + migrationBuilder.RenameColumn( + name: "assignment_id", + table: "exam_attachments", + newName: "exam_id"); + + migrationBuilder.RenameIndex( + name: "IX_assignment_attachments_assignment_id", + table: "exam_attachments", + newName: "IX_exam_attachments_exam_id"); + + migrationBuilder.AlterColumn( + name: "TotalScore", + table: "submissions", + type: "float", + nullable: false, + oldClrType: typeof(byte), + oldType: "tinyint unsigned"); + + migrationBuilder.AddColumn( + name: "exam_struct_type", + table: "exam_questions", + type: "tinyint unsigned", + nullable: false, + defaultValue: (byte)0); + + migrationBuilder.AddPrimaryKey( + name: "PK_exams", + table: "exams", + column: "id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_exam_questions", + table: "exam_questions", + column: "id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_exam_attachments", + table: "exam_attachments", + column: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_exam_attachments_exams_exam_id", + table: "exam_attachments", + column: "exam_id", + principalTable: "exams", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_exam_questions_QuestionContexts_description", + table: "exam_questions", + column: "description", + principalTable: "QuestionContexts", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_exam_questions_exam_questions_parent_question_group_id", + table: "exam_questions", + column: "parent_question_group_id", + principalTable: "exam_questions", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_exam_questions_question_types_QuestionTypeId", + table: "exam_questions", + column: "QuestionTypeId", + principalTable: "question_types", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_exam_questions_questions_question_id", + table: "exam_questions", + column: "question_id", + principalTable: "questions", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_exams_AspNetUsers_created_by", + table: "exams", + column: "created_by", + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_exams_exam_questions_exam_struct_id", + table: "exams", + column: "exam_struct_id", + principalTable: "exam_questions", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_exams_exam_type_exam_type_id", + table: "exams", + column: "exam_type_id", + principalTable: "exam_type", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_exams_subjects_subject_id", + table: "exams", + column: "subject_id", + principalTable: "subjects", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_submission_details_exam_questions_exam_question_id", + table: "submission_details", + column: "exam_question_id", + principalTable: "exam_questions", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_submissions_exams_exam_id", + table: "submissions", + column: "exam_id", + principalTable: "exams", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_exam_attachments_exams_exam_id", + table: "exam_attachments"); + + migrationBuilder.DropForeignKey( + name: "FK_exam_questions_QuestionContexts_description", + table: "exam_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_exam_questions_exam_questions_parent_question_group_id", + table: "exam_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_exam_questions_question_types_QuestionTypeId", + table: "exam_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_exam_questions_questions_question_id", + table: "exam_questions"); + + migrationBuilder.DropForeignKey( + name: "FK_exams_AspNetUsers_created_by", + table: "exams"); + + migrationBuilder.DropForeignKey( + name: "FK_exams_exam_questions_exam_struct_id", + table: "exams"); + + migrationBuilder.DropForeignKey( + name: "FK_exams_exam_type_exam_type_id", + table: "exams"); + + migrationBuilder.DropForeignKey( + name: "FK_exams_subjects_subject_id", + table: "exams"); + + migrationBuilder.DropForeignKey( + name: "FK_submission_details_exam_questions_exam_question_id", + table: "submission_details"); + + migrationBuilder.DropForeignKey( + name: "FK_submissions_exams_exam_id", + table: "submissions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_exams", + table: "exams"); + + migrationBuilder.DropPrimaryKey( + name: "PK_exam_questions", + table: "exam_questions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_exam_attachments", + table: "exam_attachments"); + + migrationBuilder.DropColumn( + name: "exam_struct_type", + table: "exam_questions"); + + migrationBuilder.RenameTable( + name: "exams", + newName: "assignments"); + + migrationBuilder.RenameTable( + name: "exam_questions", + newName: "assignment_questions"); + + migrationBuilder.RenameTable( + name: "exam_attachments", + newName: "assignment_attachments"); + + migrationBuilder.RenameColumn( + name: "exam_question_id", + table: "submission_details", + newName: "assignment_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_submission_details_exam_question_id", + table: "submission_details", + newName: "IX_submission_details_assignment_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_exams_subject_id", + table: "assignments", + newName: "IX_assignments_subject_id"); + + migrationBuilder.RenameIndex( + name: "IX_exams_exam_type_id", + table: "assignments", + newName: "IX_assignments_exam_type_id"); + + migrationBuilder.RenameIndex( + name: "IX_exams_exam_struct_id", + table: "assignments", + newName: "IX_assignments_exam_struct_id"); + + migrationBuilder.RenameIndex( + name: "IX_exams_created_by", + table: "assignments", + newName: "IX_assignments_created_by"); + + migrationBuilder.RenameIndex( + name: "IX_exam_questions_QuestionTypeId", + table: "assignment_questions", + newName: "IX_assignment_questions_QuestionTypeId"); + + migrationBuilder.RenameIndex( + name: "IX_exam_questions_question_id", + table: "assignment_questions", + newName: "IX_assignment_questions_question_id"); + + migrationBuilder.RenameIndex( + name: "IX_exam_questions_parent_question_group_id", + table: "assignment_questions", + newName: "IX_assignment_questions_parent_question_group_id"); + + migrationBuilder.RenameIndex( + name: "IX_exam_questions_description", + table: "assignment_questions", + newName: "IX_assignment_questions_description"); + + migrationBuilder.RenameColumn( + name: "exam_id", + table: "assignment_attachments", + newName: "assignment_id"); + + migrationBuilder.RenameIndex( + name: "IX_exam_attachments_exam_id", + table: "assignment_attachments", + newName: "IX_assignment_attachments_assignment_id"); + + migrationBuilder.AlterColumn( + name: "TotalScore", + table: "submissions", + type: "tinyint unsigned", + nullable: false, + oldClrType: typeof(float), + oldType: "float"); + + migrationBuilder.AddPrimaryKey( + name: "PK_assignments", + table: "assignments", + column: "id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_assignment_questions", + table: "assignment_questions", + column: "id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_assignment_attachments", + table: "assignment_attachments", + column: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_assignment_attachments_assignments_assignment_id", + table: "assignment_attachments", + column: "assignment_id", + principalTable: "assignments", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_assignment_questions_QuestionContexts_description", + table: "assignment_questions", + column: "description", + principalTable: "QuestionContexts", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_assignment_questions_assignment_questions_parent_question_gr~", + table: "assignment_questions", + column: "parent_question_group_id", + principalTable: "assignment_questions", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_assignment_questions_question_types_QuestionTypeId", + table: "assignment_questions", + column: "QuestionTypeId", + principalTable: "question_types", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_assignment_questions_questions_question_id", + table: "assignment_questions", + column: "question_id", + principalTable: "questions", + principalColumn: "id"); + + migrationBuilder.AddForeignKey( + name: "FK_assignments_AspNetUsers_created_by", + table: "assignments", + column: "created_by", + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_assignments_assignment_questions_exam_struct_id", + table: "assignments", + column: "exam_struct_id", + principalTable: "assignment_questions", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_assignments_exam_type_exam_type_id", + table: "assignments", + column: "exam_type_id", + principalTable: "exam_type", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_assignments_subjects_subject_id", + table: "assignments", + column: "subject_id", + principalTable: "subjects", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_submission_details_assignment_questions_assignment_question_~", + table: "submission_details", + column: "assignment_question_id", + principalTable: "assignment_questions", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_submissions_assignments_exam_id", + table: "submissions", + column: "exam_id", + principalTable: "assignments", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs b/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs index 3d19c48..232676a 100644 --- a/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs +++ b/TechHelper.Server/Migrations/ApplicationContextModelSnapshot.cs @@ -18,11 +18,87 @@ namespace TechHelper.Server.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("class_id"); + + b.Property("ClassName") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)") + .HasColumnName("class_name"); + + b.Property("CreatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("created_at"); + + b.Property("GradeId") + .HasColumnType("char(36)") + .HasColumnName("grade_id"); + + b.Property("HeadTeacherId") + .HasColumnType("char(36)") + .HasColumnName("head_teacher_id"); + + b.Property("Index") + .HasColumnType("tinyint unsigned") + .HasColumnName("index"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.Property("UpdatedAt") + .HasColumnType("datetime(6)") + .HasColumnName("updated_at"); + + b.HasKey("Id"); + + b.HasIndex("GradeId"); + + b.HasIndex("HeadTeacherId"); + + b.ToTable("classes"); + }); + + modelBuilder.Entity("Entities.Contracts.ClassUser", b => + { + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id") + .HasColumnOrder(0); + + b.Property("UserId") + .HasColumnType("char(36)") + .HasColumnName("student_id") + .HasColumnOrder(1); + + b.Property("EnrollmentDate") + .HasColumnType("datetime(6)") + .HasColumnName("enrollment_date"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("deleted"); + + b.HasKey("ClassId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("class_user"); + }); + + modelBuilder.Entity("Entities.Contracts.Exam", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -50,8 +126,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("exam_struct_id"); - b.Property("ExamType") - .HasColumnType("tinyint unsigned"); + b.Property("ExamTypeId") + .HasColumnType("char(36)") + .HasColumnName("exam_type_id"); b.Property("IsDeleted") .HasColumnType("tinyint(1)") @@ -59,15 +136,16 @@ namespace TechHelper.Server.Migrations b.Property("Name") .IsRequired() - .HasColumnType("longtext"); + .HasColumnType("longtext") + .HasColumnName("name"); b.Property("Score") .HasColumnType("float") .HasColumnName("score"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_area"); + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); b.Property("Title") .IsRequired() @@ -83,9 +161,6 @@ namespace TechHelper.Server.Migrations .HasColumnType("datetime(6)") .HasColumnName("updated_at"); - b.Property("UserId") - .HasColumnType("char(36)"); - b.HasKey("Id"); b.HasIndex("CreatorId"); @@ -93,21 +168,23 @@ namespace TechHelper.Server.Migrations b.HasIndex("ExamStructId") .IsUnique(); - b.HasIndex("UserId"); + b.HasIndex("ExamTypeId"); - b.ToTable("assignments", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("exams"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") + b.Property("ExamId") .HasColumnType("char(36)") - .HasColumnName("assignment_id"); + .HasColumnName("exam_id"); b.Property("FileName") .IsRequired() @@ -131,68 +208,35 @@ namespace TechHelper.Server.Migrations b.HasKey("Id"); - b.HasIndex("AssignmentId"); + b.HasIndex("ExamId"); - b.ToTable("assignment_attachments"); + b.ToTable("exam_attachments"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id") - .HasColumnOrder(0); - - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(1); - - b.Property("AssignedAt") - .HasColumnType("datetime(6)") - .HasColumnName("assigned_at"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("AssignmentId", "ClassId"); - - b.HasIndex("ClassId"); - - b.ToTable("assignment_class", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)"); - - b.Property("BCorrect") - .HasColumnType("tinyint(1)"); - b.Property("CreatedAt") .HasColumnType("datetime(6)") .HasColumnName("created_at"); + b.Property("ExamStructType") + .HasColumnType("tinyint unsigned") + .HasColumnName("exam_struct_type"); + b.Property("Index") .HasColumnType("tinyint unsigned") .HasColumnName("question_number"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); - b.Property("ParentAssignmentQuestionId") + b.Property("ParentExamQuestionId") .HasColumnType("char(36)") .HasColumnName("parent_question_group_id"); @@ -204,6 +248,9 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("question_id"); + b.Property("QuestionTypeId") + .HasColumnType("char(36)"); + b.Property("Score") .HasColumnType("float") .HasColumnName("score"); @@ -213,148 +260,73 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("sequence"); - b.Property("StructType") - .HasColumnType("tinyint unsigned") - .HasColumnName("group_state"); - b.Property("Title") .HasMaxLength(1024) .HasColumnType("varchar(1024)") .HasColumnName("title"); - b.Property("Type") - .HasColumnType("tinyint unsigned"); - b.HasKey("Id"); - b.HasIndex("AssignmentId"); - - b.HasIndex("ParentAssignmentQuestionId"); + b.HasIndex("ParentExamQuestionId"); b.HasIndex("QuestionContextId"); b.HasIndex("QuestionId"); - b.ToTable("assignment_questions", (string)null); + b.HasIndex("QuestionTypeId"); + + b.ToTable("exam_questions"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() - .HasColumnType("datetime(6)") - .HasColumnName("created_at"); - - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - b.Property("Description") + .IsRequired() .HasColumnType("longtext") .HasColumnName("description"); - b.Property("Grade") - .HasColumnType("tinyint unsigned") - .HasColumnName("grade"); - - b.Property("HeadTeacherId") - .HasColumnType("char(36)") - .HasColumnName("head_teacher_id"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.Property("Number") - .HasColumnType("tinyint unsigned") - .HasColumnName("class"); - - b.Property("UpdatedAt") - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("datetime(6)") - .HasColumnName("updated_at"); - - MySqlPropertyBuilderExtensions.UseMySqlComputedColumn(b.Property("UpdatedAt")); + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); b.HasKey("Id"); - b.HasIndex("HeadTeacherId"); - - b.ToTable("classes", (string)null); + b.ToTable("exam_type"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id") - .HasColumnOrder(0); - - b.Property("StudentId") - .HasColumnType("char(36)") - .HasColumnName("student_id") - .HasColumnOrder(1); - - b.Property("EnrollmentDate") - .HasColumnType("datetime(6)") - .HasColumnName("enrollment_date"); - - b.Property("IsDeleted") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint(1)") - .HasDefaultValue(false) - .HasColumnName("deleted"); - - b.HasKey("ClassId", "StudentId"); - - b.HasIndex("StudentId"); - - b.ToTable("class_student", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => - { - b.Property("ClassId") - .HasColumnType("char(36)") - .HasColumnName("class_id"); - - b.Property("TeacherId") - .HasColumnType("char(36)") - .HasColumnName("teacher_id"); - - b.Property("SubjectTaught") - .HasColumnType("tinyint unsigned") - .HasColumnName("subject_taught"); - - b.HasKey("ClassId", "TeacherId"); - - b.HasIndex("TeacherId"); - - b.ToTable("class_teachers", (string)null); - }); - - modelBuilder.Entity("Entities.Contracts.Global", b => + modelBuilder.Entity("Entities.Contracts.Grade", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("char(36)") - .HasColumnName("id"); + .HasColumnName("grade_id"); - b.Property("Area") - .HasColumnType("tinyint unsigned"); + b.Property("GradeLevel") + .HasColumnType("tinyint unsigned") + .HasColumnName("grade_level"); - b.Property("Info") + b.Property("GradeName") .IsRequired() - .HasColumnType("longtext"); + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("grade_name"); + + b.Property("SchoolId") + .HasColumnType("char(36)") + .HasColumnName("school_id"); b.HasKey("Id"); - b.ToTable("global"); + b.HasIndex("SchoolId"); + + b.ToTable("grades"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -434,28 +406,14 @@ namespace TechHelper.Server.Migrations b.Property("Answer") .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("correct_answer"); + .HasColumnName("answer"); b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); - - b.Property("CreatorId") - .HasColumnType("char(36)") - .HasColumnName("created_by"); - - b.Property("DifficultyLevel") - .HasMaxLength(10) - .HasColumnType("tinyint unsigned") - .HasColumnName("difficulty_level"); - b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("KeyPointId") @@ -470,44 +428,35 @@ namespace TechHelper.Server.Migrations .HasColumnType("longtext") .HasColumnName("options"); - b.Property("QType") - .IsRequired() - .HasColumnType("longtext"); + b.Property("QuestioTypeId") + .HasColumnType("char(36)") + .HasColumnName("type"); - b.Property("SubjectArea") - .HasMaxLength(100) - .HasColumnType("tinyint unsigned") + b.Property("SubjectId") + .HasColumnType("char(36)") .HasColumnName("subject_area"); b.Property("Title") .IsRequired() .HasMaxLength(65535) .HasColumnType("longtext") - .HasColumnName("question_text"); - - b.Property("Type") - .HasMaxLength(20) - .HasColumnType("tinyint unsigned") - .HasColumnName("question_type"); + .HasColumnName("title"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("CreatorId"); - b.HasIndex("KeyPointId"); b.HasIndex("LessonId"); - b.HasIndex("Title") - .HasAnnotation("MySql:IndexPrefixLength", new[] { 20 }); + b.HasIndex("QuestioTypeId"); - b.ToTable("questions", (string)null); + b.HasIndex("SubjectId"); + + b.ToTable("questions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -525,6 +474,92 @@ namespace TechHelper.Server.Migrations b.ToTable("QuestionContexts"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.Property("ScoreRule") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("score_rule"); + + b.Property("SubjectId") + .HasColumnType("char(36)") + .HasColumnName("subject_id"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("question_types"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("address"); + + b.Property("CreateTime") + .HasColumnType("datetime(6)") + .HasColumnName("create_time"); + + b.Property("SchoolName") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)") + .HasColumnName("school_name"); + + b.HasKey("Id"); + + b.ToTable("schools"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)") + .HasColumnName("id"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name"); + + b.HasKey("Id"); + + b.ToTable("subjects"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Property("Id") @@ -532,17 +567,21 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentId") - .HasColumnType("char(36)") - .HasColumnName("assignment_id"); - b.Property("AttemptNumber") .HasColumnType("tinyint unsigned") .HasColumnName("attempt_number"); + b.Property("ClassId") + .HasColumnType("char(36)") + .HasColumnName("class_id"); + b.Property("ErrorQuesNum") .HasColumnType("tinyint unsigned"); + b.Property("ExamId") + .HasColumnType("char(36)") + .HasColumnName("exam_id"); + b.Property("GradedAt") .HasColumnType("datetime(6)") .HasColumnName("graded_at"); @@ -552,9 +591,7 @@ namespace TechHelper.Server.Migrations .HasColumnName("graded_by"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("OverallFeedback") @@ -562,12 +599,10 @@ namespace TechHelper.Server.Migrations .HasColumnName("overall_feedback"); b.Property("OverallGrade") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("overall_grade"); b.Property("Status") - .HasMaxLength(15) .HasColumnType("int") .HasColumnName("status"); @@ -582,18 +617,20 @@ namespace TechHelper.Server.Migrations b.Property("TotalQuesNum") .HasColumnType("tinyint unsigned"); - b.Property("TotalScore") - .HasColumnType("tinyint unsigned"); + b.Property("TotalScore") + .HasColumnType("float"); b.HasKey("Id"); - b.HasIndex("AssignmentId"); + b.HasIndex("ClassId"); + + b.HasIndex("ExamId"); b.HasIndex("GraderId"); b.HasIndex("StudentId"); - b.ToTable("submissions", (string)null); + b.ToTable("submissions"); }); modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => @@ -603,36 +640,26 @@ namespace TechHelper.Server.Migrations .HasColumnType("char(36)") .HasColumnName("id"); - b.Property("AssignmentQuestionId") - .HasColumnType("char(36)") - .HasColumnName("assignment_question_id"); - b.Property("CreatedAt") - .ValueGeneratedOnAdd() .HasColumnType("datetime(6)") .HasColumnName("created_at"); - MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CreatedAt")); + b.Property("ExamQuestionId") + .HasColumnType("char(36)") + .HasColumnName("exam_question_id"); b.Property("IsCorrect") .HasColumnType("tinyint(1)") .HasColumnName("is_correct"); b.Property("IsDeleted") - .ValueGeneratedOnAdd() .HasColumnType("tinyint(1)") - .HasDefaultValue(false) .HasColumnName("deleted"); b.Property("PointsAwarded") - .HasPrecision(5, 2) .HasColumnType("float") .HasColumnName("points_awarded"); - b.Property("Status") - .HasColumnType("int") - .HasColumnName("status"); - b.Property("StudentAnswer") .HasColumnType("longtext") .HasColumnName("student_answer"); @@ -650,20 +677,18 @@ namespace TechHelper.Server.Migrations .HasColumnName("teacher_feedback"); b.Property("UpdatedAt") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() .HasColumnType("datetime(6)") .HasColumnName("updated_at"); b.HasKey("Id"); - b.HasIndex("AssignmentQuestionId"); + b.HasIndex("ExamQuestionId"); b.HasIndex("StudentId"); b.HasIndex("SubmissionId"); - b.ToTable("submission_details", (string)null); + b.ToTable("submission_details"); }); modelBuilder.Entity("Entities.Contracts.Textbook", b => @@ -699,9 +724,6 @@ namespace TechHelper.Server.Migrations b.Property("AccessFailedCount") .HasColumnType("int"); - b.Property("Address") - .HasColumnType("longtext"); - b.Property("ConcurrencyStamp") .IsConcurrencyToken() .HasColumnType("longtext"); @@ -716,6 +738,9 @@ namespace TechHelper.Server.Migrations b.Property("EmailConfirmed") .HasColumnType("tinyint(1)"); + b.Property("HomeAddress") + .HasColumnType("longtext"); + b.Property("IsDeleted") .HasColumnType("tinyint(1)") .HasColumnName("deleted"); @@ -749,11 +774,14 @@ namespace TechHelper.Server.Migrations b.Property("RefreshTokenExpiryTime") .HasColumnType("datetime(6)"); + b.Property("Role") + .HasColumnType("int"); + b.Property("SecurityStamp") .HasColumnType("longtext"); - b.Property("SubjectArea") - .HasColumnType("tinyint unsigned"); + b.Property("TeachSubjectId") + .HasColumnType("char(36)"); b.Property("TwoFactorEnabled") .HasColumnType("tinyint(1)"); @@ -771,6 +799,8 @@ namespace TechHelper.Server.Migrations .IsUnique() .HasDatabaseName("UserNameIndex"); + b.HasIndex("TeachSubjectId"); + b.ToTable("AspNetUsers", (string)null); }); @@ -799,26 +829,6 @@ namespace TechHelper.Server.Migrations .HasDatabaseName("RoleNameIndex"); b.ToTable("AspNetRoles", (string)null); - - b.HasData( - new - { - Id = new Guid("d480cdca-7de2-4abe-8129-73bbaa6c1b32"), - Name = "Student", - NormalizedName = "STUDENT" - }, - new - { - Id = new Guid("d7bcfb37-3f1c-467b-a3f0-b2339a8a990d"), - Name = "Teacher", - NormalizedName = "TEACHER" - }, - new - { - Id = new Guid("f4a6788a-04d8-499c-9e64-73dfba97ca6b"), - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); }); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => @@ -924,136 +934,126 @@ namespace TechHelper.Server.Migrations b.ToTable("AspNetUserTokens", (string)null); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => - { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany() - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ExamStruct") - .WithOne() - .HasForeignKey("Entities.Contracts.Assignment", "ExamStructId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.User", null) - .WithMany("CreatedAssignments") - .HasForeignKey("UserId"); - - b.Navigation("Creator"); - - b.Navigation("ExamStruct"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentAttachment", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentAttachments") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentClass", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany("AssignmentClasses") - .HasForeignKey("AssignmentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("AssignmentClasses") - .HasForeignKey("ClassId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Assignment"); - - b.Navigation("Class"); - }); - - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => - { - b.HasOne("Entities.Contracts.Assignment", "Assignment") - .WithMany() - .HasForeignKey("AssignmentId"); - - b.HasOne("Entities.Contracts.AssignmentQuestion", "ParentAssignmentQuestion") - .WithMany("ChildrenAssignmentQuestion") - .HasForeignKey("ParentAssignmentQuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") - .WithMany("Questions") - .HasForeignKey("QuestionContextId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("Entities.Contracts.Question", "Question") - .WithMany("AssignmentQuestions") - .HasForeignKey("QuestionId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Assignment"); - - b.Navigation("ParentAssignmentQuestion"); - - b.Navigation("Question"); - - b.Navigation("QuestionContext"); - }); - modelBuilder.Entity("Entities.Contracts.Class", b => { + b.HasOne("Entities.Contracts.Grade", "Grade") + .WithMany("Classes") + .HasForeignKey("GradeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("Entities.Contracts.User", "HeadTeacher") .WithMany() - .HasForeignKey("HeadTeacherId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); + .HasForeignKey("HeadTeacherId"); + + b.Navigation("Grade"); b.Navigation("HeadTeacher"); }); - modelBuilder.Entity("Entities.Contracts.ClassStudent", b => + modelBuilder.Entity("Entities.Contracts.ClassUser", b => { b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassStudents") + .WithMany("ClassUsers") .HasForeignKey("ClassId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Student") - .WithMany("EnrolledClassesLink") - .HasForeignKey("StudentId") - .OnDelete(DeleteBehavior.Restrict) + b.HasOne("Entities.Contracts.User", "User") + .WithMany("UserInjoinedClass") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.Navigation("Class"); - b.Navigation("Student"); + b.Navigation("User"); }); - modelBuilder.Entity("Entities.Contracts.ClassTeacher", b => + modelBuilder.Entity("Entities.Contracts.Exam", b => { - b.HasOne("Entities.Contracts.Class", "Class") - .WithMany("ClassTeachers") - .HasForeignKey("ClassId") + b.HasOne("Entities.Contracts.User", "Creator") + .WithMany("CreatedExams") + .HasForeignKey("CreatorId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Entities.Contracts.User", "Teacher") - .WithMany("TaughtClassesLink") - .HasForeignKey("TeacherId") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamStruct") + .WithOne("Exam") + .HasForeignKey("Entities.Contracts.Exam", "ExamStructId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Class"); + b.HasOne("Entities.Contracts.ExamType", "ExamType") + .WithMany("Exams") + .HasForeignKey("ExamTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); - b.Navigation("Teacher"); + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany() + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("ExamStruct"); + + b.Navigation("ExamType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamAttachment", b => + { + b.HasOne("Entities.Contracts.Exam", "Exam") + .WithMany("ExamAttachments") + .HasForeignKey("ExamId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Exam"); + }); + + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => + { + b.HasOne("Entities.Contracts.ExamQuestion", "ParentExamQuestion") + .WithMany("ChildExamQuestions") + .HasForeignKey("ParentExamQuestionId"); + + b.HasOne("Entities.Contracts.QuestionContext", "QuestionContext") + .WithMany("Questions") + .HasForeignKey("QuestionContextId"); + + b.HasOne("Entities.Contracts.Question", "Question") + .WithMany("ExamQuestions") + .HasForeignKey("QuestionId"); + + b.HasOne("Entities.Contracts.QuestionType", "Type") + .WithMany() + .HasForeignKey("QuestionTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ParentExamQuestion"); + + b.Navigation("Question"); + + b.Navigation("QuestionContext"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.HasOne("Entities.Contracts.School", "School") + .WithMany("Grades") + .HasForeignKey("SchoolId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("School"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1091,49 +1091,73 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.HasOne("Entities.Contracts.User", "Creator") - .WithMany("CreatedQuestions") - .HasForeignKey("CreatorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - b.HasOne("Entities.Contracts.KeyPoint", "KeyPoint") .WithMany("Questions") - .HasForeignKey("KeyPointId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("KeyPointId"); b.HasOne("Entities.Contracts.Lesson", "Lesson") .WithMany("Questions") - .HasForeignKey("LessonId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("LessonId"); - b.Navigation("Creator"); + b.HasOne("Entities.Contracts.QuestionType", "QuestionType") + .WithMany("Questions") + .HasForeignKey("QuestioTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("Questions") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("KeyPoint"); b.Navigation("Lesson"); + + b.Navigation("QuestionType"); + + b.Navigation("Subject"); + }); + + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.HasOne("Entities.Contracts.Subject", "Subject") + .WithMany("QuestionTypes") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subject"); }); modelBuilder.Entity("Entities.Contracts.Submission", b => { - b.HasOne("Entities.Contracts.Assignment", "Assignment") + b.HasOne("Entities.Contracts.Class", "Class") + .WithMany() + .HasForeignKey("ClassId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.Contracts.Exam", "Exam") .WithMany("Submissions") - .HasForeignKey("AssignmentId") + .HasForeignKey("ExamId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("Entities.Contracts.User", "Grader") .WithMany("GradedSubmissions") - .HasForeignKey("GraderId") - .OnDelete(DeleteBehavior.SetNull); + .HasForeignKey("GraderId"); b.HasOne("Entities.Contracts.User", "Student") - .WithMany("SubmissionsAsStudent") + .WithMany("StudentSubmissions") .HasForeignKey("StudentId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Assignment"); + b.Navigation("Class"); + + b.Navigation("Exam"); b.Navigation("Grader"); @@ -1142,9 +1166,9 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.SubmissionDetail", b => { - b.HasOne("Entities.Contracts.AssignmentQuestion", "AssignmentQuestion") + b.HasOne("Entities.Contracts.ExamQuestion", "ExamQuestion") .WithMany("SubmissionDetails") - .HasForeignKey("AssignmentQuestionId") + .HasForeignKey("ExamQuestionId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1160,13 +1184,22 @@ namespace TechHelper.Server.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("AssignmentQuestion"); + b.Navigation("ExamQuestion"); b.Navigation("Student"); b.Navigation("Submission"); }); + modelBuilder.Entity("Entities.Contracts.User", b => + { + b.HasOne("Entities.Contracts.Subject", "TeachSubject") + .WithMany("SubjectTeachers") + .HasForeignKey("TeachSubjectId"); + + b.Navigation("TeachSubject"); + }); + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) @@ -1218,29 +1251,35 @@ namespace TechHelper.Server.Migrations .IsRequired(); }); - modelBuilder.Entity("Entities.Contracts.Assignment", b => + modelBuilder.Entity("Entities.Contracts.Class", b => { - b.Navigation("AssignmentAttachments"); + b.Navigation("ClassUsers"); + }); - b.Navigation("AssignmentClasses"); + modelBuilder.Entity("Entities.Contracts.Exam", b => + { + b.Navigation("ExamAttachments"); b.Navigation("Submissions"); }); - modelBuilder.Entity("Entities.Contracts.AssignmentQuestion", b => + modelBuilder.Entity("Entities.Contracts.ExamQuestion", b => { - b.Navigation("ChildrenAssignmentQuestion"); + b.Navigation("ChildExamQuestions"); + + b.Navigation("Exam"); b.Navigation("SubmissionDetails"); }); - modelBuilder.Entity("Entities.Contracts.Class", b => + modelBuilder.Entity("Entities.Contracts.ExamType", b => { - b.Navigation("AssignmentClasses"); + b.Navigation("Exams"); + }); - b.Navigation("ClassStudents"); - - b.Navigation("ClassTeachers"); + modelBuilder.Entity("Entities.Contracts.Grade", b => + { + b.Navigation("Classes"); }); modelBuilder.Entity("Entities.Contracts.KeyPoint", b => @@ -1259,7 +1298,7 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.Question", b => { - b.Navigation("AssignmentQuestions"); + b.Navigation("ExamQuestions"); }); modelBuilder.Entity("Entities.Contracts.QuestionContext", b => @@ -1267,6 +1306,25 @@ namespace TechHelper.Server.Migrations b.Navigation("Questions"); }); + modelBuilder.Entity("Entities.Contracts.QuestionType", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("Entities.Contracts.School", b => + { + b.Navigation("Grades"); + }); + + modelBuilder.Entity("Entities.Contracts.Subject", b => + { + b.Navigation("QuestionTypes"); + + b.Navigation("Questions"); + + b.Navigation("SubjectTeachers"); + }); + modelBuilder.Entity("Entities.Contracts.Submission", b => { b.Navigation("SubmissionDetails"); @@ -1279,19 +1337,15 @@ namespace TechHelper.Server.Migrations modelBuilder.Entity("Entities.Contracts.User", b => { - b.Navigation("CreatedAssignments"); - - b.Navigation("CreatedQuestions"); - - b.Navigation("EnrolledClassesLink"); + b.Navigation("CreatedExams"); b.Navigation("GradedSubmissions"); + b.Navigation("StudentSubmissions"); + b.Navigation("SubmissionDetails"); - b.Navigation("SubmissionsAsStudent"); - - b.Navigation("TaughtClassesLink"); + b.Navigation("UserInjoinedClass"); }); #pragma warning restore 612, 618 } diff --git a/TechHelper.Server/Program.cs b/TechHelper.Server/Program.cs index a31c3df..0a4a758 100644 --- a/TechHelper.Server/Program.cs +++ b/TechHelper.Server/Program.cs @@ -9,10 +9,11 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; using TechHelper.Features; -using TechHelper.Services; -using TechHelper.Server.Services; using TechHelper.Server.Repositories; using Microsoft.OpenApi.Models; +using TechHelper.Services.Beta; +using TechHelper.Server.Context; +using TechHelper.Server.Repository; /// /// TechHelper 服务器应用程序的主入口点 @@ -24,22 +25,28 @@ builder.Services.AddControllers(); // 2. 数据库服务 (DbContext) builder.Services.AddDbContext(options => - options.UseMySql( + options + .UseLazyLoadingProxies() + .UseMySql( builder.Configuration.GetConnectionString("XSDB"), ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("XSDB")) ) ).AddUnitOfWork() -.AddCustomRepository() -.AddCustomRepository() -.AddCustomRepository() +.AddCustomRepository() +.AddCustomRepository() +.AddCustomRepository() .AddCustomRepository() -.AddCustomRepository() -.AddCustomRepository() +.AddCustomRepository() .AddCustomRepository() .AddCustomRepository() .AddCustomRepository() +.AddCustomRepository() +.AddCustomRepository() +.AddCustomRepository() .AddCustomRepository() -.AddCustomRepository(); +.AddCustomRepository() +.AddCustomRepository() +.AddCustomRepository(); builder.Services.AddAutoMapper(typeof(AutoMapperProFile).Assembly); @@ -55,10 +62,11 @@ builder.Services.AddIdentity>(opt => { opt.User.AllowedUserNameCharacters = ""; opt.Lockout.AllowedForNewUsers = true; - opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(2); + opt.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); opt.Lockout.MaxFailedAccessAttempts = 3; }) - .AddEntityFrameworkStores() + .AddRoles>() + .AddEntityFrameworkStores() .AddDefaultTokenProviders(); builder.Services.Configure(Options => { @@ -81,7 +89,7 @@ builder.Services.AddAuthentication(options => ValidateAudience = true, // 验证受众 ValidateLifetime = true, // 验证令牌有效期 ValidateIssuerSigningKey = true, // 验证签名密钥 - + ValidIssuer = jwtSettings["validIssuer"], // 合法的签发人 ValidAudience = jwtSettings["validAudience"], // 合法的受众 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["securityKey"])) // 签名密钥 @@ -90,15 +98,23 @@ builder.Services.AddAuthentication(options => builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddTransient(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + builder.Services.AddEndpointsApiExplorer(); @@ -108,11 +124,11 @@ builder.Services.AddSwaggerGen(c => c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { - Name = "Authorization", - Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT", - In = ParameterLocation.Header, + Name = "Authorization", + Type = SecuritySchemeType.Http, + Scheme = "bearer", + BearerFormat = "JWT", + In = ParameterLocation.Header, Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"", }); @@ -124,27 +140,28 @@ builder.Services.AddSwaggerGen(c => Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, - Id = "Bearer" - } + Id = "Bearer" + } }, new string[] {} - } + } }); }); - builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => builder - .WithOrigins("https://localhost:7047", "http://localhost:7047", "https://localhost:5001", "http://localhost:5001") + .WithOrigins("https://localhost:7047", "http://localhost:7047", "https://localhost:5001", "http://localhost:5001") .AllowAnyHeader() .AllowAnyMethod() - .AllowCredentials()); + .AllowCredentials()); }); var app = builder.Build(); + + // Configure the HTTP request pipeline. if (/*app.Environment.IsDevelopment()*/true) { @@ -157,6 +174,21 @@ app.UseHttpsRedirection(); app.UseAuthorization(); +using (var scope = app.Services.CreateScope()) +{ + var services = scope.ServiceProvider; + try + { + var roleManager = services.GetRequiredService>>(); + await DbInitializer.SeedRoles(roleManager); + } + catch (Exception ex) + { + var logger = services.GetRequiredService>(); + logger.LogError(ex, "An error occurred while seeding the database."); + } +} + app.MapControllers(); app.Run(); diff --git a/TechHelper.Server/Repositories/ExamRepository.cs b/TechHelper.Server/Repositories/ExamRepository.cs index c9df66a..9825cd1 100644 --- a/TechHelper.Server/Repositories/ExamRepository.cs +++ b/TechHelper.Server/Repositories/ExamRepository.cs @@ -9,18 +9,18 @@ namespace TechHelper.Server.Repositories public class ExamRepository : IExamRepository { private readonly IUnitOfWork _unitOfWork; - private readonly IRepository _assignmentRepo; + private readonly IRepository _assignmentRepo; private readonly IRepository _questionRepo; - private readonly IRepository _assignQuestionRepo; + private readonly IRepository _assignQuestionRepo; public ExamRepository(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; - _assignmentRepo = _unitOfWork.GetRepository(); - _assignQuestionRepo = _unitOfWork.GetRepository(); + _assignmentRepo = _unitOfWork.GetRepository(); + _assignQuestionRepo = _unitOfWork.GetRepository(); } - public async Task GetFullExamByIdAsync(Guid assignmentId) + public async Task GetFullExamByIdAsync(Guid assignmentId) { var result = await _assignmentRepo.GetFirstOrDefaultAsync( predicate: @@ -35,12 +35,12 @@ namespace TechHelper.Server.Repositories } - public async Task GetNeed(Guid id) + public async Task GetNeed(Guid id) { var result = await _assignQuestionRepo.GetFirstOrDefaultAsync( predicate: aq => aq.Id == id, include: i => i - .Include(aq => aq.ChildrenAssignmentQuestion) + .Include(aq => aq.ChildExamQuestions) .Include(aq => aq.Question) .ThenInclude(q => q.Lesson) .Include(aq => aq.Question) @@ -52,8 +52,8 @@ namespace TechHelper.Server.Repositories return null; } - var loadedChildren = new List(); - foreach (var child in result.ChildrenAssignmentQuestion) + var loadedChildren = new List(); + foreach (var child in result.ChildExamQuestions) { var loadedChild = await GetNeed(child.Id); if (loadedChild != null) @@ -61,25 +61,25 @@ namespace TechHelper.Server.Repositories loadedChildren.Add(loadedChild); } } - result.ChildrenAssignmentQuestion = loadedChildren; + result.ChildExamQuestions = loadedChildren; return result; } - public async Task> GetExamPreviewsByUserAsync(Guid userId) + public async Task> GetExamPreviewsByUserAsync(Guid userId) { return await _assignmentRepo.GetAllAsync( predicate: a => a.CreatorId == userId && !a.IsDeleted); } - public async Task AddAsync(Assignment assignment) + public async Task AddAsync(Exam assignment) { await _assignmentRepo.InsertAsync(assignment); } - public async Task AddAsync(AssignmentQuestion assignment) + public async Task AddAsync(ExamQuestion assignment) { } @@ -87,21 +87,17 @@ namespace TechHelper.Server.Repositories { } - public async Task AddAsync(AssignmentClass assignment) - { - } - public async Task AddAsync(Submission submission) { await _unitOfWork.GetRepository().InsertAsync(submission); } - public async Task> GetAllSubmissionPreviewsByUserAsync(Guid id) + public async Task> GetAllSubmissionPreviewsByUserAsync(Guid id) { - var submissions = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.StudentId == id, include: i => i.Include(s => s.Assignment)); + var submissions = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.StudentId == id, include: i => i.Include(s => s.Exam)); if (submissions == null || !submissions.Any()) - return Enumerable.Empty(); - return submissions.ToList().Select(s => s.Assignment).Where(a => a != null).ToList(); + return Enumerable.Empty(); + return submissions.ToList().Select(s => s.Exam).Where(a => a != null).ToList(); } } } diff --git a/TechHelper.Server/Repositories/IExamRepository.cs b/TechHelper.Server/Repositories/IExamRepository.cs index a4f8075..3fc178e 100644 --- a/TechHelper.Server/Repositories/IExamRepository.cs +++ b/TechHelper.Server/Repositories/IExamRepository.cs @@ -10,30 +10,29 @@ namespace TechHelper.Server.Repositories /// /// 试卷ID /// 完整的 Assignment 实体,如果找不到则返回 null。 - Task GetFullExamByIdAsync(Guid assignmentId); + Task GetFullExamByIdAsync(Guid assignmentId); /// /// 获取指定用户创建的所有试卷的预览信息。 /// /// 用户ID /// Assignment 实体集合。 - Task> GetExamPreviewsByUserAsync(Guid userId); + Task> GetExamPreviewsByUserAsync(Guid userId); /// /// 向数据库添加一个新的试卷。 /// /// 要添加的试卷实体。 - Task AddAsync(Assignment assignment); + Task AddAsync(Exam assignment); Task AddAsync(Submission submission); - Task AddAsync(AssignmentQuestion assignment); + Task AddAsync(ExamQuestion assignment); Task AddAsync(Question assignment); - Task AddAsync(AssignmentClass assignment); - Task> GetAllSubmissionPreviewsByUserAsync(Guid id); + Task> GetAllSubmissionPreviewsByUserAsync(Guid id); } } diff --git a/TechHelper.Server/Repository/AssignmentAttachmentRepository.cs b/TechHelper.Server/Repository/AssignmentAttachmentRepository.cs index 4d22a0f..2ae8e18 100644 --- a/TechHelper.Server/Repository/AssignmentAttachmentRepository.cs +++ b/TechHelper.Server/Repository/AssignmentAttachmentRepository.cs @@ -5,7 +5,7 @@ using TechHelper.Context; namespace TechHelper.Repository { - public class AssignmentAttachmentRepository : Repository, IRepository + public class AssignmentAttachmentRepository : Repository, IRepository { public AssignmentAttachmentRepository(ApplicationContext dbContext) : base(dbContext) { diff --git a/TechHelper.Server/Repository/AssignmentClassRepository.cs b/TechHelper.Server/Repository/AssignmentClassRepository.cs deleted file mode 100644 index 9f60d33..0000000 --- a/TechHelper.Server/Repository/AssignmentClassRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore; -using SharedDATA.Api; -using TechHelper.Context; - -namespace TechHelper.Repository -{ - public class AssignmentClassRepository : Repository, IRepository - { - public AssignmentClassRepository(ApplicationContext dbContext) : base(dbContext) - { - } - } -} diff --git a/TechHelper.Server/Repository/AssignmentQuestionRepository.cs b/TechHelper.Server/Repository/AssignmentQuestionRepository.cs index a54c669..95bb8dd 100644 --- a/TechHelper.Server/Repository/AssignmentQuestionRepository.cs +++ b/TechHelper.Server/Repository/AssignmentQuestionRepository.cs @@ -5,7 +5,7 @@ using TechHelper.Context; namespace TechHelper.Repository { - public class AssignmentQuestionRepository : Repository, IRepository + public class AssignmentQuestionRepository : Repository, IRepository { public AssignmentQuestionRepository(ApplicationContext dbContext) : base(dbContext) { diff --git a/TechHelper.Server/Repository/AssignmentRepository.cs b/TechHelper.Server/Repository/AssignmentRepository.cs index 2648f4b..a7d8a53 100644 --- a/TechHelper.Server/Repository/AssignmentRepository.cs +++ b/TechHelper.Server/Repository/AssignmentRepository.cs @@ -5,7 +5,7 @@ using TechHelper.Context; namespace TechHelper.Repository { - public class AssignmentRepository : Repository, IRepository + public class AssignmentRepository : Repository, IRepository { public AssignmentRepository(ApplicationContext dbContext) : base(dbContext) { diff --git a/TechHelper.Server/Repository/ClassStudentRepository.cs b/TechHelper.Server/Repository/ClassStudentRepository.cs deleted file mode 100644 index 6d4e43e..0000000 --- a/TechHelper.Server/Repository/ClassStudentRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore; -using SharedDATA.Api; -using TechHelper.Context; - -namespace TechHelper.Repository -{ - public class ClassStudentRepository : Repository, IRepository - { - public ClassStudentRepository(ApplicationContext dbContext) : base(dbContext) - { - } - } -} diff --git a/TechHelper.Server/Repository/ClassTeacherRepository.cs b/TechHelper.Server/Repository/ClassTeacherRepository.cs deleted file mode 100644 index 7fc5403..0000000 --- a/TechHelper.Server/Repository/ClassTeacherRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Entities.Contracts; -using Microsoft.EntityFrameworkCore; -using SharedDATA.Api; -using TechHelper.Context; - -namespace TechHelper.Repository -{ - public class ClassTeacherRepository : Repository, IRepository - { - public ClassTeacherRepository(ApplicationContext dbContext) : base(dbContext) - { - } - } -} diff --git a/TechHelper.Server/Repository/GlobalRepository.cs b/TechHelper.Server/Repository/ClassUserRepository.cs similarity index 50% rename from TechHelper.Server/Repository/GlobalRepository.cs rename to TechHelper.Server/Repository/ClassUserRepository.cs index bd6d17a..6b337e6 100644 --- a/TechHelper.Server/Repository/GlobalRepository.cs +++ b/TechHelper.Server/Repository/ClassUserRepository.cs @@ -5,13 +5,10 @@ using TechHelper.Context; namespace TechHelper.Repository { - public class GlobalRepository : Repository, IRepository + public class ClassUserRepository : Repository, IRepository { - public GlobalRepository(ApplicationContext dbContext) : base(dbContext) + public ClassUserRepository(ApplicationContext dbContext) : base(dbContext) { - } - - } } diff --git a/TechHelper.Server/Repository/ExamQuestionRepository.cs b/TechHelper.Server/Repository/ExamQuestionRepository.cs new file mode 100644 index 0000000..871d5b8 --- /dev/null +++ b/TechHelper.Server/Repository/ExamQuestionRepository.cs @@ -0,0 +1,14 @@ +using Entities.Contracts; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + public class ExamQuestionRepository : Repository, IRepository + { + public ExamQuestionRepository(ApplicationContext dbContext) : base(dbContext) + { + } + } +} diff --git a/TechHelper.Server/Repository/ExamTypeRepository.cs b/TechHelper.Server/Repository/ExamTypeRepository.cs new file mode 100644 index 0000000..5a55183 --- /dev/null +++ b/TechHelper.Server/Repository/ExamTypeRepository.cs @@ -0,0 +1,14 @@ +using Entities.Contracts; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + public class ExamTypeRepository : Repository, IRepository + { + public ExamTypeRepository(ApplicationContext dbContext) : base(dbContext) + { + } + } +} diff --git a/TechHelper.Server/Repository/KeyPointRepository.cs b/TechHelper.Server/Repository/KeyPointRepository.cs new file mode 100644 index 0000000..427ed81 --- /dev/null +++ b/TechHelper.Server/Repository/KeyPointRepository.cs @@ -0,0 +1,13 @@ +using Entities.Contracts; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + public class KeyPointRepository : Repository, IRepository + { + public KeyPointRepository(ApplicationContext context) : base(context) + { + } + } +} diff --git a/TechHelper.Server/Repository/LessonRepository.cs b/TechHelper.Server/Repository/LessonRepository.cs new file mode 100644 index 0000000..b78df5d --- /dev/null +++ b/TechHelper.Server/Repository/LessonRepository.cs @@ -0,0 +1,18 @@ +using Entities.Contracts; +using SharedDATA.Api; +using System.Linq.Expressions; +using TechHelper.Context; +using TechHelper.Server.Repository; + +namespace TechHelper.Server.Repository +{ + /// + /// Lesson仓储实现类 + /// + public class LessonRepository : Repository, IRepository + { + public LessonRepository(ApplicationContext context) : base(context) + { + } + } +} diff --git a/TechHelper.Server/Repository/QuestionTypeRepository.cs b/TechHelper.Server/Repository/QuestionTypeRepository.cs new file mode 100644 index 0000000..103f59d --- /dev/null +++ b/TechHelper.Server/Repository/QuestionTypeRepository.cs @@ -0,0 +1,14 @@ +using Entities.Contracts; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + public class QuestionTypeRepository : Repository, IRepository + { + public QuestionTypeRepository(ApplicationContext dbContext) : base(dbContext) + { + } + } +} diff --git a/TechHelper.Server/Repository/SubjectRepository.cs b/TechHelper.Server/Repository/SubjectRepository.cs new file mode 100644 index 0000000..cef1111 --- /dev/null +++ b/TechHelper.Server/Repository/SubjectRepository.cs @@ -0,0 +1,14 @@ +using Entities.Contracts; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + public class SubjectRepository : Repository, IRepository + { + public SubjectRepository(ApplicationContext dbContext) : base(dbContext) + { + } + } +} diff --git a/TechHelper.Server/Repository/TextbookRepository.cs b/TechHelper.Server/Repository/TextbookRepository.cs new file mode 100644 index 0000000..bcf7359 --- /dev/null +++ b/TechHelper.Server/Repository/TextbookRepository.cs @@ -0,0 +1,21 @@ +using Entities.Contracts; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Context; + +namespace TechHelper.Repository +{ + /// + /// 教材仓储实现类 + /// + public class TextbookRepository : Repository, IRepository + { + /// + /// 初始化教材仓储 + /// + /// 数据库上下文 + public TextbookRepository(ApplicationContext dbContext) : base(dbContext) + { + } + } +} diff --git a/TechHelper.Server/Services/Class/ClassService.cs b/TechHelper.Server/Services/Class/ClassService.cs new file mode 100644 index 0000000..fba75a4 --- /dev/null +++ b/TechHelper.Server/Services/Class/ClassService.cs @@ -0,0 +1,319 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Entities.DTO.Class; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Repository; + +namespace TechHelper.Services.Beta +{ + public class ClassService : IClassService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public ClassService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var classes = await repository.GetPagedListAsync( + predicate: c => c.ClassName.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var classDtosFiltered = _mapper.Map>(classes.Items); + return new ApiResponse(true, classDtosFiltered); + } + else + { + var classes = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var classDtos = _mapper.Map>(classes.Items); + return new ApiResponse(true, classDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有班级时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var @class = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.Id == id, + include: i => i.Include(c => c.Grade).Include(c => c.HeadTeacher)); + + if (@class == null) + { + return new ApiResponse("班级未找到。"); + } + + var classDto = _mapper.Map(@class); + return new ApiResponse(true, classDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取班级时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(ClassDto model) + { + try + { + // 检查是否已存在相同年级下的同名班级 + var existingClass = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.GradeId == model.GradeId && (c.ClassName == model.ClassName || c.Index == model.Index)); + + if (existingClass != null) + { + return new ApiResponse($"在当前年级下,班级 '{model.ClassName}', 序号 '{model.Index}' 已存在。 请检查你的班级名称和序号, 如有问题请联系管理员."); + } + + var @class = _mapper.Map(model); + await _work.GetRepository().InsertAsync(@class); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(@class)); + } + return new ApiResponse("添加班级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加班级时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(ClassDto model) + { + try + { + var existingClass = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.Id == model.Id); + + if (existingClass == null) + { + return new ApiResponse("班级未找到。"); + } + + _mapper.Map(model, existingClass); + _work.GetRepository().Update(existingClass); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(existingClass)); + } + return new ApiResponse("更新班级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新班级时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingClass = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.Id == id); + + if (existingClass == null) + { + return new ApiResponse("班级未找到。"); + } + + _work.GetRepository().Delete(existingClass); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "班级删除成功。"); + } + return new ApiResponse("删除班级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除班级时发生错误: {ex.Message}"); + } + } + + public async Task GetClassStudentsAsync(Guid classId) + { + try + { + var classEntity = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.Id == classId); + + if (classEntity == null) + { + return new ApiResponse("班级未找到。"); + } + + var students = classEntity.Students + .Where(u => !u.IsDeleted) + .Select(u => u.User) + .ToList(); + + + var StudentsDto = _mapper.Map>(students); + return new ApiResponse(true, StudentsDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取班级学生时发生错误: {ex.Message}"); + } + } + + public async Task ValidateClassRegistration(ClassValidDto user) + { + try + { + // 验证学校是否存在 + var schoolRepository = _work.GetRepository(); + var school = await schoolRepository.GetFirstOrDefaultAsync( + predicate: s => s.SchoolName == user.SchoolName); + + if (school == null) + { + return new ApiResponse("学校未找到。"); + } + + // 验证年级是否存在 + var gradeRepository = _work.GetRepository(); + var grade = await gradeRepository.GetFirstOrDefaultAsync( + predicate: g => g.SchoolId == school.Id && g.GradeLevel == user.Grade); + + if (grade == null) + { + return new ApiResponse("年级未找到。"); + } + + // 验证班级是否存在 + var classRepository = _work.GetRepository(); + var classEntity = await classRepository.GetFirstOrDefaultAsync( + predicate: c => c.GradeId == grade.Id && c.Index == user.Class && !c.IsDeleted); + + if (classEntity == null) + { + return new ApiResponse("班级未找到。"); + } + + // 返回验证成功的班级信息 + return new ApiResponse(true, classEntity.Id); + } + catch (Exception ex) + { + return new ApiResponse($"验证班级信息时发生错误: {ex.Message}"); + } + } + + public async Task UserRegister(RegisterUserToClassDto user) + { + try + { + // 获取班级实体 + var classRepository = _work.GetRepository(); + var classEntity = await classRepository.GetFirstOrDefaultAsync( + predicate: c => c.Id == user.ClassId); + + if (classEntity == null) + { + return new ApiResponse("检查你的班级输入,没有该班级。"); + } + + // 检查用户是否已经在该班级中 + var existingClassUser = classEntity.ClassUsers.FirstOrDefault(u => u.UserId == user.UserId); + if (existingClassUser != null ) + { + return new ApiResponse("用户已经在该班级中。"); + } + + await _work.GetRepository().InsertAsync( + new ClassUser { ClassId = user.ClassId, UserId = user.UserId, EnrollmentDate = DateTime.Now }); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "用户成功注册到班级。"); + } + return new ApiResponse("用户注册到班级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"用户注册到班级时发生错误: {ex.Message}"); + } + } + + public async Task GetUserInjoinedClasses(Guid user) + { + try + { + var userInfo = await _work.GetRepository().GetFirstOrDefaultAsync(predicate: + u => u.Id == user,include: i => i + .Include(u => u.UserInjoinedClass) + .ThenInclude(c => c.Class) + .ThenInclude(cs => cs.Grade)); + var schoolName = userInfo.UserInjoinedClass.First().Class.Grade.School.SchoolName; + var userClassInfo = userInfo.UserInjoinedClass.Select(c => c.Class); + var userClassDto = userClassInfo.Select(c => new UserClassInfoDto(c.Id, c.Index, c.Grade.GradeLevel)); + var result = new UserClassDetailInfoDto(userClassDto, schoolName); + return ApiResponse.Success(result: result); + } + catch(Exception ex) + { + return ApiResponse.Error($"获取用户班级信息时发生错误: {ex.Message}"); + } + + + } + + public Task GetUserClassRole(Guid id) + { + throw new NotImplementedException(); + } + + public async Task AdminAddAsync(ClassCreateDto model) + { + try + { + // 检查是否已存在相同年级下的同名班级 + var existingClass = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: c => c.Grade.GradeLevel == model.Grade.GradeLevel && (c.ClassName == model.ClassName || c.Index == model.Index)); + + if (existingClass != null) + { + return new ApiResponse($"在当前年级下,班级 '{model.ClassName}', 序号 '{model.Index}' 已存在。 请检查你的班级名称和序号, 如有问题请联系管理员."); + } + + var @class = _mapper.Map(model); + await _work.GetRepository().InsertAsync(@class); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(@class)); + } + return new ApiResponse("添加班级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加班级时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/Class/IClassService.cs b/TechHelper.Server/Services/Class/IClassService.cs new file mode 100644 index 0000000..e6bca67 --- /dev/null +++ b/TechHelper.Server/Services/Class/IClassService.cs @@ -0,0 +1,16 @@ +using Entities.DTO; +using Entities.DTO.Class; +using SharedDATA.Api; + +namespace TechHelper.Services.Beta +{ + public interface IClassService : IBaseService + { + Task GetClassStudentsAsync(Guid classId); + Task UserRegister(RegisterUserToClassDto user); + Task ValidateClassRegistration(ClassValidDto user); + Task GetUserInjoinedClasses(Guid user); + Task GetUserClassRole(Guid id); + Task AdminAddAsync(ClassCreateDto dto); + } +} diff --git a/TechHelper.Server/Services/ClassService.cs b/TechHelper.Server/Services/ClassService.cs index 1b1f89c..3e16c27 100644 --- a/TechHelper.Server/Services/ClassService.cs +++ b/TechHelper.Server/Services/ClassService.cs @@ -1,6 +1,7 @@ using AutoMapper; using Entities.Contracts; using Entities.DTO; +using Entities.DTO.Class; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Org.BouncyCastle.Crypto; @@ -41,7 +42,7 @@ namespace TechHelper.Services } // 实现 IBaseService.DeleteAsync - public async Task DeleteAsync(Guid id) // ID 类型现在是 int + public async Task DeleteAsync(Guid id) { try { diff --git a/TechHelper.Server/Services/Exam/ExamQuestionService.cs b/TechHelper.Server/Services/Exam/ExamQuestionService.cs new file mode 100644 index 0000000..33034f7 --- /dev/null +++ b/TechHelper.Server/Services/Exam/ExamQuestionService.cs @@ -0,0 +1,196 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services.Beta; +using static TechHelper.Services.Beta.IExamQuestionService; + +namespace TechHelper.Services.Beta +{ + public class ExamQuestionService : IExamQuestionService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + private readonly IClassService _classService; + + public ExamQuestionService(IUnitOfWork work, IMapper mapper, IClassService classService) + { + _work = work; + _mapper = mapper; + _classService = classService; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var examQuestions = await repository.GetPagedListAsync( + predicate: eq => eq.Title.Contains(query.Search) && eq.ParentExamQuestionId == null, + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var examQuestionDtosFiltered = _mapper.Map>(examQuestions.Items); + return new ApiResponse(true, examQuestionDtosFiltered); + } + else + { + var examQuestions = await repository.GetPagedListAsync( + predicate: eq => eq.ParentExamQuestionId == null, + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var examQuestionDtos = _mapper.Map>(examQuestions.Items); + return new ApiResponse(true, examQuestionDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有考试题目时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var examQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: eq => eq.Id == id); + + if (examQuestion == null) + { + return new ApiResponse("考试题目未找到。"); + } + + var examQuestionDto = _mapper.Map(examQuestion); + return new ApiResponse(true, examQuestionDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取考试题目时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(ExamQuestionDto model) + { + try + { + // 检查是否已存在相同考试和题目的组合 + var existingExamQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: eq => eq.Id == model.Id/* && eq.QuestionId == model.Question.Id*/); + + if (existingExamQuestion != null) + { + return new ApiResponse($"该题目已在此考试中存在。"); + } + + var examQuestion = _mapper.Map(model); + + await _work.GetRepository().InsertAsync(examQuestion); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, examQuestion.Id); + } + return new ApiResponse("添加考试题目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加考试题目时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(ExamQuestionDto model) + { + try + { + var existingExamQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: eq => eq.Id == model.Id); + + if (existingExamQuestion == null) + { + return new ApiResponse("考试题目未找到。"); + } + + // 检查是否要修改为已存在的考试题目组合(排除当前记录) + var examQuestionWithSameCombination = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: eq => eq.Id == model.Id /*&& eq.QuestionId == model.QuestionId*/ && eq.Id != model.Id); + + if (examQuestionWithSameCombination != null) + { + return new ApiResponse($"该题目与考试的组合已存在。"); + } + + _mapper.Map(model, existingExamQuestion); + _work.GetRepository().Update(existingExamQuestion); + + if (await _work.SaveChangesAsync() > 0) + { + var examQuestionDto = _mapper.Map(existingExamQuestion); + return new ApiResponse(true, examQuestionDto); + } + return new ApiResponse("更新考试题目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新考试题目时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingExamQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: eq => eq.Id == id); + + if (existingExamQuestion == null) + { + return new ApiResponse("考试题目未找到。"); + } + + _work.GetRepository().Delete(existingExamQuestion); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "考试题目删除成功。"); + } + return new ApiResponse("删除考试题目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除考试题目时发生错误: {ex.Message}"); + } + } + + public async Task GetQuestionDependy(QuesitionDenpendceyRequst request) + { + try + { + var classStudentsResponse = await _classService.GetClassStudentsAsync(request.ClassId); + if (!classStudentsResponse.Status) return ApiResponse.Error(classStudentsResponse.Message); + + var classStudents = classStudentsResponse.Result as IEnumerable; + if (classStudents == null) return ApiResponse.Error("班级学生列表为空。"); + + var submissionResult = await _work.GetRepository().GetAllAsync(predicate: sd => sd.ExamQuestionId == request.ExamQuestioId ); + var submission = submissionResult.Where(s => classStudents.Any(c => c.Id == s.StudentId)); + var errorStudents = submission.Select(s => s.Student); + var scores = submission.Select(s => s.PointsAwarded); + var lesson = submission.FirstOrDefault()?.ExamQuestion?.Question?.Lesson ?? null; + var lessonDto = _mapper.Map(lesson); + var ErrorStudentDtro = _mapper.Map>(errorStudents); + return ApiResponse.Success("获取成功", new QuestionDependecyDto(lessonDto, scores, ErrorStudentDtro)); + + } + catch (Exception ex) + { + return ApiResponse.Error($"获取考试题目密度时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/Exam/ExamService.cs b/TechHelper.Server/Services/Exam/ExamService.cs new file mode 100644 index 0000000..e4262e2 --- /dev/null +++ b/TechHelper.Server/Services/Exam/ExamService.cs @@ -0,0 +1,341 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using Microsoft.VisualBasic; +using SharedDATA.Api; +using System.Linq; +using TechHelper.Context; +using TechHelper.Server.Repositories; +using TechHelper.Services.Beta; +using static TechHelper.Services.Beta.IExamService; + +namespace TechHelper.Services.Beta +{ + + public class ExamService : IExamService + { + private readonly IUnitOfWork _unitOfWork; + private readonly ISubmissionService _submissionService; + private readonly IClassService _classService; + private readonly IMapper _mapper; + + public ExamService(IUnitOfWork unitOfWork, IMapper mapper, IClassService classService, ISubmissionService submissionService) + { + _unitOfWork = unitOfWork; + _mapper = mapper; + _classService = classService; + _submissionService = submissionService; + } + + public async Task CreateExamAsync(ExamDto ExamDto) + { + try + { + + Exam newAssi = _mapper.Map(ExamDto); + //var context = _unitOfWork.GetDbContext(); + + //foreach (var entry in context.ChangeTracker.Entries()) + //{ + // if (entry.State == Microsoft.EntityFrameworkCore.EntityState.Added) + // { + // if (entry.Entity is Question newQues) + // { + // newQues.CreatorId = newAssi.CreatorId; + // } + // } + + //} + + + + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success(); + } + + return ApiResponse.Error("保存失败"); + } + catch (Exception ex) + { + return ApiResponse.Error(ex.Message); + } + } + + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _unitOfWork.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var examQuestions = await repository.GetPagedListAsync( + predicate: eq => eq.Title.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var examQuestionDtosFiltered = _mapper.Map>(examQuestions.Items); + return new ApiResponse(true, examQuestionDtosFiltered); + } + else + { + var examQuestions = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var examQuestionDtos = _mapper.Map>(examQuestions.Items); + return new ApiResponse(true, examQuestionDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有考试题目时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == id); + if (assignment == null) + { + return ApiResponse.Error("获取失败"); + } + var result = _mapper.Map(assignment); + return ApiResponse.Success(result: result); + } + catch (Exception ex) + { + return ApiResponse.Error(ex.Message); + } + } + + public async Task AddAsync(ExamDto model) + { + try + { + var exam = _mapper.Map(model); + await _unitOfWork.GetRepository().InsertAsync(exam); + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success("创建成功", exam.Id); + } + return ApiResponse.Error("创建失败"); + } + catch (Exception ex) + { + return ApiResponse.Error(ex.Message); + } + } + + public async Task UpdateAsync(ExamDto model) + { + try + { + var existingExam = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == model.Id); + if (existingExam == null) return ApiResponse.Error("找不到该试卷"); + _mapper.Map(model, existingExam); + _unitOfWork.GetRepository().Update(existingExam); + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success("更新成功"); + } + return ApiResponse.Error("更新失败"); + } + catch (Exception ex) + { + return ApiResponse.Error(ex.Message); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == id); + + if (assignment == null) return ApiResponse.Error("找不到该试卷"); + _unitOfWork.GetRepository().Delete(id); + _unitOfWork.GetRepository().Delete(assignment.ExamStructId); + + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success(); + } + return ApiResponse.Error("删除失败"); + } + catch (Exception ex) + { + return ApiResponse.Error($"内部问题,{ex.Message}, InerException{ex.InnerException}"); + } + } + + public async Task AssignmentToAllClassesAsync(AssigExamToClassDto examToClassDto, Guid TeacherId) + { + try + { + var result = await _classService.GetUserInjoinedClasses(TeacherId); + + if (result.Status == false) return ApiResponse.Error(result.Message); + var userClass = result.Result as UserClassDetailInfoDto; + if (userClass == null || !userClass.UserClassInfos.Any()) return ApiResponse.Error("教师没有管理任何班级"); + + + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == examToClassDto.examId); + if (assignment == null) return ApiResponse.Error("没有找到该试卷"); + + foreach (var classId in userClass.UserClassInfos) + { + await AssignmentToClassAsync(TeacherId, examToClassDto.examId, classId.Id); + } + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success("分配成功"); + } + return ApiResponse.Error("分配失败"); + } + catch (Exception ex) + { + return ApiResponse.Error($"内部错误, {ex.Message}"); + } + } + + public async Task AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto) + { + try + { + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == examToStudentsDto.ExamId); + if (assignment == null) + { + return ApiResponse.Error("获取失败"); + } + if (assignment == null) return ApiResponse.Error("没有找到该试卷"); + + if (examToStudentsDto.StudentIds == null || !examToStudentsDto.StudentIds.Any()) + { + return ApiResponse.Error("没有选择学生"); + } + + foreach (var studentId in examToStudentsDto.StudentIds) + { + var subCount = await _unitOfWork.GetRepository().GetAll( + predicate: su => su.ExamId == examToStudentsDto.ExamId && su.StudentId == studentId + ).CountAsync(); + + var submission = assignment.ConvertToSubmission(studentId, examToStudentsDto.CreaterId, examToStudentsDto.ClassId); + submission.AttemptNumber = (byte)(subCount + 1); + await _unitOfWork.GetRepository().InsertAsync(submission); + } + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success(); + } + return ApiResponse.Error(); + } + catch (Exception ex) + { + return ApiResponse.Error($"内部错误, {ex.Message}"); + } + } + + public async Task AssignmentToClassAsync(Guid TeacherId, Guid examId, Guid classId) + { + try + { + var classStudents = await _classService.GetClassStudentsAsync(classId); + if (!classStudents.Status) return ApiResponse.Error(classStudents.Message); + var userlist = classStudents.Result as IEnumerable; + if (userlist == null || !userlist.Any()) return ApiResponse.Error("班级没有学生"); + + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == examId); + if (assignment == null) return ApiResponse.Error("没有找到该试卷"); + + foreach (var student in userlist) + { + var subCount = await _unitOfWork.GetRepository().GetAll( + predicate: su => su.ExamId == examId && su.StudentId == student.Id + ).CountAsync(); + + var submission = assignment.ConvertToSubmission(student.Id, TeacherId, classId); + submission.AttemptNumber = (byte)(subCount + 1); + await _unitOfWork.GetRepository().InsertAsync(submission); + } + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success("创建成功"); + } + return ApiResponse.Error("创建失败"); + } + catch (Exception ex) + { + return ApiResponse.Error($"内部错误, {ex.Message}"); + } + } + + public async Task GetExamSubmissionDetailInClassAsync(AssigExamToClassDto examToClassDto) + { + try + { + var submissions = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.ExamId == examToClassDto.examId && s.ClassId == examToClassDto.classId); + + if (submissions == null || !submissions.Any()) return ApiResponse.Error("没有找到该试卷"); + + var result = _mapper.Map>(submissions); + + return ApiResponse.Success(result: result); + + + } + catch (Exception ex) + { + return ApiResponse.Error($"内部错误, {ex.Message}"); + } + } + + public async Task GetExamTotalErrorDistributionInClassAsync(AssigExamToClassDto examToClassDto) + { + try + { + var submissions = await _unitOfWork.GetRepository(). + GetAllAsync(predicate: s => s.ExamId == examToClassDto.examId && s.ClassId == examToClassDto.classId); + + if (submissions == null || !submissions.Any()) return ApiResponse.Error("没有找到该试卷"); + + var errorTypeDistribution = submissions + .SelectMany(s => s.SubmissionDetails) + .Where(d => d.IsCorrect == false) + .GroupBy(d => d.ExamQuestion.Type.Name) + .ToDictionary(g => g.Key, g => g.Count()); + + var errorLessonDistribution = submissions + .SelectMany(s => s.SubmissionDetails) + .Where(d => d.IsCorrect == false) + .Where(d => d.ExamQuestion?.Question?.Lesson?.Title != null) + .GroupBy(d => d.ExamQuestion.Question?.Lesson?.Title) + .ToDictionary(g => g.Key, g => g.Count()); + + + var scores = submissions.Select(s => s.OverallGrade); + var result = new ExamDistributionDto(errorTypeDistribution, errorLessonDistribution, scores); + + return ApiResponse.Success(result: result); + + + } + catch (Exception ex) + { + return ApiResponse.Error($"内部错误, {ex.Message}"); + } + } + } + +} diff --git a/TechHelper.Server/Services/Exam/IExamQuestionService.cs b/TechHelper.Server/Services/Exam/IExamQuestionService.cs new file mode 100644 index 0000000..c7c0b72 --- /dev/null +++ b/TechHelper.Server/Services/Exam/IExamQuestionService.cs @@ -0,0 +1,19 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface IExamQuestionService : IBaseService + { + /// + /// ĿҪ֪ʶ,÷ֲ,ѧб + /// + /// + /// + Task GetQuestionDependy(QuesitionDenpendceyRequst request); + + public record QuesitionDenpendceyRequst(Guid ExamQuestioId, Guid ClassId); + + public record QuestionDependecyDto (LessonDto? Lesson, IEnumerable ScoreDistribution, IEnumerable ErrorStudents); + } +} diff --git a/TechHelper.Server/Services/Exam/IExamService.cs b/TechHelper.Server/Services/Exam/IExamService.cs new file mode 100644 index 0000000..1e5e033 --- /dev/null +++ b/TechHelper.Server/Services/Exam/IExamService.cs @@ -0,0 +1,66 @@ +using Entities.DTO; +///* +/// 创建一个新的试卷。 +/// 删除一个试卷。 +/// 修改一个试卷。 +/// 查看试卷详情。 +/// +/// Teacher +/// 获取指定用户的所有试卷预览。 +/// 获取试卷的所有指定 +/// + + +namespace TechHelper.Services.Beta +{ + public interface IExamService : IBaseService + { + + ///// + ///// 获取指定用户的所有试卷预览。 + ///// + //Task GetAllExamPreviewsAsync(Guid userId); + + /// + /// 创建一个新的试卷。 + /// + /// 创建成功的试卷ID + Task CreateExamAsync(ExamDto examDto); + + /// + /// 为指定的班级指派一个试卷 + /// + /// 老师ID + /// 试卷ID + /// 班级ID + /// + Task AssignmentToClassAsync(Guid TeacherId , Guid assignmentId, Guid classId); + + /// + /// 为指定学生指派一个试卷 + /// + /// + /// + /// + Task AssignmentToStudentsAsync(AssigExamToStudentsDto examToStudentsDto); + + + /// + /// 获取该试卷在指定班级指派了多少人 + /// + /// + /// + Task GetExamSubmissionDetailInClassAsync(AssigExamToClassDto examToClassDto); + + + + + Task GetExamTotalErrorDistributionInClassAsync(AssigExamToClassDto examToClassDto); + + + public record ExamDistributionDto(Dictionary ErrorTypeDistribution, + Dictionary ErrorLessonDistribution, + IEnumerable ScoreDistribution); + + } +} diff --git a/TechHelper.Server/Services/ExamService.cs b/TechHelper.Server/Services/ExamService.cs index 21ff45a..9ce594c 100644 --- a/TechHelper.Server/Services/ExamService.cs +++ b/TechHelper.Server/Services/ExamService.cs @@ -1,6 +1,7 @@ using AutoMapper; using Entities.Contracts; using Entities.DTO; +using Entities.DTO.Class; using Microsoft.VisualBasic; using SharedDATA.Api; using TechHelper.Context; @@ -32,7 +33,7 @@ namespace TechHelper.Server.Services try { - Assignment newAssi = _mapper.Map(assignmentDto); + Exam newAssi = _mapper.Map(assignmentDto); await _examRepository.AddAsync(newAssi); @@ -117,11 +118,11 @@ namespace TechHelper.Server.Services { try { - var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == id); + var assignment = await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: a => a.Id == id); if (assignment == null) return ApiResponse.Error("找不到该试卷"); - _unitOfWork.GetRepository().Delete(id); - _unitOfWork.GetRepository().Delete(assignment.ExamStructId); + _unitOfWork.GetRepository().Delete(id); + _unitOfWork.GetRepository().Delete(assignment.ExamStructId); if (await _unitOfWork.SaveChangesAsync() > 0) @@ -170,7 +171,7 @@ namespace TechHelper.Server.Services var cs = cla.Result as ICollection; cs?.ToList().ForEach(async s => { - var subCount = _unitOfWork.GetRepository().GetAll(predicate: su => su.AssignmentId == assignmentId && su.StudentId == s.StudentId); + var subCount = _unitOfWork.GetRepository().GetAll(predicate: su => su.ExamId == assignmentId && su.StudentId == s.StudentId); var submission = assignment.ConvertToSubmission(s.StudentId, TeacherId); submission.AttemptNumber = (byte)(subCount.Count() + 1); @@ -199,7 +200,7 @@ namespace TechHelper.Server.Services examToStudentsDto.StudentIds?.ForEach(async s => { - var subCount = _unitOfWork.GetRepository().GetAll(predicate: su => su.AssignmentId == examToStudentsDto.AssignmentId && su.StudentId == s); + var subCount = _unitOfWork.GetRepository().GetAll(predicate: su => su.ExamId == examToStudentsDto.AssignmentId && su.StudentId == s); var submission = assignment.ConvertToSubmission(s, examToStudentsDto.CreaterId); submission.AttemptNumber = (byte)(subCount.Count() + 1); await _unitOfWork.GetRepository().InsertAsync(submission); diff --git a/TechHelper.Server/Services/ExamType/ExamTypeService.cs b/TechHelper.Server/Services/ExamType/ExamTypeService.cs new file mode 100644 index 0000000..9c9a65c --- /dev/null +++ b/TechHelper.Server/Services/ExamType/ExamTypeService.cs @@ -0,0 +1,175 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services.Beta; + +namespace TechHelper.Services.Beta +{ + public class ExamTypeService : IExamTypeService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public ExamTypeService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var examTypes = await repository.GetPagedListAsync( + predicate: et => et.Name.Contains(query.Search) || et.Description.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var examTypeDtosFiltered = _mapper.Map>(examTypes.Items); + return new ApiResponse(true, examTypeDtosFiltered); + } + else + { + var examTypes = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex, + include: i => i.Include(et => et.Exams) + ); + var examTypeDtos = _mapper.Map>(examTypes.Items); + return new ApiResponse(true, examTypeDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有考试类型时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var examType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: et => et.Id == id, + include: i => i + .Include(et => et.Exams)); + + if (examType == null) + { + return new ApiResponse("考试类型未找到。"); + } + + var examTypeDto = _mapper.Map(examType); + return new ApiResponse(true, examTypeDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取考试类型时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(ExamTypeDto model) + { + try + { + // 检查是否已存在同名考试类型 + var existingExamType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: et => et.Name == model.Name); + + if (existingExamType != null) + { + return new ApiResponse($"考试类型 '{model.Name}' 已存在。"); + } + + var examType = _mapper.Map(model); + await _work.GetRepository().InsertAsync(examType); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, examType.Id); + } + return new ApiResponse("添加考试类型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加考试类型时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(ExamTypeDto model) + { + try + { + var existingExamType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: et => et.Id == model.Id); + + if (existingExamType == null) + { + return new ApiResponse("考试类型未找到。"); + } + + // 检查是否要修改为已存在的考试类型名称(排除当前考试类型) + var examTypeWithSameName = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: et => et.Name == model.Name && et.Id != model.Id); + + if (examTypeWithSameName != null) + { + return new ApiResponse($"考试类型名称 '{model.Name}' 已被其他考试类型使用。"); + } + + _mapper.Map(model, existingExamType); + _work.GetRepository().Update(existingExamType); + + if (await _work.SaveChangesAsync() > 0) + { + var examTypeDto = _mapper.Map(existingExamType); + return new ApiResponse(true, examTypeDto); + } + return new ApiResponse("更新考试类型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新考试类型时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingExamType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: et => et.Id == id, + include: i => i.Include(et => et.Exams)); + + if (existingExamType == null) + { + return new ApiResponse("考试类型未找到。"); + } + + // 检查是否有关联的考试 + if (existingExamType.Exams != null && existingExamType.Exams.Any()) + { + return new ApiResponse("无法删除该考试类型,因为存在关联的考试。"); + } + + _work.GetRepository().Delete(existingExamType); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "考试类型删除成功。"); + } + return new ApiResponse("删除考试类型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除考试类型时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/ExamType/IExamTypeService.cs b/TechHelper.Server/Services/ExamType/IExamTypeService.cs new file mode 100644 index 0000000..a1906d7 --- /dev/null +++ b/TechHelper.Server/Services/ExamType/IExamTypeService.cs @@ -0,0 +1,9 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface IExamTypeService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/Grade/GradeService.cs b/TechHelper.Server/Services/Grade/GradeService.cs new file mode 100644 index 0000000..70125f4 --- /dev/null +++ b/TechHelper.Server/Services/Grade/GradeService.cs @@ -0,0 +1,155 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; + +namespace TechHelper.Services.Beta +{ + public class GradeService : IGradeService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public GradeService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var grades = await repository.GetPagedListAsync( + predicate: g => g.GradeName.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var gradeDtosFiltered = _mapper.Map>(grades); + return new ApiResponse(true, gradeDtosFiltered); + } + else + { + var grades = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var gradeDtos = _mapper.Map>(grades); + return new ApiResponse(true, gradeDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有年级时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var grade = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: g => g.Id == id, + include: i => i.Include(g => g.School)); + + if (grade == null) + { + return new ApiResponse("年级未找到。"); + } + + var gradeDto = _mapper.Map(grade); + return new ApiResponse(true, gradeDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取年级时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(GradeDto model) + { + try + { + // 检查是否已存在相同学校下的同名年级 + var existingGrade = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: g => g.SchoolId == model.SchoolId && g.GradeName == model.GradeName && g.GradeLevel == model.GradeLevel); + + if (existingGrade != null) + { + return new ApiResponse($"在当前学校下,年级 '{model.GradeName}' 已存在。"); + } + + var grade = _mapper.Map(model); + await _work.GetRepository().InsertAsync(grade); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(grade)); + } + return new ApiResponse("添加年级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加年级时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(GradeDto model) + { + try + { + var existingGrade = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: g => g.Id == model.Id); + + if (existingGrade == null) + { + return new ApiResponse("年级未找到。"); + } + + _mapper.Map(model, existingGrade); + _work.GetRepository().Update(existingGrade); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(existingGrade)); + } + return new ApiResponse("更新年级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新年级时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingGrade = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: g => g.Id == id); + + if (existingGrade == null) + { + return new ApiResponse("年级未找到。"); + } + + _work.GetRepository().Delete(existingGrade); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "年级删除成功。"); + } + return new ApiResponse("删除年级失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除年级时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/Grade/IGradeService.cs b/TechHelper.Server/Services/Grade/IGradeService.cs new file mode 100644 index 0000000..8cfd216 --- /dev/null +++ b/TechHelper.Server/Services/Grade/IGradeService.cs @@ -0,0 +1,10 @@ +using Entities.DTO; +using SharedDATA.Api; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface IGradeService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/IBaseService.cs b/TechHelper.Server/Services/IBaseService.cs index 75c69b1..3cd1fad 100644 --- a/TechHelper.Server/Services/IBaseService.cs +++ b/TechHelper.Server/Services/IBaseService.cs @@ -1,4 +1,6 @@ -namespace TechHelper.Services +using Entities.DTO; + +namespace TechHelper.Services { public interface IBaseService { diff --git a/TechHelper.Server/Services/IClassService.cs b/TechHelper.Server/Services/IClassService.cs index c96309f..607741b 100644 --- a/TechHelper.Server/Services/IClassService.cs +++ b/TechHelper.Server/Services/IClassService.cs @@ -1,16 +1,17 @@ using Entities.Contracts; using Entities.DTO; +using Entities.DTO.Class; using System.Net; namespace TechHelper.Services { public interface IClassService : IBaseService { - public Task UserRegister(UserRegistrationToClassDto user); + public Task UserRegister(RegisterUserToClassDto user); public Task GetUserClass(Guid user); // List public Task GetUserClassRole(Guid user); // List public Task GetClassStudents(ClassDto classDto); // Class public Task GetGradeClasses(byte Grade); // Class - Task GetClassStudents(byte grade, byte id); + public Task GetClassStudents(byte Grade, byte Class); } } diff --git a/TechHelper.Server/Services/IUserRegistrationService.cs b/TechHelper.Server/Services/IUserRegistrationService.cs deleted file mode 100644 index 091ef79..0000000 --- a/TechHelper.Server/Services/IUserRegistrationService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Entities.DTO; - -namespace TechHelper.Services -{ - public interface IUserRegistrationService - { - /// - /// 注册新用户,并根据角色关联到班级。 - /// - /// 用户注册数据。 - /// 操作结果。 - Task RegisterNewUserAsync(UserForRegistrationDto registrationDto); - } -} diff --git a/TechHelper.Server/Services/IUserSerivces.cs b/TechHelper.Server/Services/IUserSerivces.cs deleted file mode 100644 index e15e59e..0000000 --- a/TechHelper.Server/Services/IUserSerivces.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Entities.Contracts; -using TechHelper.Services; - -namespace TechHelper.Server.Services -{ - public interface IUserSerivces : IBaseService - { - Task GetStudentDetailInfo(Guid userId); - Task RestoreUserRoleInformation(User user); - Task VerifyUserInformation(Guid userId); - } -} diff --git a/TechHelper.Server/Services/KeyPoint/IKeyPointService.cs b/TechHelper.Server/Services/KeyPoint/IKeyPointService.cs new file mode 100644 index 0000000..4e4e6e8 --- /dev/null +++ b/TechHelper.Server/Services/KeyPoint/IKeyPointService.cs @@ -0,0 +1,10 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface IKeyPointService : IBaseService + { + Task GetKeyPointsByLessonIdAsync(Guid lessonId); + } +} diff --git a/TechHelper.Server/Services/KeyPoint/KeyPointService.cs b/TechHelper.Server/Services/KeyPoint/KeyPointService.cs new file mode 100644 index 0000000..073049e --- /dev/null +++ b/TechHelper.Server/Services/KeyPoint/KeyPointService.cs @@ -0,0 +1,170 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public class KeyPointService : IKeyPointService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public KeyPointService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var keyPoints = await repository.GetPagedListAsync( + predicate: k => k.Key.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var keyPointDtosFiltered = _mapper.Map>(keyPoints); + return new ApiResponse(true, keyPointDtosFiltered); + } + else + { + var keyPoints = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var keyPointDtos = _mapper.Map>(keyPoints); + return new ApiResponse(true, keyPointDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有知识点时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var keyPoint = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: k => k.Id == id); + + if (keyPoint == null) + { + return new ApiResponse("知识点未找到。"); + } + + var keyPointDto = _mapper.Map(keyPoint); + return new ApiResponse(true, keyPointDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取知识点时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(KeyPointDto model) + { + try + { + var existingKeyPoint = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: k => k.Key == model.Key && k.LessonID == model.LessonId); + + if (existingKeyPoint != null) + { + return new ApiResponse($"知识点 '{model.Key}' 在此课程中已存在。"); + } + + var keyPoint = _mapper.Map(model); + await _work.GetRepository().InsertAsync(keyPoint); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(keyPoint)); + } + return new ApiResponse("添加知识点失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加知识点时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(KeyPointDto model) + { + try + { + var existingKeyPoint = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: k => k.Id == model.Id); + + if (existingKeyPoint == null) + { + return new ApiResponse("知识点未找到。"); + } + + _mapper.Map(model, existingKeyPoint); + _work.GetRepository().Update(existingKeyPoint); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(existingKeyPoint)); + } + return new ApiResponse("更新知识点失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新知识点时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingKeyPoint = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: k => k.Id == id); + + if (existingKeyPoint == null) + { + return new ApiResponse("知识点未找到。"); + } + + _work.GetRepository().Delete(existingKeyPoint); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "知识点删除成功。"); + } + return new ApiResponse("删除知识点失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除知识点时发生错误: {ex.Message}"); + } + } + + public async Task GetKeyPointsByLessonIdAsync(Guid lessonId) + { + try + { + var keyPoints = await _work.GetRepository().GetAllAsync( + predicate: k => k.LessonID == lessonId); + + var keyPointDtos = _mapper.Map>(keyPoints); + return new ApiResponse(true, keyPointDtos); + } + catch (Exception ex) + { + return new ApiResponse($"根据课程ID获取知识点时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/Lesson/ILessonService.cs b/TechHelper.Server/Services/Lesson/ILessonService.cs new file mode 100644 index 0000000..a530ce6 --- /dev/null +++ b/TechHelper.Server/Services/Lesson/ILessonService.cs @@ -0,0 +1,11 @@ +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + /// + /// Lesson服务接口 + /// + public interface ILessonService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/Lesson/LessonService.cs b/TechHelper.Server/Services/Lesson/LessonService.cs new file mode 100644 index 0000000..f7928df --- /dev/null +++ b/TechHelper.Server/Services/Lesson/LessonService.cs @@ -0,0 +1,167 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using SharedDATA.Api; + +namespace TechHelper.Services.Beta +{ + /// + /// Lesson服务实现类 + /// + public class LessonService : ILessonService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public LessonService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var lessons = await repository.GetPagedListAsync( + predicate: l => l.Title.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var lessonDtosFiltered = _mapper.Map>(lessons.Items); + return new ApiResponse(true, lessonDtosFiltered); + } + else + { + var lessons = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var lessonDtos = _mapper.Map>(lessons.Items); + return new ApiResponse(true, lessonDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有课程时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var lesson = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: l => l.Id == id); + + if (lesson == null) + { + return new ApiResponse("课程未找到。"); + } + + var lessonDto = _mapper.Map(lesson); + return new ApiResponse(true, lessonDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取课程时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(LessonDto model) + { + try + { + // 检查是否已存在同名课程 + var existingLesson = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: l => l.Title == model.Title && l.TextbookID == model.TextBookId); + + if (existingLesson != null) + { + return new ApiResponse($"课程 '{model.Title}' 在该教材中已存在。"); + } + + var lesson = _mapper.Map(model); + + await _work.GetRepository().InsertAsync(lesson); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, lesson.Id); + } + return new ApiResponse("添加课程失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加课程时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(LessonDto model) + { + try + { + var existingLesson = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: l => l.Id == model.Id); + + if (existingLesson == null) + { + return new ApiResponse("课程未找到。"); + } + + // 检查是否要修改为已存在的课程名称(排除当前课程) + var lessonWithSameName = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: l => l.Title == model.Title && l.TextbookID == model.TextBookId && l.Id != model.Id); + + if (lessonWithSameName != null) + { + return new ApiResponse($"课程名称 '{model.Title}' 在该教材中已被其他课程使用。"); + } + + _mapper.Map(model, existingLesson); + _work.GetRepository().Update(existingLesson); + + if (await _work.SaveChangesAsync() > 0) + { + var lessonDto = _mapper.Map(existingLesson); + return new ApiResponse(true, lessonDto); + } + return new ApiResponse("更新课程失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新课程时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingLesson = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: l => l.Id == id); + + if (existingLesson == null) + { + return new ApiResponse("课程未找到。"); + } + + _work.GetRepository().Delete(existingLesson); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "课程删除成功。"); + } + return new ApiResponse("删除课程失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除课程时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/QueryParameter.cs b/TechHelper.Server/Services/QueryParameter.cs index 2ce9af1..da50e9a 100644 --- a/TechHelper.Server/Services/QueryParameter.cs +++ b/TechHelper.Server/Services/QueryParameter.cs @@ -2,8 +2,8 @@ { public class QueryParameter { - public int PageIndex { get; set; } - public int PageSize { get; set; } - public string Search { get; set; } + public int PageIndex { get; set; } = 0; + public int PageSize { get; set; } = 10; + public string? Search { get; set; } } } \ No newline at end of file diff --git a/TechHelper.Server/Services/Question/IQuestionService.cs b/TechHelper.Server/Services/Question/IQuestionService.cs new file mode 100644 index 0000000..6d2df76 --- /dev/null +++ b/TechHelper.Server/Services/Question/IQuestionService.cs @@ -0,0 +1,11 @@ +using Entities.Contracts; +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + public interface IQuestionService : IBaseService + { + Task FindByTitle(string title); + Task CheckTitlesExistence(IEnumerable titles); + } +} diff --git a/TechHelper.Server/Services/Question/QuestionService.cs b/TechHelper.Server/Services/Question/QuestionService.cs new file mode 100644 index 0000000..510d026 --- /dev/null +++ b/TechHelper.Server/Services/Question/QuestionService.cs @@ -0,0 +1,302 @@ +using AutoMapper; +using Entities.Contracts; +using SharedDATA.Api; +using System.Linq.Expressions; +using System.Linq; +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + public class QuestionService : IQuestionService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + private readonly IExamService _examService; + + public QuestionService(IUnitOfWork work, IMapper mapper, IExamService examService) + { + _work = work; + _mapper = mapper; + _examService = examService; + } + + #region CRUD Operations + + /// + /// 创建新题目 + /// + /// 题目DTO + /// API响应结果 + public async Task AddAsync(QuestionDto model) + { + try + { + // 业务逻辑校验:检查题目是否已存在 + var existingQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Title == model.Title && !q.IsDeleted + ); + + if (existingQuestion != null) + { + return ApiResponse.Error($"题目 '{model.Title}' 已存在,请勿重复添加。"); + } + + var newQuestion = _mapper.Map(model); + + // 插入数据 + await _work.GetRepository().InsertAsync(newQuestion); + await _work.SaveChangesAsync(); + + return ApiResponse.Success("题目添加成功。", newQuestion); + } + catch (Exception ex) + { + return ApiResponse.Error($"添加题目失败: {ex.Message}"); + } + } + + /// + /// 根据ID获取题目 + /// + /// 题目ID + /// API响应结果 + public async Task GetAsync(Guid id) + { + try + { + var question = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Id == id && !q.IsDeleted + ); + + if (question == null) + { + return ApiResponse.Error($"找不到 ID 为 {id} 的题目。"); + } + + return ApiResponse.Success(result: question); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取题目时发生错误: {ex.Message}"); + } + } + + /// + /// 获取所有题目(支持分页和搜索) + /// + /// 查询参数 + /// API响应结果 + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var questions = await repository.GetPagedListAsync( + predicate: q => q.Title.Contains(query.Search) && !q.IsDeleted, + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var questionDtosFiltered = _mapper.Map>(questions.Items); + return new ApiResponse(true, questionDtosFiltered); + } + else + { + var questions = await repository.GetPagedListAsync( + predicate: q => !q.IsDeleted, + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var questionDtos = _mapper.Map>(questions.Items); + return new ApiResponse(true, questionDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有题目时发生错误: {ex.Message}"); + } + } + + /// + /// 更新题目信息 + /// + /// 题目DTO + /// API响应结果 + public async Task UpdateAsync(QuestionDto model) + { + try + { + // 检查题目是否存在 + var existingQuestion = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Id == model.Id && !q.IsDeleted + ); + + if (existingQuestion == null) + { + return ApiResponse.Error($"找不到 ID 为 {model.Id} 的题目,无法更新。"); + } + + // 检查题目文本是否与其他题目重复 + var duplicateCheck = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Id != model.Id && q.Title == model.Title && !q.IsDeleted + ); + + if (duplicateCheck != null) + { + return ApiResponse.Error($"题目文本 '{model.Title}' 已被其他题目占用,请修改。"); + } + + // 使用mapper更新实体属性,保留系统字段 + _mapper.Map(model, existingQuestion); + existingQuestion.UpdatedAt = DateTime.UtcNow; + + // 更新数据 + _work.GetRepository().Update(existingQuestion); + await _work.SaveChangesAsync(); + + return ApiResponse.Success("题目更新成功。", existingQuestion); + } + catch (Exception ex) + { + return ApiResponse.Error($"更新题目失败: {ex.Message}"); + } + } + + /// + /// 删除题目(软删除) + /// + /// 题目ID + /// API响应结果 + public async Task DeleteAsync(Guid id) + { + try + { + var questionToDelete = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Id == id && !q.IsDeleted + ); + + if (questionToDelete == null) + { + return ApiResponse.Error($"找不到 ID 为 {id} 的题目,或者该题目已被删除。"); + } + + // 软删除 + questionToDelete.IsDeleted = true; + questionToDelete.UpdatedAt = DateTime.UtcNow; + + _work.GetRepository().Update(questionToDelete); + await _work.SaveChangesAsync(); + + return ApiResponse.Success($"ID 为 {id} 的题目已成功删除 (软删除)。"); + } + catch (Exception ex) + { + return ApiResponse.Error($"删除题目时发生错误: {ex.Message}"); + } + } + + #endregion + + #region Business Logic Methods + + /// + /// 根据标题查找题目 + /// + /// 题目标题 + /// API响应结果 + public async Task FindByTitle(string title) + { + try + { + var question = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: q => q.Title == title && !q.IsDeleted + ); + + if (question == null) + { + return ApiResponse.Error($"未找到题目 '{title}'。"); + } + + return ApiResponse.Success(result: question); + } + catch (Exception ex) + { + return ApiResponse.Error($"查找题目时出现问题: {ex.Message}"); + } + } + + /// + /// 批量检查题目标题是否存在 + /// + /// 题目标题集合 + /// API响应结果 + public async Task CheckTitlesExistence(IEnumerable titles) + { + try + { + if (titles == null || !titles.Any()) + { + return ApiResponse.Success("未指定查询的题目文本,返回空结果。", new Dictionary()); + } + + var distinctTitles = titles.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); + + var existingQuestions = await _work.GetRepository().GetAllAsync( + predicate: q => distinctTitles.Contains(q.Title) && !q.IsDeleted + ); + + var existingQuestionTexts = new HashSet( + existingQuestions.Select(q => q.Title), + StringComparer.OrdinalIgnoreCase + ); + + var resultDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var title in titles) + { + resultDictionary[title] = existingQuestionTexts.Contains(title); + } + + return ApiResponse.Success(result: resultDictionary); + } + catch (Exception ex) + { + return ApiResponse.Error($"批量查找题目存在性时出现问题: {ex.Message}"); + } + } + + #endregion + } + + /// + /// 表达式构建器扩展类 + /// + public static class PredicateBuilder + { + public static Expression> And( + this Expression> first, + Expression> second) + { + var invokedExpr = Expression.Invoke(second, first.Parameters.Cast()); + return Expression.Lambda>( + Expression.AndAlso(first.Body, invokedExpr), + first.Parameters + ); + } + + public static Expression> Or( + this Expression> first, + Expression> second) + { + var invokedExpr = Expression.Invoke(second, first.Parameters.Cast()); + return Expression.Lambda>( + Expression.OrElse(first.Body, invokedExpr), + first.Parameters + ); + } + + public static Expression> True() => f => true; + public static Expression> False() => f => false; + } +} diff --git a/TechHelper.Server/Services/QuestionType/IQuestionTypeService.cs b/TechHelper.Server/Services/QuestionType/IQuestionTypeService.cs new file mode 100644 index 0000000..476532a --- /dev/null +++ b/TechHelper.Server/Services/QuestionType/IQuestionTypeService.cs @@ -0,0 +1,9 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface IQuestionTypeService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/QuestionType/QuestionTypeService.cs b/TechHelper.Server/Services/QuestionType/QuestionTypeService.cs new file mode 100644 index 0000000..4b1dcdc --- /dev/null +++ b/TechHelper.Server/Services/QuestionType/QuestionTypeService.cs @@ -0,0 +1,202 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services.Beta; + +namespace TechHelper.Services.Beta +{ + public class QuestionTypeService : IQuestionTypeService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public QuestionTypeService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var questionTypes = await repository.GetPagedListAsync( + predicate: qt => qt.Name.Contains(query.Search) || qt.Description.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var questionTypeDtosFiltered = _mapper.Map>(questionTypes.Items); + return new ApiResponse(true, questionTypeDtosFiltered); + } + else + { + var questionTypes = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex, + include: i => i.Include(qt => qt.Subject) + ); + var questionTypeDtos = _mapper.Map>(questionTypes.Items); + return new ApiResponse(true, questionTypeDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有题型时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var questionType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: qt => qt.Id == id, + include: i => i + .Include(qt => qt.Subject) + .Include(qt => qt.Questions)); + + if (questionType == null) + { + return new ApiResponse("题型未找到。"); + } + + var questionTypeDto = _mapper.Map(questionType); + return new ApiResponse(true, questionTypeDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取题型时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(QuestionTypeDto model) + { + try + { + var QuestionTypeExists = await _work.GetRepository().GetFirstOrDefaultAsync(predicate: qt => qt.Id == model.Id); + if (QuestionTypeExists != null) + { + if (QuestionTypeExists.Name == model.Name && QuestionTypeExists.SubjectId == model.SubjectId) + return new ApiResponse("题型已存在。"); + else + return new ApiResponse($"主键已被 '{QuestionTypeExists.Name}' 题型使用。"); + } + // 检查科目是否存在 + var subjectExists = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == model.SubjectId); + + if (subjectExists == null) + { + return new ApiResponse("指定的科目不存在。"); + } + + // 检查是否已存在相同科目下的同名题型 + var existingQuestionType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: qt => qt.SubjectId == model.SubjectId && qt.Name == model.Name); + + if (existingQuestionType != null) + { + return new ApiResponse($"在当前科目下,题型 '{model.Name}' 已存在。"); + } + + var questionType = _mapper.Map(model); + await _work.GetRepository().InsertAsync(questionType); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, questionType.Id); + } + return new ApiResponse("添加题型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加题型时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(QuestionTypeDto model) + { + try + { + var existingQuestionType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: qt => qt.Id == model.Id); + + if (existingQuestionType == null) + { + return new ApiResponse("题型未找到。"); + } + + // 检查科目是否存在 + var subjectExists = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == model.SubjectId); + + if (subjectExists == null) + { + return new ApiResponse("指定的科目不存在。"); + } + + // 检查是否要修改为已存在的题型名称(排除当前题型) + var questionTypeWithSameName = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: qt => qt.Name == model.Name && qt.Id != model.Id && qt.SubjectId == model.SubjectId); + + if (questionTypeWithSameName != null) + { + return new ApiResponse($"在当前科目下,题型名称 '{model.Name}' 已被其他题型使用。"); + } + + _mapper.Map(model, existingQuestionType); + _work.GetRepository().Update(existingQuestionType); + + if (await _work.SaveChangesAsync() > 0) + { + var questionTypeDto = _mapper.Map(existingQuestionType); + return new ApiResponse(true, questionTypeDto); + } + return new ApiResponse("更新题型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新题型时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingQuestionType = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: qt => qt.Id == id, + include: i => i.Include(qt => qt.Questions)); + + if (existingQuestionType == null) + { + return new ApiResponse("题型未找到。"); + } + + // 检查是否有关联的题目 + if (existingQuestionType.Questions != null && existingQuestionType.Questions.Any()) + { + return new ApiResponse("无法删除该题型,因为存在关联的题目。"); + } + + _work.GetRepository().Delete(existingQuestionType); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "题型删除成功。"); + } + return new ApiResponse("删除题型失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除题型时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/School/ISchoolService.cs b/TechHelper.Server/Services/School/ISchoolService.cs new file mode 100644 index 0000000..f20456e --- /dev/null +++ b/TechHelper.Server/Services/School/ISchoolService.cs @@ -0,0 +1,9 @@ +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + public interface ISchoolService : IBaseService + { + Task GetSchoolByNameAsync(string schoolName); + } +} diff --git a/TechHelper.Server/Services/School/SchoolService.cs b/TechHelper.Server/Services/School/SchoolService.cs new file mode 100644 index 0000000..a77b9a3 --- /dev/null +++ b/TechHelper.Server/Services/School/SchoolService.cs @@ -0,0 +1,179 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; + +namespace TechHelper.Services.Beta +{ + public class SchoolService : ISchoolService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public SchoolService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var schools = await repository.GetPagedListAsync( + predicate: s => s.SchoolName.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var schoolDtosFiltered = _mapper.Map>(schools.Items); + return new ApiResponse(true, schoolDtosFiltered); + } + else + { + var schools = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var schoolDtos = _mapper.Map>(schools.Items); + return new ApiResponse(true, schoolDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有学校时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var school = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == id, + include: i + => i.Include(s => s.Grades)); + + if (school == null) + { + return new ApiResponse("学校未找到。"); + } + + var schoolDto = _mapper.Map(school); + return new ApiResponse(true, schoolDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取学校时发生错误: {ex.Message}"); + } + } + + public async Task GetSchoolByNameAsync(string schoolName) + { + try + { + var school = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.SchoolName == schoolName, + include: i + =>i.Include(s => s.Grades)); + + if (school == null) + { + return new ApiResponse("学校未找到。"); + } + + var schoolDto = _mapper.Map(school); + return new ApiResponse(true, schoolDto); + } + catch (Exception ex) + { + return new ApiResponse($"根据名称获取学校时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(SchoolDto model) + { + try + { + // 检查是否已存在同名学校 + var existingSchool = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.SchoolName == model.SchoolName); + + if (existingSchool != null) + { + return new ApiResponse($"学校 '{model.SchoolName}' 已存在。"); + } + + var school = _mapper.Map(model); + await _work.GetRepository().InsertAsync(school); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(school)); + } + return new ApiResponse("添加学校失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加学校时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(SchoolDto model) + { + try + { + var existingSchool = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == model.Id); + + if (existingSchool == null) + { + return new ApiResponse("学校未找到。"); + } + + _mapper.Map(model, existingSchool); + _work.GetRepository().Update(existingSchool); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, _mapper.Map(existingSchool)); + } + return new ApiResponse("更新学校失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新学校时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingSchool = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == id); + + if (existingSchool == null) + { + return new ApiResponse("学校未找到。"); + } + + _work.GetRepository().Delete(existingSchool); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "学校删除成功。"); + } + return new ApiResponse("删除学校失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除学校时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/StudentSubmissionDetailService.cs b/TechHelper.Server/Services/StudentSubmissionDetailService.cs index d671591..29cdaf7 100644 --- a/TechHelper.Server/Services/StudentSubmissionDetailService.cs +++ b/TechHelper.Server/Services/StudentSubmissionDetailService.cs @@ -33,7 +33,7 @@ namespace TechHelper.Server.Services // 获取submission基本信息 var submission = await _unitOfWork.GetRepository() .GetAll(s => s.Id == submissionId) - .Include(s => s.Assignment) + .Include(s => s.Exam) .ThenInclude(a => a.Creator) .FirstOrDefaultAsync(); @@ -42,7 +42,7 @@ namespace TechHelper.Server.Services return ApiResponse.Error("未找到指定的提交记录"); } - var assignment = await examService.GetAsync(submission.AssignmentId); + var assignment = await examService.GetAsync(submission.ExamId); if (assignment == null) { return ApiResponse.Error("未找到指定的作业"); @@ -51,7 +51,7 @@ namespace TechHelper.Server.Services // 获取所有提交详情 var submissionDetails = await _unitOfWork.GetRepository() .GetAll(sd => sd.SubmissionId == submissionId) - .Include(sd => sd.AssignmentQuestion) + .Include(sd => sd.ExamQuestion) .ThenInclude(aq => aq.Question) .ThenInclude(q => q.Lesson) .ThenInclude(q => q.KeyPoints) @@ -59,7 +59,7 @@ namespace TechHelper.Server.Services // 获取同作业的所有提交用于排名和成绩分布 var allSubmissions = await _unitOfWork.GetRepository() - .GetAll(s => s.AssignmentId == submission.AssignmentId) + .GetAll(s => s.ExamId == submission.ExamId) .ToListAsync(); // 映射基本信息 @@ -67,11 +67,11 @@ namespace TechHelper.Server.Services result.Assignment = assignment.Result as AssignmentDto ?? new AssignmentDto(); var errorQuestion = submissionDetails - .Where(sd => sd.IsCorrect == false && sd.AssignmentQuestion?.StructType == AssignmentStructType.Question && sd.AssignmentQuestion?.Question != null) + .Where(sd => sd.IsCorrect == false && sd.ExamQuestion?.StructType == AssignmentStructType.Question && sd.ExamQuestion?.Question != null) .ToList(); // 计算基础统计 - result.TotalQuestions = submissionDetails.Select(x => x.AssignmentQuestion.StructType == AssignmentStructType.Question && x.AssignmentQuestion?.Question != null).Count(); + result.TotalQuestions = submissionDetails.Select(x => x.ExamQuestion.StructType == AssignmentStructType.Question && x.ExamQuestion?.Question != null).Count(); result.ErrorCount = errorQuestion.Count; result.CorrectCount = result.TotalQuestions - result.ErrorCount; result.AccuracyRate = result.TotalQuestions > 0 ? @@ -79,12 +79,12 @@ namespace TechHelper.Server.Services // 计算错误类型分布 - 只获取题目类型的错误 result.ErrorTypeDistribution = errorQuestion - .GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString()) + .GroupBy(sd => sd.ExamQuestion.Question.Type.ToString()) .ToDictionary(g => g.Key, g => g.Count()); ; // 计算错误类型成绩分布 - 只获取题目类型的错误 result.ErrorTypeScoreDistribution = errorQuestion - .GroupBy(sd => sd.AssignmentQuestion.Question.Type.ToString()) + .GroupBy(sd => sd.ExamQuestion.Question.Type.ToString()) .ToDictionary(g => g.Key, g => g.Sum(sd => sd.PointsAwarded ?? 0)); // 计算成绩排名 @@ -101,14 +101,14 @@ namespace TechHelper.Server.Services // 计算课文错误分布 result.LessonErrorDistribution = errorQuestion - .Where(eq => eq.AssignmentQuestion.Question.Lesson != null) - .GroupBy(sd => sd.AssignmentQuestion.Question.Lesson.Title) + .Where(eq => eq.ExamQuestion.Question.Lesson != null) + .GroupBy(sd => sd.ExamQuestion.Question.Lesson.Title) .ToDictionary(g => g.Key, g => g.Count()); // 计算关键点错误分布 result.KeyPointErrorDistribution = errorQuestion - .Where(eq => eq.AssignmentQuestion.Question.Lesson != null) - .GroupBy(sd => sd.AssignmentQuestion.Question.KeyPoint.Key) + .Where(eq => eq.ExamQuestion.Question.Lesson != null) + .GroupBy(sd => sd.ExamQuestion.Question.KeyPoint.Key) .ToDictionary(g => g.Key, g => g.Count()); return ApiResponse.Success(result: result); @@ -126,9 +126,9 @@ namespace TechHelper.Server.Services public void SetBCorrect(AssignmentQuestionDto assignmentQuestion, List submissionDetails) { - var sd = submissionDetails.FirstOrDefault(x => x.AssignmentQuestionId == assignmentQuestion.Id); + var sd = submissionDetails.FirstOrDefault(x => x.ExamQuestionId == assignmentQuestion.Id); if (sd != null) - assignmentQuestion.BCorrect = sd.AssignmentQuestion.BCorrect; + assignmentQuestion.BCorrect = sd.ExamQuestion.BCorrect; else assignmentQuestion.BCorrect = false; diff --git a/TechHelper.Server/Services/StudentSubmissionService.cs b/TechHelper.Server/Services/StudentSubmissionService.cs index 601ba45..d5f3ff7 100644 --- a/TechHelper.Server/Services/StudentSubmissionService.cs +++ b/TechHelper.Server/Services/StudentSubmissionService.cs @@ -15,14 +15,14 @@ namespace TechHelper.Server.Services private readonly IUnitOfWork _unitOfWork; private readonly IMapper _mapper; private readonly IRepository _submissionRepository; - private readonly IRepository _assignmentRepository; + private readonly IRepository _assignmentRepository; private readonly IRepository _userRepository; public StudentSubmissionService( IUnitOfWork unitOfWork, IMapper mapper, IRepository submissionRepository, - IRepository assignmentRepository, + IRepository assignmentRepository, IRepository userRepository) { _unitOfWork = unitOfWork; @@ -38,7 +38,7 @@ namespace TechHelper.Server.Services { var submissions = await _submissionRepository .GetAll(s => s.StudentId == studentId) - .Include(s => s.Assignment) + .Include(s => s.Exam) .ThenInclude(a => a.Creator) .OrderByDescending(s => s.SubmissionTime) .ToListAsync(); @@ -50,12 +50,12 @@ namespace TechHelper.Server.Services var summary = new StudentSubmissionSummaryDto { Id = submission.Id, - AssignmentName = submission.Assignment?.Title ?? "未知作业", + AssignmentName = submission.Exam?.Title ?? "未知作业", ErrorCount = await CalculateErrorCountAsync(submission.Id), CreatedDate = submission.SubmissionTime, Score = (int)submission.OverallGrade, - TotalQuestions = submission.Assignment?.TotalQuestions ?? 0, - StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师", + TotalQuestions = submission.Exam?.TotalQuestions ?? 0, + StudentName = submission.Exam?.Creator?.UserName ?? "未知老师", Status = submission.Status.ToString() }; result.Add(summary); @@ -79,7 +79,7 @@ namespace TechHelper.Server.Services var submissions = await _submissionRepository .GetAll(s => s.StudentId == studentId) - .Include(s => s.Assignment) + .Include(s => s.Exam) .ThenInclude(a => a.Creator) .OrderByDescending(s => s.SubmissionTime) .Skip((pageNumber - 1) * pageSize) @@ -93,12 +93,12 @@ namespace TechHelper.Server.Services var summary = new StudentSubmissionSummaryDto { Id = submission.Id, - AssignmentName = submission.Assignment?.Title ?? "未知作业", + AssignmentName = submission.Exam?.Title ?? "未知作业", ErrorCount = await CalculateErrorCountAsync(submission.Id), CreatedDate = submission.SubmissionTime, Score = submission.OverallGrade, - TotalQuestions = submission.Assignment?.TotalQuestions ?? 0, - StudentName = submission.Assignment?.Creator?.UserName ?? "未知老师", + TotalQuestions = submission.Exam?.TotalQuestions ?? 0, + StudentName = submission.Exam?.Creator?.UserName ?? "未知老师", Status = submission.Status.ToString() }; result.Add(summary); diff --git a/TechHelper.Server/Services/Subject/ISubjectService.cs b/TechHelper.Server/Services/Subject/ISubjectService.cs new file mode 100644 index 0000000..e297d35 --- /dev/null +++ b/TechHelper.Server/Services/Subject/ISubjectService.cs @@ -0,0 +1,9 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + public interface ISubjectService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/Subject/SubjectService.cs b/TechHelper.Server/Services/Subject/SubjectService.cs new file mode 100644 index 0000000..84b285c --- /dev/null +++ b/TechHelper.Server/Services/Subject/SubjectService.cs @@ -0,0 +1,170 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services.Beta; + +namespace TechHelper.Services.Beta +{ + public class SubjectService : ISubjectService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public SubjectService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var subjects = await repository.GetPagedListAsync( + predicate: s => s.Name.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var subjectDtosFiltered = _mapper.Map>(subjects.Items); + return new ApiResponse(true, subjectDtosFiltered); + } + else + { + var subjects = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var subjectDtos = _mapper.Map>(subjects.Items); + return new ApiResponse(true, subjectDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有科目时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var subject = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == id, + include: i => i + .Include(s => s.QuestionTypes) + .Include(s => s.Questions) + .Include(s => s.SubjectTeachers)); + + if (subject == null) + { + return new ApiResponse("科目未找到。"); + } + + var subjectDto = _mapper.Map(subject); + return new ApiResponse(true, subjectDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取科目时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(SubjectDto model) + { + try + { + // 检查是否已存在同名科目 + var existingSubject = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Name == model.Name); + + if (existingSubject != null) + { + return new ApiResponse($"科目 '{model.Name}' 已存在。"); + } + + var subject = _mapper.Map(model); + + await _work.GetRepository().InsertAsync(subject); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, subject.Id); + } + return new ApiResponse("添加科目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加科目时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(SubjectDto model) + { + try + { + var existingSubject = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == model.Id); + + if (existingSubject == null) + { + return new ApiResponse("科目未找到。"); + } + + // 检查是否要修改为已存在的科目名称(排除当前科目) + var subjectWithSameName = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Name == model.Name && s.Id != model.Id); + + if (subjectWithSameName != null) + { + return new ApiResponse($"科目名称 '{model.Name}' 已被其他科目使用。"); + } + + _mapper.Map(model, existingSubject); + _work.GetRepository().Update(existingSubject); + + if (await _work.SaveChangesAsync() > 0) + { + var subjectDto = _mapper.Map(existingSubject); + return new ApiResponse(true, subjectDto); + } + return new ApiResponse("更新科目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新科目时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingSubject = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: s => s.Id == id); + + if (existingSubject == null) + { + return new ApiResponse("科目未找到。"); + } + + _work.GetRepository().Delete(existingSubject); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "科目删除成功。"); + } + return new ApiResponse("删除科目失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除科目时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/Submission/ISubmissionDetailService.cs b/TechHelper.Server/Services/Submission/ISubmissionDetailService.cs new file mode 100644 index 0000000..01a8f4e --- /dev/null +++ b/TechHelper.Server/Services/Submission/ISubmissionDetailService.cs @@ -0,0 +1,82 @@ +using Entities.Contracts; +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + /// + /// 提交详情服务接口(Beta版本) + /// 提供提交详情相关的业务逻辑操作 + /// + public interface ISubmissionDetailService : IBaseService + { + /// + /// 获取提交详情列表 + /// + /// 提交ID + /// 提交详情列表 + Task GetBySubmissionIdAsync(Guid submissionId); + + /// + /// 获取学生的提交详情 + /// + /// 学生ID + /// 考试ID + /// 提交详情列表 + Task GetByStudentAndExamAsync(Guid studentId, Guid examId); + + /// + /// 批量创建提交详情 + /// + /// 提交ID + /// 提交详情列表 + /// 创建结果 + Task BatchCreateAsync(Guid submissionId, List details); + + /// + /// 批量更新提交详情 + /// + /// 提交详情列表 + /// 更新结果 + Task BatchUpdateAsync(List details); + + /// + /// 更新提交详情评分 + /// + /// 提交详情ID + /// 分数 + /// 反馈 + /// 更新结果 + Task UpdateScoreAsync(Guid detailId, float? points, string? feedback); + + /// + /// 获取错题详情 + /// + /// 学生ID + /// 考试ID + /// 错题详情列表 + Task GetErrorDetailsAsync(Guid studentId, Guid examId); + + /// + /// 获取正确题详情 + /// + /// 学生ID + /// 考试ID + /// 正确题详情列表 + Task GetCorrectDetailsAsync(Guid studentId, Guid examId); + + /// + /// 获取未批改的提交详情 + /// + /// 教师ID + /// 未批改的提交详情列表 + Task GetUngradedDetailsAsync(Guid teacherId); + + /// + /// 批量更新提交详情状态 + /// + /// 提交ID + /// 状态 + /// 更新结果 + Task UpdateStatusAsync(Guid submissionId, SubmissionStatus status); + } +} diff --git a/TechHelper.Server/Services/Submission/ISubmissionService.cs b/TechHelper.Server/Services/Submission/ISubmissionService.cs new file mode 100644 index 0000000..ae7706b --- /dev/null +++ b/TechHelper.Server/Services/Submission/ISubmissionService.cs @@ -0,0 +1,86 @@ +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + /// + /// 提交服务接口(Beta版本) + /// 提供提交相关的业务逻辑操作 + /// + public interface ISubmissionService : IBaseService + { + /// + /// 获取用户的错题列表 + /// + /// 用户ID + /// 错题列表 + Task GetAllErrorQuestionsAsync(Guid userId); + + /// + /// 获取指定作业的错题列表 + /// + /// 作业ID + /// 用户ID + /// 错题列表 + Task GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId); + + /// + /// 获取错题类型分布 + /// + /// 作业ID + /// 用户ID + /// 错题类型分布 + Task GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId); + + /// + /// 获取所有错题类型分布 + /// + /// 作业ID + /// 用户ID + /// 错题类型分布 + Task GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId); + + /// + /// 获取作业中所有学生的错题情况 + /// + /// 作业ID + /// 教师ID + /// 学生错题情况 + Task GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId); + + /// + /// 获取出现错题的学生列表 + /// + /// 作业题目ID + /// 错题学生列表 + Task GetQuestionErrorStudents(Guid assignmentQuestionId); + + /// + /// 判断是否已经存在提交记录 + /// + /// 作业ID + /// 学生ID + /// 提交记录数量 + Task IsHasSubmissionAsync(Guid assignmentId, Guid studentId); + + /// + /// 获取学生提交摘要 + /// + /// 用户ID + /// 学生提交摘要列表 + Task GetStudentSubmissionSummariesAsync(Guid userId); + + /// + /// 获取学生提交详情 + /// + /// 提交ID + /// 学生提交详情 + Task GetStudentSubmissionDetailAsync(Guid submissionId); + + /// + /// 批改的试卷 + /// + /// + /// + Task GradeExam(SubmissionTeacherUpdateDto model); + } +} diff --git a/TechHelper.Server/Services/Submission/SubmissionDetailService.cs b/TechHelper.Server/Services/Submission/SubmissionDetailService.cs new file mode 100644 index 0000000..befcdbd --- /dev/null +++ b/TechHelper.Server/Services/Submission/SubmissionDetailService.cs @@ -0,0 +1,457 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using SharedDATA.Context; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + /// + /// 提交详情服务实现(Beta版本) + /// 实现提交详情相关的业务逻辑操作 + /// + public class SubmissionDetailService : ISubmissionDetailService + { + private readonly IUnitOfWork _unitOfWork; + private readonly IMapper _mapper; + private readonly IRepository _submissionDetailRepository; + private readonly IRepository _submissionRepository; + + /// + /// 初始化提交详情服务 + /// + /// AutoMapper实例 + /// 工作单元 + public SubmissionDetailService(IMapper mapper, IUnitOfWork unitOfWork) + { + _mapper = mapper; + _unitOfWork = unitOfWork; + _submissionDetailRepository = _unitOfWork.GetRepository(); + _submissionRepository = _unitOfWork.GetRepository(); + } + + #region 基本CRUD操作 + + /// + /// 获取所有提交详情 + /// + /// 查询参数 + /// 提交详情列表 + public async Task GetAllAsync(QueryParameter query) + { + try + { + var pagedDetails = await _submissionDetailRepository.GetPagedListAsync( + pageIndex: query.PageIndex, + pageSize: query.PageSize, + orderBy: sd => sd.OrderByDescending(sd => sd.CreatedAt), + predicate: sd => !sd.IsDeleted, + include: i => i.Include(sd => sd.Student) + .Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(pagedDetails.Items); + + return ApiResponse.Success("获取所有提交详情成功。", new PagedList + { + PageIndex = pagedDetails.PageIndex, + PageSize = pagedDetails.PageSize, + TotalCount = pagedDetails.TotalCount, + TotalPages = pagedDetails.TotalPages, + Items = detailDtos + }); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取所有提交详情失败: {ex.Message}"); + } + } + + /// + /// 根据ID获取提交详情 + /// + /// 提交详情ID + /// 提交详情详情 + public async Task GetAsync(Guid id) + { + try + { + var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync( + predicate: sd => sd.Id == id && !sd.IsDeleted, + include: i => i.Include(sd => sd.Student) + .Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + if (detail == null) + { + return ApiResponse.Error("未找到提交详情。", 404); + } + + var detailDto = _mapper.Map(detail); + return ApiResponse.Success("获取提交详情成功。", detailDto); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取提交详情失败: {ex.Message}"); + } + } + + /// + /// 创建提交详情 + /// + /// 提交详情数据传输对象 + /// 创建结果 + public async Task AddAsync(SubmissionDetailDto model) + { + try + { + if(await _unitOfWork.GetRepository().GetFirstOrDefaultAsync(predicate: sd => sd.Id == model.Id ) != null) + { + return ApiResponse.Error("提交详情已存在。", 400); + } + + var detail = _mapper.Map(model); + detail.CreatedAt = DateTime.Now; + detail.UpdatedAt = DateTime.Now; + detail.IsDeleted = false; + + await _submissionDetailRepository.InsertAsync(detail); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(detail); + return ApiResponse.Success("创建提交详情成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"创建提交详情失败: {ex.Message}"); + } + } + + /// + /// 更新提交详情 + /// + /// 提交详情数据传输对象 + /// 更新结果 + public async Task UpdateAsync(SubmissionDetailDto model) + { + try + { + var existingDetail = await _submissionDetailRepository.GetFirstOrDefaultAsync(predicate: sd => sd.Id == model.Id && !sd.IsDeleted); + if (existingDetail == null) + { + return ApiResponse.Error("未找到要更新的提交详情。", 404); + } + + _mapper.Map(model, existingDetail); + existingDetail.UpdatedAt = DateTime.Now; + _submissionDetailRepository.Update(existingDetail); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(existingDetail); + return ApiResponse.Success("更新提交详情成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"更新提交详情失败: {ex.Message}"); + } + } + + /// + /// 删除提交详情 + /// + /// 提交详情ID + /// 删除结果 + public async Task DeleteAsync(Guid id) + { + try + { + var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync(predicate: sd => sd.Id == id && !sd.IsDeleted); + if (detail == null) + { + return ApiResponse.Error("未找到要删除的提交详情。", 404); + } + + detail.IsDeleted = true; + _submissionDetailRepository.Update(detail); + await _unitOfWork.SaveChangesAsync(); + + return ApiResponse.Success("删除提交详情成功。", null); + } + catch (Exception ex) + { + return ApiResponse.Error($"删除提交详情失败: {ex.Message}"); + } + } + + #endregion + + #region 特殊操作 + + /// + /// 获取提交详情列表 + /// + /// 提交ID + /// 提交详情列表 + public async Task GetBySubmissionIdAsync(Guid submissionId) + { + try + { + var details = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.SubmissionId == submissionId && !sd.IsDeleted, + include: i => i.Include(sd => sd.Student) + .Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(details.Items); + return ApiResponse.Success("获取提交详情列表成功。", detailDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取提交详情列表失败: {ex.Message}"); + } + } + + /// + /// 获取学生的提交详情 + /// + /// 学生ID + /// 考试ID + /// 提交详情列表 + public async Task GetByStudentAndExamAsync(Guid studentId, Guid examId) + { + try + { + var details = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.StudentId == studentId && + sd.Submission.ExamId == examId && + !sd.IsDeleted, + include: i => i.Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(details.Items); + return ApiResponse.Success("获取学生提交详情成功。", detailDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取学生提交详情失败: {ex.Message}"); + } + } + + /// + /// 批量创建提交详情 + /// + /// 提交ID + /// 提交详情列表 + /// 创建结果 + public async Task BatchCreateAsync(Guid submissionId, List details) + { + try + { + var detailEntities = _mapper.Map>(details); + foreach (var detail in detailEntities) + { + detail.SubmissionId = submissionId; + detail.CreatedAt = DateTime.Now; + detail.UpdatedAt = DateTime.Now; + detail.IsDeleted = false; + await _submissionDetailRepository.InsertAsync(detail); + } + + await _unitOfWork.SaveChangesAsync(); + var result = _mapper.Map>(detailEntities); + return ApiResponse.Success("批量创建提交详情成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"批量创建提交详情失败: {ex.Message}"); + } + } + + /// + /// 批量更新提交详情 + /// + /// 提交详情列表 + /// 更新结果 + public async Task BatchUpdateAsync(List details) + { + try + { + var detailIds = details.Select(d => d.Id).ToList(); + var existingDetails = await _submissionDetailRepository.GetAllAsync( + predicate: sd => detailIds.Contains(sd.Id) && !sd.IsDeleted); + + foreach (var detail in details) + { + var existingDetail = existingDetails.FirstOrDefault(sd => sd.Id == detail.Id); + if (existingDetail != null) + { + _mapper.Map(detail, existingDetail); + existingDetail.UpdatedAt = DateTime.Now; + _submissionDetailRepository.Update(existingDetail); + } + } + + await _unitOfWork.SaveChangesAsync(); + return ApiResponse.Success("批量更新提交详情成功。", null); + } + catch (Exception ex) + { + return ApiResponse.Error($"批量更新提交详情失败: {ex.Message}"); + } + } + + /// + /// 更新提交详情评分 + /// + /// 提交详情ID + /// 分数 + /// 反馈 + /// 更新结果 + public async Task UpdateScoreAsync(Guid detailId, float? points, string? feedback) + { + try + { + var detail = await _submissionDetailRepository.GetFirstOrDefaultAsync( + predicate: sd => sd.Id == detailId && !sd.IsDeleted); + + if (detail == null) + { + return ApiResponse.Error("未找到提交详情。", 404); + } + + detail.PointsAwarded = points; + detail.TeacherFeedback = feedback; + detail.UpdatedAt = DateTime.Now; + + _submissionDetailRepository.Update(detail); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(detail); + return ApiResponse.Success("更新评分成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"更新评分失败: {ex.Message}"); + } + } + + /// + /// 获取错题详情 + /// + /// 学生ID + /// 考试ID + /// 错题详情列表 + public async Task GetErrorDetailsAsync(Guid studentId, Guid examId) + { + try + { + var details = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.StudentId == studentId && + sd.Submission.ExamId == examId && + sd.IsCorrect == false && + !sd.IsDeleted, + include: i => i.Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(details.Items); + return ApiResponse.Success("获取错题详情成功。", detailDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取错题详情失败: {ex.Message}"); + } + } + + /// + /// 获取正确题详情 + /// + /// 学生ID + /// 考试ID + /// 正确题详情列表 + public async Task GetCorrectDetailsAsync(Guid studentId, Guid examId) + { + try + { + var details = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.StudentId == studentId && + sd.Submission.ExamId == examId && + sd.IsCorrect == true && + !sd.IsDeleted, + include: i => i.Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(details.Items); + return ApiResponse.Success("获取正确题详情成功。", detailDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取正确题详情失败: {ex.Message}"); + } + } + + /// + /// 获取未批改的提交详情 + /// + /// 教师ID + /// 未批改的提交详情列表 + public async Task GetUngradedDetailsAsync(Guid teacherId) + { + try + { + var submissions = await _submissionRepository.GetPagedListAsync( + predicate: s => s.GraderId == teacherId && + s.Status == SubmissionStatus.Submitted && + !s.IsDeleted); + + var submissionIds = submissions.Items.Select(s => s.Id).ToList(); + + var details = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => submissionIds.Contains(sd.SubmissionId) && + sd.PointsAwarded == null && + !sd.IsDeleted, + include: i => i.Include(sd => sd.Student) + .Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var detailDtos = _mapper.Map>(details.Items); + return ApiResponse.Success("获取未批改的提交详情成功。", detailDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取未批改的提交详情失败: {ex.Message}"); + } + } + + /// + /// 批量更新提交详情状态 + /// + /// 提交ID + /// 状态 + /// 更新结果 + public async Task UpdateStatusAsync(Guid submissionId, SubmissionStatus status) + { + try + { + var details = await _submissionDetailRepository.GetAllAsync( + predicate: sd => sd.SubmissionId == submissionId && !sd.IsDeleted); + + foreach (var detail in details) + { + detail.UpdatedAt = DateTime.Now; + _submissionDetailRepository.Update(detail); + } + + await _unitOfWork.SaveChangesAsync(); + return ApiResponse.Success("批量更新状态成功。", null); + } + catch (Exception ex) + { + return ApiResponse.Error($"批量更新状态失败: {ex.Message}"); + } + } + + #endregion + } +} diff --git a/TechHelper.Server/Services/Submission/SubmissionService.cs b/TechHelper.Server/Services/Submission/SubmissionService.cs new file mode 100644 index 0000000..2896b0a --- /dev/null +++ b/TechHelper.Server/Services/Submission/SubmissionService.cs @@ -0,0 +1,505 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using SharedDATA.Context; +using TechHelper.Services.Beta; + +namespace TechHelper.Services.Beta +{ + /// + /// 提交服务实现(Beta版本) + /// 实现提交相关的业务逻辑操作 + /// + public class SubmissionService : ISubmissionService + { + private readonly IUnitOfWork _unitOfWork; + private readonly IMapper _mapper; + private readonly IRepository _submissionRepository; + private readonly IRepository _submissionDetailRepository; + + /// + /// 初始化提交服务 + /// + /// AutoMapper实例 + /// 工作单元 + public SubmissionService(IMapper mapper, IUnitOfWork unitOfWork) + { + _mapper = mapper; + _unitOfWork = unitOfWork; + _submissionRepository = _unitOfWork.GetRepository(); + _submissionDetailRepository = _unitOfWork.GetRepository(); + } + + #region 基本CRUD操作 + + /// + /// 获取所有提交记录 + /// + /// 查询参数 + /// 提交记录列表 + public async Task GetAllAsync(QueryParameter query) + { + try + { + var pagedSubmissions = await _submissionRepository.GetPagedListAsync( + pageIndex: query.PageIndex, + pageSize: query.PageSize, + orderBy: s => s.OrderByDescending(s => s.SubmissionTime), + predicate: s => !s.IsDeleted); + + var submissionDtos = _mapper.Map>(pagedSubmissions.Items); + + return ApiResponse.Success("获取所有提交成功。", submissionDtos); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取所有提交失败: {ex.Message}"); + } + } + + /// + /// 根据ID获取提交记录 + /// + /// 提交ID + /// 提交记录详情 + public async Task GetAsync(Guid id) + { + try + { + var submission = await _submissionRepository.GetFirstOrDefaultAsync( + predicate: s => s.Id == id && !s.IsDeleted); + + if (submission == null) + { + return ApiResponse.Error("未找到提交记录。", 404); + } + + var submissionDto = _mapper.Map(submission); + return ApiResponse.Success("获取提交记录成功。", submissionDto); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取提交记录失败: {ex.Message}"); + } + } + + /// + /// 创建提交记录 + /// + /// 提交数据传输对象 + /// 创建结果 + public async Task AddAsync(SubmissionDto model) + { + try + { + var submission = _mapper.Map(model); + submission.SubmissionTime = DateTime.Now; + submission.IsDeleted = false; + + await _submissionRepository.InsertAsync(submission); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(submission); + return ApiResponse.Success("提交成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"创建提交失败: {ex.Message}"); + } + } + + /// + /// 更新提交记录 + /// + /// 提交数据传输对象 + /// 更新结果 + public async Task UpdateAsync(SubmissionDto model) + { + try + { + var existingSubmission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == model.Id && !s.IsDeleted); + if (existingSubmission == null) + { + return ApiResponse.Error("未找到要更新的提交记录。", 404); + } + + _mapper.Map(model, existingSubmission); + _submissionRepository.Update(existingSubmission); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(existingSubmission); + return ApiResponse.Success("更新提交记录成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"更新提交记录失败: {ex.Message}"); + } + } + + /// + /// 删除提交记录 + /// + /// 提交ID + /// 删除结果 + public async Task DeleteAsync(Guid id) + { + try + { + var submission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == id && !s.IsDeleted); + if (submission == null) + { + return ApiResponse.Error("未找到要删除的提交记录。", 404); + } + + submission.IsDeleted = true; + _submissionRepository.Update(submission); + + var submissionDetails = await _submissionDetailRepository.GetPagedListAsync(predicate: sd => sd.SubmissionId == id); + foreach (var detail in submissionDetails.Items) + { + detail.IsDeleted = true; + _submissionDetailRepository.Update(detail); + } + + await _unitOfWork.SaveChangesAsync(); + return ApiResponse.Success("提交记录及相关详情删除成功。", null); + } + catch (Exception ex) + { + return ApiResponse.Error($"删除提交记录失败: {ex.Message}"); + } + } + + #endregion + + #region 错题相关操作 + + /// + /// 获取用户的错题列表 + /// + /// 用户ID + /// 错题列表 + public async Task GetAllErrorQuestionsAsync(Guid userId) + { + try + { + var errorSDs = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.StudentId == userId && sd.IsCorrect == false, + include: i => i + .Include(s => s.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question) + .Where(q => q != null) + .DistinctBy(q => q.Id) + .ToList(); + + var result = _mapper.Map>(errorQuestions); + return ApiResponse.Success("获取所有错题成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取所有错题失败: {ex.Message}"); + } + } + + /// + /// 获取指定作业的错题列表 + /// + /// 作业ID + /// 用户ID + /// 错题列表 + public async Task GetAssignmentErrorQuestionsAsync(Guid assignmentId, Guid userId) + { + try + { + var errorSDs = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.Submission.ExamId == assignmentId && + sd.StudentId == userId && + sd.IsCorrect == false, + include: i => i + .Include(s => s.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question) + .Where(q => q != null) + .DistinctBy(q => q.Id) + .ToList(); + + var result = _mapper.Map>(errorQuestions); + return ApiResponse.Success("获取指定作业错题成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取指定作业错题失败: {ex.Message}"); + } + } + + /// + /// 获取错题类型分布 + /// + /// 作业ID + /// 用户ID + /// 错题类型分布 + public async Task GetAssignmentErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId) + { + try + { + var errorSDs = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.Submission.ExamId == assignmentId && + sd.StudentId == userId && + sd.IsCorrect == false, + include: i => i + .Include(s => s.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var errorTypeDistribution = errorSDs.Items + .Where(sd => sd.ExamQuestion?.Question?.QuestionType != null) + .GroupBy(sd => sd.ExamQuestion.Question.QuestionType.Name) + .Select(g => new + { + QuestionType = g.Key.ToString(), + Count = g.Count() + }) + .ToList(); + + return ApiResponse.Success("获取指定作业错题类型分布成功。", errorTypeDistribution); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取指定作业错题类型分布失败: {ex.Message}"); + } + } + + /// + /// 获取所有错题类型分布 + /// + /// 作业ID + /// 用户ID + /// 错题类型分布 + public async Task GetAllErrorQuestionTypeDisAsync(Guid assignmentId, Guid userId) + { + try + { + var errorSDs = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.Submission.ExamId == assignmentId && + sd.StudentId == userId && + sd.IsCorrect == false, + include: i => i + .Include(s => s.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var errorTypeDistribution = errorSDs.Items + .Where(sd => sd.ExamQuestion?.Question?.QuestionType != null) + .GroupBy(sd => sd.ExamQuestion.Question.QuestionType.Name) + .Select(g => new + { + QuestionType = g.Key.ToString(), + Count = g.Count() + }) + .ToList(); + + return ApiResponse.Success("获取错题类型分布成功。", errorTypeDistribution); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取错题类型分布失败: {ex.Message}"); + } + } + + /// + /// 获取作业中所有学生的错题情况 + /// + /// 作业ID + /// 教师ID + /// 学生错题情况 + public async Task GetAssignmentAllStudentsError(Guid assignmentId, Guid teacherId) + { + try + { + var submissionDetails = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.Submission.ExamId == assignmentId && + sd.IsCorrect == false, + include: i => i.Include(sd => sd.Student)); + + var studentsErrorSummary = submissionDetails.Items + .Where(sd => sd.Student != null) + .GroupBy(sd => new { sd.StudentId, sd.Student.UserName }) + .Select(g => new + { + StudentId = g.Key.StudentId, + StudentName = g.Key.UserName, + ErrorQuestionCount = g.Count() + }) + .ToList(); + + return ApiResponse.Success("获取作业中所有学生的错题情况成功。", studentsErrorSummary); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取作业中所有学生的错题情况失败: {ex.Message}"); + } + } + + /// + /// 获取出现错题的学生列表 + /// + /// 作业题目ID + /// 错题学生列表 + public async Task GetQuestionErrorStudents(Guid assignmentQuestionId) + { + try + { + var errorSubmissionDetails = await _submissionDetailRepository.GetPagedListAsync( + predicate: sd => sd.ExamQuestionId == assignmentQuestionId && + sd.IsCorrect == false, + include: i => i + .Include(sd => sd.Student) + .Include(sd => sd.ExamQuestion) + .ThenInclude(aq => aq.Question)); + + var errorStudentsByQuestion = errorSubmissionDetails.Items + .Where(sd => sd.ExamQuestion?.Question != null && sd.Student != null) + .GroupBy(sd => new { sd.ExamQuestionId, sd.ExamQuestion.Question.Title }) + .Select(g => new + { + AssignmentQuestionId = g.Key.ExamQuestionId, + QuestionTitle = g.Key.Title, + ErrorStudents = g.Select(sd => new + { + StudentId = sd.StudentId, + StudentName = sd.Student.UserName + }).Distinct().ToList() + }) + .ToList(); + + return ApiResponse.Success("获取出现错题的学生成功。", errorStudentsByQuestion); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取出现错题的学生失败: {ex.Message}"); + } + } + + #endregion + + #region 特殊操作 + + /// + /// 判断是否已经存在提交记录 + /// + /// 作业ID + /// 学生ID + /// 提交记录数量 + public async Task IsHasSubmissionAsync(Guid assignmentId, Guid studentId) + { + try + { + var result = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.ExamId == assignmentId && s.StudentId == studentId); + return (byte)result.Count; + } + catch (Exception ex) + { + throw; + } + } + + /// + /// 获取学生提交摘要 + /// + /// 用户ID + /// 学生提交摘要列表 + public async Task GetStudentSubmissionSummariesAsync(Guid userId) + { + try + { + var submissions = await _submissionRepository.GetPagedListAsync( + predicate: s => s.StudentId == userId && !s.IsDeleted, + orderBy: s => s.OrderByDescending(s => s.SubmissionTime)); + + var summaries = submissions.Items.Select(s => new StudentSubmissionSummaryDto + { + Id = s.Id, + AssignmentName = s.Exam?.Title ?? "未知作业", + CreatedDate = s.SubmissionTime, + Score = s.OverallGrade, + StudentName = s.Student?.UserName ?? "未知学生", + Status = s.Status.GetDisplayName() + }).ToList(); + + return ApiResponse.Success("获取学生提交摘要成功。", new StudentSubmissionSummaryResponseDto + { + Submissions = summaries, + TotalCount = submissions.TotalCount + }); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取学生提交摘要失败: {ex.Message}"); + } + } + + /// + /// 获取学生提交详情 + /// + /// 提交ID + /// 学生提交详情 + public async Task GetStudentSubmissionDetailAsync(Guid submissionId) + { + try + { + var submission = await _submissionRepository.GetFirstOrDefaultAsync( + predicate: s => s.Id == submissionId && !s.IsDeleted); + + if (submission == null) + { + return ApiResponse.Error("未找到提交记录。", 404); + } + + var detail = _mapper.Map(submission); + + + return ApiResponse.Success("获取学生提交详情成功。", detail); + } + catch (Exception ex) + { + return ApiResponse.Error($"获取学生提交详情失败: {ex.Message}"); + } + } + + public async Task GradeExam(SubmissionTeacherUpdateDto model) + { + + try + { + var existingSubmission = await _submissionRepository.GetFirstOrDefaultAsync(predicate: s => s.Id == model.Id && !s.IsDeleted); + if (existingSubmission == null) + { + return ApiResponse.Error("未找到要批改的试卷记录。", 404); + } + + _mapper.Map(model, existingSubmission); + + foreach (var item in existingSubmission.SubmissionDetails) + { + var sdd = model.SubmissionUpdateDetails.FirstOrDefault(d => d.Id == item.Id); + if (sdd == null) continue; + _mapper.Map(sdd, item); + } + _submissionRepository.Update(existingSubmission); + await _unitOfWork.SaveChangesAsync(); + + var result = _mapper.Map(existingSubmission); + return ApiResponse.Success("批改试卷记录成功。", result); + } + catch (Exception ex) + { + return ApiResponse.Error($"批改试卷记录失败: {ex.Message}"); + } + } + + #endregion + } +} diff --git a/TechHelper.Server/Services/SubmissionServices.cs b/TechHelper.Server/Services/SubmissionServices.cs index c1a732b..9f653a6 100644 --- a/TechHelper.Server/Services/SubmissionServices.cs +++ b/TechHelper.Server/Services/SubmissionServices.cs @@ -81,7 +81,7 @@ namespace TechHelper.Server.Services orderBy: s => s.OrderByDescending(s => s.SubmissionTime), predicate: s => !s.IsDeleted, include: i => i.Include(s => s.Student) - .Include(s => s.Assignment)); + .Include(s => s.Exam)); var submissionDtos = _mapper.Map>(pagedSubmissions.Items); @@ -109,10 +109,10 @@ namespace TechHelper.Server.Services predicate: sd => sd.StudentId == userId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i - .Include(s => s.AssignmentQuestion) + .Include(s => s.ExamQuestion) .ThenInclude(aq => aq.Question)); - var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question) + var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question) .Where(q => q != null) .DistinctBy(q => q.Id) .ToList(); @@ -132,18 +132,18 @@ namespace TechHelper.Server.Services try { var errorSDs = await _submissionDetailRepository.GetPagedListAsync( - predicate: sd => sd.Submission.AssignmentId == assignmentId && + predicate: sd => sd.Submission.ExamId == assignmentId && sd.StudentId == userId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i - .Include(s => s.AssignmentQuestion) + .Include(s => s.ExamQuestion) .ThenInclude(aq => aq.Question)); // 对错题按类型进行分组计数 var errorTypeDistribution = errorSDs.Items - .Where(sd => sd.AssignmentQuestion?.Question != null) - .GroupBy(sd => sd.AssignmentQuestion.Question.Type) + .Where(sd => sd.ExamQuestion?.Question != null) + .GroupBy(sd => sd.ExamQuestion.Question.Type) .Select(g => new { QuestionType = g.Key.ToString(), @@ -164,7 +164,7 @@ namespace TechHelper.Server.Services try { var submissionDetails = await _submissionDetailRepository.GetPagedListAsync( - predicate: sd => sd.Submission.AssignmentId == assignmentId && + predicate: sd => sd.Submission.ExamId == assignmentId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i.Include(sd => sd.Student)); @@ -194,15 +194,15 @@ namespace TechHelper.Server.Services try { var errorSDs = await _submissionDetailRepository.GetPagedListAsync( - predicate: sd => sd.Submission.AssignmentId == assignmentId && + predicate: sd => sd.Submission.ExamId == assignmentId && sd.StudentId == userId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i - .Include(s => s.AssignmentQuestion) + .Include(s => s.ExamQuestion) .ThenInclude(aq => aq.Question)); - var errorQuestions = errorSDs.Items.Select(sd => sd.AssignmentQuestion.Question) + var errorQuestions = errorSDs.Items.Select(sd => sd.ExamQuestion.Question) .Where(q => q != null) .DistinctBy(q => q.Id) .ToList(); @@ -221,17 +221,17 @@ namespace TechHelper.Server.Services try { var errorSDs = await _submissionDetailRepository.GetPagedListAsync( - predicate: sd => sd.Submission.AssignmentId == assignmentId && + predicate: sd => sd.Submission.ExamId == assignmentId && sd.StudentId == userId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i - .Include(s => s.AssignmentQuestion) + .Include(s => s.ExamQuestion) .ThenInclude(aq => aq.Question)); var errorTypeDistribution = errorSDs.Items - .Where(sd => sd.AssignmentQuestion?.Question != null) - .GroupBy(sd => sd.AssignmentQuestion.Question.Type) + .Where(sd => sd.ExamQuestion?.Question != null) + .GroupBy(sd => sd.ExamQuestion.Question.Type) .Select(g => new { QuestionType = g.Key.ToString(), @@ -254,10 +254,10 @@ namespace TechHelper.Server.Services var submission = await _submissionRepository.GetFirstOrDefaultAsync( predicate: s => s.Id == id && !s.IsDeleted, include: i => i.Include(s => s.Student) - .Include(s => s.Assignment) + .Include(s => s.Exam) .Include(s => s.Grader) .Include(s => s.SubmissionDetails) - .ThenInclude(sd => sd.AssignmentQuestion) + .ThenInclude(sd => sd.ExamQuestion) .ThenInclude(aq => aq.Question)); if (submission == null) @@ -279,18 +279,18 @@ namespace TechHelper.Server.Services try { var errorSubmissionDetails = await _submissionDetailRepository.GetPagedListAsync( - predicate: sd => sd.AssignmentQuestionId == assignmentQuestionId && + predicate: sd => sd.ExamQuestionId == assignmentQuestionId && sd.IsCorrect == false && (sd.Status == SubmissionStatus.Submitted || sd.Status == SubmissionStatus.Graded), include: i => i .Include(sd => sd.Student) - .Include(sd => sd.AssignmentQuestion) + .Include(sd => sd.ExamQuestion) .ThenInclude(aq => aq.Question)); var errorStudentsByQuestion = errorSubmissionDetails.Items - .Where(sd => sd.AssignmentQuestion?.Question != null && sd.Student != null) - .GroupBy(sd => new { sd.AssignmentQuestionId, sd.AssignmentQuestion.Question.Title }) + .Where(sd => sd.ExamQuestion?.Question != null && sd.Student != null) + .GroupBy(sd => new { sd.ExamQuestionId, sd.ExamQuestion.Question.Title }) .Select(g => new { AssignmentQuestionId = g.Key.AssignmentQuestionId, @@ -315,7 +315,7 @@ namespace TechHelper.Server.Services { try { - var result = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.AssignmentId == assignment && s.StudentId == studentId); + var result = await _unitOfWork.GetRepository().GetAllAsync(predicate: s => s.ExamId == assignment && s.StudentId == studentId); return (byte)result.Count; } catch (Exception ex) diff --git a/TechHelper.Server/Services/Textbook/ITextbookService.cs b/TechHelper.Server/Services/Textbook/ITextbookService.cs new file mode 100644 index 0000000..1dfb7b7 --- /dev/null +++ b/TechHelper.Server/Services/Textbook/ITextbookService.cs @@ -0,0 +1,12 @@ +using Entities.DTO; +using TechHelper.Services; + +namespace TechHelper.Services.Beta +{ + /// + /// 教材服务接口 + /// + public interface ITextbookService : IBaseService + { + } +} diff --git a/TechHelper.Server/Services/Textbook/TextbookService.cs b/TechHelper.Server/Services/Textbook/TextbookService.cs new file mode 100644 index 0000000..62b1437 --- /dev/null +++ b/TechHelper.Server/Services/Textbook/TextbookService.cs @@ -0,0 +1,186 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.EntityFrameworkCore; +using SharedDATA.Api; +using TechHelper.Services.Beta; + +namespace TechHelper.Services.Beta +{ + /// + /// 教材服务实现类 + /// + public class TextbookService : ITextbookService + { + private readonly IUnitOfWork _work; + private readonly IMapper _mapper; + + public TextbookService(IUnitOfWork work, IMapper mapper) + { + _work = work; + _mapper = mapper; + } + + public async Task GetAllAsync(QueryParameter query) + { + try + { + var repository = _work.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var textbooks = await repository.GetPagedListAsync( + predicate: t => t.Title.Contains(query.Search) || + t.Grade.ToString().Contains(query.Search) || + t.Publisher.ToString().Contains(query.Search) || + t.SubjectArea.ToString().Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var textbookDtosFiltered = _mapper.Map>(textbooks.Items); + return new ApiResponse(true, textbookDtosFiltered); + } + else + { + var textbooks = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var textbookDtos = _mapper.Map>(textbooks.Items); + return new ApiResponse(true, textbookDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有教材时发生错误: {ex.Message}"); + } + } + + public async Task GetAsync(Guid id) + { + try + { + var textbook = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: t => t.Id == id, + include: i => i + .Include(t => t.Lessons)); + + if (textbook == null) + { + return new ApiResponse("教材未找到。"); + } + + var textbookDto = _mapper.Map(textbook); + return new ApiResponse(true, textbookDto); + } + catch (Exception ex) + { + return new ApiResponse($"获取教材时发生错误: {ex.Message}"); + } + } + + public async Task AddAsync(TextbookDto model) + { + try + { + // 检查是否已存在同名教材(考虑年级和学科领域) + var existingTextbook = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: t => t.Title == model.Title && + t.Grade.ToString() == model.Grade && + t.SubjectArea.ToString() == model.SubjectArea); + + if (existingTextbook != null) + { + return new ApiResponse($"教材 '{model.Title}' 在该年级和学科领域已存在。"); + } + + var textbook = _mapper.Map(model); + + await _work.GetRepository().InsertAsync(textbook); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, textbook.Id); + } + return new ApiResponse("添加教材失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"添加教材时发生错误: {ex.Message}"); + } + } + + public async Task UpdateAsync(TextbookDto model) + { + try + { + var existingTextbook = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: t => t.Id == model.Id); + + if (existingTextbook == null) + { + return new ApiResponse("教材未找到。"); + } + + // 检查是否要修改为已存在的教材名称(排除当前教材) + var textbookWithSameName = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: t => t.Title == model.Title && + t.Grade.ToString() == model.Grade && + t.SubjectArea.ToString() == model.SubjectArea && + t.Id != model.Id); + + if (textbookWithSameName != null) + { + return new ApiResponse($"教材名称 '{model.Title}' 在该年级和学科领域已被其他教材使用。"); + } + + _mapper.Map(model, existingTextbook); + _work.GetRepository().Update(existingTextbook); + + if (await _work.SaveChangesAsync() > 0) + { + var textbookDto = _mapper.Map(existingTextbook); + return new ApiResponse(true, textbookDto); + } + return new ApiResponse("更新教材失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"更新教材时发生错误: {ex.Message}"); + } + } + + public async Task DeleteAsync(Guid id) + { + try + { + var existingTextbook = await _work.GetRepository().GetFirstOrDefaultAsync( + predicate: t => t.Id == id); + + if (existingTextbook == null) + { + return new ApiResponse("教材未找到。"); + } + + // 检查是否有相关课程 + var hasLessons = existingTextbook.Lessons.Any(); + if (hasLessons) + { + return new ApiResponse("无法删除该教材,因为它包含相关课程。"); + } + + _work.GetRepository().Delete(existingTextbook); + + if (await _work.SaveChangesAsync() > 0) + { + return new ApiResponse(true, "教材删除成功。"); + } + return new ApiResponse("删除教材失败。"); + } + catch (Exception ex) + { + return new ApiResponse($"删除教材时发生错误: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/AuthenticationService.cs b/TechHelper.Server/Services/User/AuthenticationService.cs similarity index 58% rename from TechHelper.Server/Services/AuthenticationService.cs rename to TechHelper.Server/Services/User/AuthenticationService.cs index fc0cbad..2374ba3 100644 --- a/TechHelper.Server/Services/AuthenticationService.cs +++ b/TechHelper.Server/Services/User/AuthenticationService.cs @@ -1,5 +1,4 @@ -using TechHelper.Context; -using Entities.Configuration; +using Entities.Configuration; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; @@ -7,17 +6,24 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; -using Entities.Contracts; +using Entities.DTO; -namespace TechHelper.Services +namespace TechHelper.Services.Beta { + /// + /// 用户认证服务,实现 JWT 令牌生成、刷新令牌生成、过期令牌解析等功能。 + /// public class AuthenticationService : IAuthenticationService { private readonly JwtConfiguration _jwtSettings; private readonly JwtSecurityTokenHandler _jwtHandler; - private readonly UserManager _userManager; + private readonly UserManager _userManager; private readonly IClassService _classService; - public AuthenticationService(IOptions jwtSettings, UserManager userManager, IClassService classService) + + /// + /// 构造函数,注入 JWT 配置、用户管理器和班级服务。 + /// + public AuthenticationService(IOptions jwtSettings, UserManager userManager, IClassService classService) { _jwtSettings = jwtSettings.Value; _jwtHandler = new JwtSecurityTokenHandler(); @@ -25,54 +31,72 @@ namespace TechHelper.Services _classService = classService; } - public async Task GetToken(User user) + /// + /// 生成指定用户的 JWT 访问令牌。 + /// + /// 用户实体 + /// JWT 字符串 + public async Task GetToken(Entities.Contracts.User user) { var signingCredentials = GetSigningCredentials(); - var claims = await GetClaims(user); - var tokenOptions = GenerateTokenOptions(signingCredentials, claims); - return _jwtHandler.WriteToken(tokenOptions); } + /// + /// 获取 JWT 签名凭证。 + /// + /// 签名凭证 private SigningCredentials GetSigningCredentials() { var key = Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey); var secret = new SymmetricSecurityKey(key); - return new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); } - private async Task> GetClaims(User user) + /// + /// 获取用户的声明信息,包括角色和班级信息。 + /// + /// 用户实体 + /// 声明集合 + private async Task> GetClaims(Entities.Contracts.User user) { var claims = new List { new Claim(ClaimTypes.Name, user.Email) }; + // 添加用户角色声明 var roles = await _userManager.GetRolesAsync(user); foreach (var role in roles) { claims.Add(new Claim(ClaimTypes.Role, role)); } - var classInfo = await _classService.GetUserClass(user.Id); + #region ClassInfo + // 添加用户班级信息声明 + var classInfo = await _classService.GetUserInjoinedClasses(user.Id); if (classInfo.Status) { - var classs = classInfo.Result as List; - - classs?.ForEach(c => + var classs = classInfo.Result as UserClassDetailInfoDto; + if (classs == null) return claims; + foreach (var c in classs.UserClassInfos) { - claims.Add(new Claim("Grade", c.Grade.ToString())); - claims.Add(new Claim("Class", c.Number.ToString())); - }); + claims.Add(new Claim("Class", c.Class.ToString())); + } } - + #endregion return claims; } + /// + /// 生成 JWT 令牌对象。 + /// + /// 签名凭证 + /// 声明集合 + /// JWT 令牌对象 private JwtSecurityToken GenerateTokenOptions(SigningCredentials signingCredentials, IEnumerable claims) { var tokenOptions = new JwtSecurityToken( @@ -86,6 +110,10 @@ namespace TechHelper.Services return tokenOptions; } + /// + /// 生成安全的刷新令牌(Base64 字符串)。 + /// + /// 刷新令牌 public string GenerateRefreshToken() { var randomNumber = new byte[32]; @@ -96,6 +124,12 @@ namespace TechHelper.Services } } + /// + /// 从过期的 JWT 令牌中获取声明主体(不验证过期时间)。 + /// + /// 过期的 JWT 令牌 + /// 声明主体 + /// 令牌无效时抛出 public ClaimsPrincipal GetPrincipalFromExpiredToken(string token) { var tokenValidationParameters = new TokenValidationParameters @@ -105,7 +139,7 @@ namespace TechHelper.Services ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_jwtSettings.SecurityKey)), - ValidateLifetime = false, + ValidateLifetime = false, // 不验证过期时间 ValidIssuer = _jwtSettings.ValidIssuer, ValidAudience = _jwtSettings.ValidAudience, }; diff --git a/TechHelper.Server/Services/IAuthenticationService.cs b/TechHelper.Server/Services/User/IAuthenticationService.cs similarity index 74% rename from TechHelper.Server/Services/IAuthenticationService.cs rename to TechHelper.Server/Services/User/IAuthenticationService.cs index ef5a462..97e0394 100644 --- a/TechHelper.Server/Services/IAuthenticationService.cs +++ b/TechHelper.Server/Services/User/IAuthenticationService.cs @@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Identity; using System.Security.Claims; using Entities.Contracts; -namespace TechHelper.Services +namespace TechHelper.Services.Beta { public interface IAuthenticationService { - public Task GetToken(User user); + public Task GetToken(Entities.Contracts.User user); public string GenerateRefreshToken(); public ClaimsPrincipal GetPrincipalFromExpiredToken(string token); } diff --git a/TechHelper.Server/Services/User/IUserSerivces.cs b/TechHelper.Server/Services/User/IUserSerivces.cs new file mode 100644 index 0000000..d18243f --- /dev/null +++ b/TechHelper.Server/Services/User/IUserSerivces.cs @@ -0,0 +1,20 @@ +using Entities.Contracts; +using Entities.DTO; + +namespace TechHelper.Services.Beta +{ + public interface IUserSerivces : IBaseService + { + Task GetStudentDetailInfo(Guid userId); + Task RestoreUserRoleInformation(User user); + Task VerifyUserInformation(Guid userId); + /// + /// 注册新用户,并根据角色关联到班级 + /// + /// 用户注册数据 + /// 操作结果 + Task RegisterNewUserAsync(UserForRegistrationDto registrationDto); + + Task InitAdminUser(UserForAdmin registrationDto); + } +} diff --git a/TechHelper.Server/Services/User/UserServices.cs b/TechHelper.Server/Services/User/UserServices.cs new file mode 100644 index 0000000..41e7d81 --- /dev/null +++ b/TechHelper.Server/Services/User/UserServices.cs @@ -0,0 +1,421 @@ +using AutoMapper; +using Entities.Contracts; +using Entities.DTO; +using Microsoft.AspNetCore.Identity; +using SharedDATA.Api; +using TechHelper.Features; + +namespace TechHelper.Services.Beta +{ + /// + /// 用户服务实现类 + /// 处理用户相关的业务逻辑操作 + /// + public class UserServices : IUserSerivces + { + + private readonly IUnitOfWork _unitOfWork; + private readonly IClassService _classService; + private readonly UserManager _userManager; + private readonly IMapper _mapper; + private readonly TechHelper.Features.IEmailSender _emailSender; + + /// + /// 初始化用户服务 + /// + /// 工作单元实例 + /// 班级服务实例 + /// 用户管理实例 + /// 对象映射实例 + /// 邮件发送实例 + public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager userManager, IMapper mapper, IEmailSender emailSender) + { + _unitOfWork = unitOfWork; + _classService = classService; + _userManager = userManager; + _mapper = mapper; + _emailSender = emailSender; + } + + /// + /// 添加新用户 + /// + /// 用户实体对象 + /// 操作结果响应 + public async Task AddAsync(UserDto model) + { + try + { + //var user = _mapper.Map(model); + //user.UserName = model.Email; + //user.EmailConfirmed = true; + + //var result = await _userManager.CreateAsync(user, model.Password ?? "TempPassword123!"); + + //if (!result.Succeeded) + //{ + // var errors = result.Errors.Select(e => e.Description).ToList(); + // return new ApiResponse(false, errors); + //} + + return new ApiResponse(true, "用户添加成功"); + } + catch (Exception ex) + { + return new ApiResponse(false, $"添加用户失败: {ex.Message}"); + } + } + + /// + /// 删除指定用户 + /// + /// 用户唯一标识符 + /// 操作结果响应 + public async Task DeleteAsync(Guid id) + { + try + { + var user = await _userManager.FindByIdAsync(id.ToString()); + if (user == null) + { + return new ApiResponse(false, "用户不存在"); + } + + var result = await _userManager.DeleteAsync(user); + + if (!result.Succeeded) + { + var errors = result.Errors.Select(e => e.Description).ToList(); + return new ApiResponse(false, errors); + } + + return new ApiResponse(true, "用户删除成功"); + } + catch (Exception ex) + { + return new ApiResponse(false, $"删除用户失败: {ex.Message}"); + } + } + + /// + /// 获取所有用户列表 + /// + /// 查询参数对象 + /// 用户列表响应 + public async Task GetAllAsync(QueryParameter query) + { + + try + { + var repository = _unitOfWork.GetRepository(); + + if (query.Search != null && !string.IsNullOrWhiteSpace(query.Search)) + { + var users = await repository.GetPagedListAsync( + predicate: u => u.Email.Contains(query.Search) || u.DisplayName.Contains(query.Search), + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var userDtosFiltered = _mapper.Map>(users.Items); + return new ApiResponse(true, userDtosFiltered); + } + else + { + var users = await repository.GetPagedListAsync( + pageSize: query.PageSize, + pageIndex: query.PageIndex + ); + var userDtos = _mapper.Map>(users.Items); + return new ApiResponse(true, userDtos); + } + } + catch (Exception ex) + { + return new ApiResponse($"获取所有用户时发生错误: {ex.Message}"); + } + } + + + + /// + /// 获取指定用户信息 + /// + /// 用户唯一标识符 + /// 用户信息响应 + public async Task GetAsync(Guid id) + { + try + { + var user = await _userManager.FindByIdAsync(id.ToString()); + if (user == null) + { + return new ApiResponse(false, "用户不存在"); + } + + var userDto = _mapper.Map(user); + return new ApiResponse(true, userDto); + } + catch (Exception ex) + { + return new ApiResponse(false, $"获取用户信息失败: {ex.Message}"); + } + } + + /// + /// 获取学生详细信息 + /// + /// 用户唯一标识符 + /// 学生详细信息响应 + public async Task GetStudentDetailInfo(Guid userId) + { + try + { + var user = await _userManager.FindByIdAsync(userId.ToString()); + if (user == null) + { + return new ApiResponse(false, "用户不存在"); + } + + var studentDetail = new + { + user.Id, + user.Email, + user.DisplayName, + user.PhoneNumber, + user.Role, + IsEmailConfirmed = user.EmailConfirmed, + UserStatus = user.EmailConfirmed ? "Verified" : "Pending Verification" + }; + + return new ApiResponse(true, studentDetail); + } + catch (Exception ex) + { + return new ApiResponse(false, $"获取学生详细信息失败: {ex.Message}"); + } + } + + /// + /// 恢复用户角色信息 + /// 根据用户所在班级信息恢复用户的角色权限 + /// + /// 用户实体对象 + /// 操作结果响应 + public async Task RestoreUserRoleInformation(User user) + { + var result = await _classService.GetUserClassRole(user.Id); + if (result.Status) + { + var classRole = result.Result as string; + if (classRole != null) + { + if (!await _userManager.IsInRoleAsync(user, classRole)) + { + await _userManager.AddToRoleAsync(user, classRole); + + return ApiResponse.Success(); + } + } + } + return ApiResponse.Error(); + } + + /// + /// 更新用户信息 + /// + /// 用户实体对象 + /// 操作结果响应 + public async Task UpdateAsync(UserDto model) + { + try + { + var user = await _userManager.FindByIdAsync(model.Id.ToString()); + if (user == null) + { + return new ApiResponse(false, "用户不存在"); + } + + user.DisplayName = model.DisplayName; + user.PhoneNumber = model.PhoneNumber; + + var result = await _userManager.UpdateAsync(user); + + if (!result.Succeeded) + { + var errors = result.Errors.Select(e => e.Description).ToList(); + return new ApiResponse(false, errors); + } + + return new ApiResponse(true, "用户信息更新成功"); + } + catch (Exception ex) + { + return new ApiResponse(false, $"更新用户信息失败: {ex.Message}"); + } + } + + /// + /// 验证用户信息 + /// + /// 用户唯一标识符 + /// 验证结果响应 + public async Task VerifyUserInformation(Guid userId) + { + try + { + var user = await _userManager.FindByIdAsync(userId.ToString()); + if (user == null) + { + return new ApiResponse(false, "用户不存在"); + } + + // 验证邮箱确认状态 + var isEmailConfirmed = user.EmailConfirmed; + + // 验证用户角色 + var isInRole = await _userManager.IsInRoleAsync(user, "Student") || + await _userManager.IsInRoleAsync(user, "Teacher"); + + var verificationResult = new + { + UserId = user.Id, + Email = user.Email, + IsEmailConfirmed = isEmailConfirmed, + HasValidRole = isInRole, + DisplayName = user.DisplayName, + Role = user.Role + }; + + if (isEmailConfirmed && isInRole) + { + return new ApiResponse(true, "用户信息验证成功"); + } + else + { + return new ApiResponse(false, "用户信息验证失败"); + } + } + catch (Exception ex) + { + return new ApiResponse(false, $"验证用户信息失败: {ex.Message}"); + } + } + + /// + /// 注册新用户,并根据角色关联到班级 + /// + /// 用户注册数据 + /// 操作结果 + public async Task RegisterNewUserAsync(UserForRegistrationDto registrationDto) + { + try + { + var existingUserByEmail = await _userManager.FindByEmailAsync(registrationDto.Email); + if (existingUserByEmail != null) + { + return new ApiResponse("此电子邮件地址已被注册。"); + } + + var user = _mapper.Map(registrationDto); + + user.UserName = registrationDto.Email; + user.DisplayName = registrationDto.DisplayName; + user.Role = registrationDto.Roles; + user.EmailConfirmed = false; + user.TeachSubjectId = registrationDto.RegisterUserToClassDto.SubjectArea; + + var result = await _userManager.CreateAsync(user, registrationDto.Password); + + + if (!result.Succeeded) + { + var errors = result.Errors.Select(e => e.Description).ToList(); + return new ApiResponse(false, errors); + } + + var userResult = await _userManager.FindByEmailAsync(user.Email); + if (userResult == null) + return ApiResponse.Error("注册失败,请联系管理员。"); + + var roleResult = await _userManager.AddToRoleAsync(userResult, registrationDto.Roles.ToString()); + + if (!roleResult.Succeeded) + { + var errors = roleResult.Errors.Select(e => e.Description).ToList(); + return new ApiResponse(false, errors); + } + + registrationDto.RegisterUserToClassDto.UserId = userResult.Id; + var classRegisterResult = await _classService.UserRegister(registrationDto.RegisterUserToClassDto); + + if (!classRegisterResult.Status) + { + if (userResult != null) + await _userManager.DeleteAsync(userResult); + + return new ApiResponse(false, classRegisterResult.Message ?? "Class registration failed"); + } + + return new ApiResponse(true, "操作成功。"); + + //var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(user); + //var encodedToken = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(emailConfirmationToken)); + //var callbackUrl = QueryHelpers.AddQueryString(registrationDto.ClientURI, new Dictionary + //{ + // {"token", encodedToken}, + // {"email", user.Email} + //}); + + //try + //{ + // await _emailSender.SendEmailAsync(user.Email, "请确认您的邮箱", $"请点击此链接确认您的邮箱: {callbackUrl}"); + //} + //catch (Exception ex) + //{ + // Console.Error.WriteLine($"发送邮箱确认邮件失败: {ex.Message}"); + //} + + } + catch (Exception ex) + { + var userResult = await _userManager.FindByEmailAsync(registrationDto.Email); + if (userResult != null) + await _userManager.DeleteAsync(userResult); + return new ApiResponse(false, "注册过程中发生错误"); + } + } + + public async Task InitAdminUser(UserForAdmin admin) + { + try + { + var existingUserByEmail = await _userManager.FindByEmailAsync(admin.Email); + if (existingUserByEmail != null) + { + return new ApiResponse("此电子邮件地址已被注册。"); + } + var user = new User { Role = UserRoles.Admin, DisplayName = admin.DisplayName, Email = admin.Email, UserName = admin.Email }; + + var result = await _userManager.CreateAsync(user, admin.Password); + if (!result.Succeeded) + { + return ApiResponse.Error("管理员用户创建失败, 用户注册时失败"); + } + + await _userManager.AddToRoleAsync(user, UserRoles.Admin.ToString()); + + await _unitOfWork.GetRepository().InsertAsync(new School { SchoolName = admin.SchoolName, CreateTime = DateTime.Now, Address = admin.Address }); + + if (await _unitOfWork.SaveChangesAsync() > 0) + { + return ApiResponse.Success("管理员用户创建成功"); + } + return ApiResponse.Error("管理员用户创建失败"); + } + catch (Exception ex) + { + return ApiResponse.Error($"创建失败: {ex.Message}"); + } + } + } +} diff --git a/TechHelper.Server/Services/UserRegistrationService.cs b/TechHelper.Server/Services/UserRegistrationService.cs deleted file mode 100644 index d97dae1..0000000 --- a/TechHelper.Server/Services/UserRegistrationService.cs +++ /dev/null @@ -1,126 +0,0 @@ -using AutoMapper; -using Entities.Contracts; -using Entities.DTO; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.WebUtilities; -using SharedDATA.Api; -using System.Text; -using TechHelper.Features; - -namespace TechHelper.Services -{ - public class UserRegistrationService : IUserRegistrationService - { - private readonly IUnitOfWork _work; - private readonly IMapper _mapper; - private readonly UserManager _userManager; - private readonly IEmailSender _emailSender; - - public UserRegistrationService( - IUnitOfWork work, - IMapper mapper, - UserManager userManager, - IEmailSender emailSender) - { - _work = work; - _mapper = mapper; - _userManager = userManager; - _emailSender = emailSender; - } - - public async Task RegisterNewUserAsync(UserForRegistrationDto registrationDto) - { - try - { - var existingUserByEmail = await _userManager.FindByEmailAsync(registrationDto.Email); - if (existingUserByEmail != null) - { - return new ApiResponse("此电子邮件地址已被注册。"); - } - - var user = _mapper.Map(registrationDto); - - user.UserName = registrationDto.Email; - user.DisplayName = registrationDto.Name; - user.EmailConfirmed = false; - - var result = await _userManager.CreateAsync(user, registrationDto.Password); - - if (!result.Succeeded) - { - var errors = result.Errors.Select(e => e.Description).ToList(); - return new ApiResponse(false, errors); - } - - var existingClass = await _work.GetRepository().GetFirstOrDefaultAsync( - predicate: c => c.Number == registrationDto.Class && c.Grade == registrationDto.Grade); - - if (existingClass == null) - { - existingClass = new Class - { - Number = (byte)registrationDto.Class, - Grade = (byte)registrationDto.Grade - }; - await _work.GetRepository().InsertAsync(existingClass); - } - - //if (registrationDto.Roles == UserRoles.Student) - //{ - // var classStudent = new ClassStudent - // { - // ClassId = existingClass.Id, - // StudentId = user.Id - // }; - // await _work.GetRepository().InsertAsync(classStudent); - - // await _userManager.AddToRoleAsync(user, UserRoles.Student.ToString()); - //} - //else if (registrationDto.Roles == UserRoles.Teacher) - //{ - // var classTeacher = new ClassTeacher - // { - // ClassId = existingClass.Id, - // TeacherId = user.Id - // }; - // await _work.GetRepository().InsertAsync(classTeacher); - - // await _userManager.AddToRoleAsync(user, UserRoles.Teacher.ToString()); - //} - - //var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(user); - //var encodedToken = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(emailConfirmationToken)); - //var callbackUrl = QueryHelpers.AddQueryString(registrationDto.ClientURI, new Dictionary - //{ - // {"token", encodedToken}, - // {"email", user.Email} - // }); - - //try - //{ - // await _emailSender.SendEmailAsync(user.Email, "请确认您的邮箱", $"请点击此链接确认您的邮箱: {callbackUrl}"); - //} - //catch (Exception ex) - //{ - // Console.Error.WriteLine($"发送邮箱确认邮件失败: {ex.Message}"); - //} - - - if (await _work.SaveChangesAsync() > 0) - { - return new ApiResponse(true, "用户注册成功,班级关联和邮箱确认邮件已发送。"); - } - else - { - return new ApiResponse("用户注册成功但班级关联失败。"); - } - - } - catch (Exception ex) - { - Console.Error.WriteLine($"注册过程中发生错误: {ex.Message}"); - return new ApiResponse($"注册过程中发生错误: {ex.Message}"); - } - } - } -} \ No newline at end of file diff --git a/TechHelper.Server/Services/UserServices.cs b/TechHelper.Server/Services/UserServices.cs deleted file mode 100644 index 4ef5e5a..0000000 --- a/TechHelper.Server/Services/UserServices.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Entities.Contracts; -using Entities.DTO; -using Microsoft.AspNetCore.Identity; -using SharedDATA.Api; -using TechHelper.Services; - -namespace TechHelper.Server.Services -{ - /// - /// 用户服务实现类 - /// 处理用户相关的业务逻辑操作 - /// - public class UserServices : IUserSerivces - { - - private readonly IUnitOfWork _unitOfWork; - private readonly IClassService _classService; - private readonly UserManager _userManager; - - /// - /// 初始化用户服务 - /// - /// 工作单元实例 - /// 班级服务实例 - /// 用户管理实例 - public UserServices(IUnitOfWork unitOfWork, IClassService classService, UserManager userManager) - { - _unitOfWork = unitOfWork; - _classService = classService; - _userManager = userManager; - } - - /// - /// 添加新用户 - /// - /// 用户实体对象 - /// 操作结果响应 - public Task AddAsync(User model) - { - throw new NotImplementedException(); - } - - /// - /// 删除指定用户 - /// - /// 用户唯一标识符 - /// 操作结果响应 - public Task DeleteAsync(Guid id) - { - throw new NotImplementedException(); - } - - /// - /// 获取所有用户列表 - /// - /// 查询参数对象 - /// 用户列表响应 - public Task GetAllAsync(QueryParameter query) - { - throw new NotImplementedException(); - } - - /// - /// 获取指定用户信息 - /// - /// 用户唯一标识符 - /// 用户信息响应 - public Task GetAsync(Guid id) - { - throw new NotImplementedException(); - } - - /// - /// 获取学生详细信息 - /// - /// 用户唯一标识符 - /// 学生详细信息响应 - public Task GetStudentDetailInfo(Guid userId) - { - throw new NotImplementedException(); - } - - /// - /// 恢复用户角色信息 - /// 根据用户所在班级信息恢复用户的角色权限 - /// - /// 用户实体对象 - /// 操作结果响应 - public async Task RestoreUserRoleInformation(User user) - { - var result = await _classService.GetUserClassRole(user.Id); - if (result.Status) - { - var classRole = result.Result as UserClassRoleDto; - if (classRole != null) - { - if (!await _userManager.IsInRoleAsync(user, classRole.Role)) - { - await _userManager.AddToRoleAsync(user, classRole.Role); - - return ApiResponse.Success(); - } - } - } - return ApiResponse.Error(); - } - - /// - /// 更新用户信息 - /// - /// 用户实体对象 - /// 操作结果响应 - public Task UpdateAsync(User model) - { - throw new NotImplementedException(); - } - - /// - /// 验证用户信息 - /// - /// 用户唯一标识符 - /// 验证结果响应 - public Task VerifyUserInformation(Guid userId) - { - throw new NotImplementedException(); - } - } -} diff --git a/TechHelper.Server/TechHelper.Server.csproj b/TechHelper.Server/TechHelper.Server.csproj index 5c00dd7..9ee9ad0 100644 --- a/TechHelper.Server/TechHelper.Server.csproj +++ b/TechHelper.Server/TechHelper.Server.csproj @@ -8,6 +8,34 @@ Linux + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18,6 +46,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -33,4 +62,8 @@ + + + + diff --git a/TechHelper.Server/WeatherForecast.cs b/TechHelper.Server/WeatherForecast.cs deleted file mode 100644 index 95fd18f..0000000 --- a/TechHelper.Server/WeatherForecast.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TechHelper.Server -{ - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } - } -} diff --git a/TechHelper.Server/appsettings.json b/TechHelper.Server/appsettings.json index 3e21c47..3ff34a5 100644 --- a/TechHelper.Server/appsettings.json +++ b/TechHelper.Server/appsettings.json @@ -6,16 +6,16 @@ } }, "ConnectionStrings": { - "XSDB": "Server=mysql.eazygame.cn;Port=13002;Database=test1;User=root;Password=wx1998WX" + "XSDB": "Server=mysql.eazygame.cn;Port=13002;Database=test3;User=root;Password=wx1998WX" }, "JWTSettings": { "securityKey": "MxcxQHVYVDQ0U3lqWkIwdjZlSGx4eFp6YnFpUGxodmc5Y3hPZk5vWm9MZEg2Y0I=", "validIssuer": "CodeMazeAPI", - "validAudience": "http://localhost:5099", - "expiryInMinutes": 5 + "validAudience": "http://localhost:8080", + "expiryInMinutes": 1200 }, "ApiConfiguration": { - "BaseAddress": "http://localhost:5099" + "BaseAddress": "http://localhost:8080" }, "EmailConfiguration": { "From": "1468441589@qq.com", diff --git a/TechHelper.sln b/TechHelper.sln index efa6d84..6031c86 100644 --- a/TechHelper.sln +++ b/TechHelper.sln @@ -19,28 +19,78 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entities", "Entities\Entiti EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmailLib", "EmailLib\EmailLib.csproj", "{A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechHelper.Server.Tests", "TechHelper.Server.Tests\TechHelper.Server.Tests.csproj", "{8A86854F-9DF7-4538-BA09-2BF89CAB00B0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|x64.ActiveCfg = Debug|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|x64.Build.0 = Debug|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|x86.ActiveCfg = Debug|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Debug|x86.Build.0 = Debug|Any CPU {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|Any CPU.Build.0 = Release|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|x64.ActiveCfg = Release|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|x64.Build.0 = Release|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|x86.ActiveCfg = Release|Any CPU + {1C15B87F-4929-4262-8FBE-6281B5A31DF0}.Release|x86.Build.0 = Release|Any CPU {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|x64.ActiveCfg = Debug|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|x64.Build.0 = Debug|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|x86.ActiveCfg = Debug|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Debug|x86.Build.0 = Debug|Any CPU {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|Any CPU.Build.0 = Release|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|x64.ActiveCfg = Release|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|x64.Build.0 = Release|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|x86.ActiveCfg = Release|Any CPU + {084ECFE7-8F9C-4B75-A934-650E33507A4D}.Release|x86.Build.0 = Release|Any CPU {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|x64.ActiveCfg = Debug|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|x64.Build.0 = Debug|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|x86.ActiveCfg = Debug|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Debug|x86.Build.0 = Debug|Any CPU {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|Any CPU.ActiveCfg = Release|Any CPU {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|Any CPU.Build.0 = Release|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|x64.ActiveCfg = Release|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|x64.Build.0 = Release|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|x86.ActiveCfg = Release|Any CPU + {94A9A70B-A57A-4D70-A266-45AD6DAEEB82}.Release|x86.Build.0 = Release|Any CPU {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|x64.ActiveCfg = Debug|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|x64.Build.0 = Debug|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|x86.ActiveCfg = Debug|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Debug|x86.Build.0 = Debug|Any CPU {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|Any CPU.Build.0 = Release|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|x64.ActiveCfg = Release|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|x64.Build.0 = Release|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|x86.ActiveCfg = Release|Any CPU + {A4DD2BCA-E9E0-4866-BA2E-B1BBBFAF65CC}.Release|x86.Build.0 = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|x64.ActiveCfg = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|x64.Build.0 = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Debug|x86.Build.0 = Debug|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|Any CPU.Build.0 = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|x64.ActiveCfg = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|x64.Build.0 = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|x86.ActiveCfg = Release|Any CPU + {8A86854F-9DF7-4538-BA09-2BF89CAB00B0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE