From 4918eafa0d9b100158b2948f00efe48cc1322153 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 12 Apr 2020 15:03:45 +0300 Subject: [PATCH 1/9] new entities --- .../GraphLabs.Backend.Domain.csproj.user | 4 +++ GraphLabs.Backend.Domain/Student.cs | 2 ++ GraphLabs.Backend.Domain/Subject.cs | 19 ++++++++++++++ GraphLabs.Backend.Domain/TaskModule.cs | 2 ++ GraphLabs.Backend.Domain/TestAnswer.cs | 17 +++++++++++++ GraphLabs.Backend.Domain/TestQuestion.cs | 25 +++++++++++++++++++ GraphLabs.Backend.Domain/TestResult.cs | 23 +++++++++++++++++ GraphLabs.Backend.Domain/User.cs | 2 ++ 8 files changed, 94 insertions(+) create mode 100644 GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user create mode 100644 GraphLabs.Backend.Domain/Subject.cs create mode 100644 GraphLabs.Backend.Domain/TestAnswer.cs create mode 100644 GraphLabs.Backend.Domain/TestQuestion.cs create mode 100644 GraphLabs.Backend.Domain/TestResult.cs diff --git a/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user b/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/GraphLabs.Backend.Domain/Student.cs b/GraphLabs.Backend.Domain/Student.cs index 1617535..21336c2 100644 --- a/GraphLabs.Backend.Domain/Student.cs +++ b/GraphLabs.Backend.Domain/Student.cs @@ -7,5 +7,7 @@ public class Student : User public virtual string Group { get; set; } public virtual ICollection Logs { get; set; } + + public virtual ICollection TestResults { get; set; } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Domain/Subject.cs b/GraphLabs.Backend.Domain/Subject.cs new file mode 100644 index 0000000..1896a6d --- /dev/null +++ b/GraphLabs.Backend.Domain/Subject.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class Subject + { + public virtual long Id { get; set; } + + public virtual string Name { get; set; } + + public virtual string Description { get; set; } + + public virtual ICollection TaskModules { get; set; } + + public virtual ICollection TestQuestions { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TaskModule.cs b/GraphLabs.Backend.Domain/TaskModule.cs index 0108ad0..4542da8 100644 --- a/GraphLabs.Backend.Domain/TaskModule.cs +++ b/GraphLabs.Backend.Domain/TaskModule.cs @@ -13,6 +13,8 @@ public class TaskModule public virtual string Description { get; set; } public virtual string Version { get; set; } + + public virtual Subject Subject { get; set; } public virtual ICollection Variants { get; set; } } diff --git a/GraphLabs.Backend.Domain/TestAnswer.cs b/GraphLabs.Backend.Domain/TestAnswer.cs new file mode 100644 index 0000000..922d1bc --- /dev/null +++ b/GraphLabs.Backend.Domain/TestAnswer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestAnswer + { + public virtual long Id { get; set; } + + public virtual string Answer { get; set; } + + public virtual bool IsRight { get; set; } + + public virtual TestQuestion Question { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TestQuestion.cs b/GraphLabs.Backend.Domain/TestQuestion.cs new file mode 100644 index 0000000..b5c32f2 --- /dev/null +++ b/GraphLabs.Backend.Domain/TestQuestion.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestQuestion + { + public virtual long Id { get; set; } + + public virtual string Description { get; set; } + + public enum Difficulty : int { Three, Four, Five } + + public virtual int MaxScore { get; set; } + + public virtual string ImageURL { get; set; } + + public virtual TestResult TestResult { get; set; } + + public virtual Subject Subject { get; set; } + + public virtual ICollection Answers { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TestResult.cs b/GraphLabs.Backend.Domain/TestResult.cs new file mode 100644 index 0000000..f88fa83 --- /dev/null +++ b/GraphLabs.Backend.Domain/TestResult.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestResult + { + public virtual long Id { get; set; } + + public virtual DateTime DateTime { get; set; } + + public virtual int Mark { get; set; } + + public enum MarkEU : int { F, E, D, C, B, A } + + public enum MarkRU : int { Two = 2, Three = 3, Four = 4, Five = 5 } + + public virtual Student Student { get; set; } + + public virtual ICollection Questions { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/User.cs b/GraphLabs.Backend.Domain/User.cs index baa3b6d..9a3ac14 100644 --- a/GraphLabs.Backend.Domain/User.cs +++ b/GraphLabs.Backend.Domain/User.cs @@ -16,5 +16,7 @@ public abstract class User public virtual byte[] PasswordHash { get; set; } public virtual byte[] PasswordSalt { get; set; } + + public virtual string Token { get; set; } } } \ No newline at end of file From 568684aeb539805e305c7d2634937bfb78dfe4f5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 19 Apr 2020 18:29:16 +0300 Subject: [PATCH 2/9] update database structure --- .gitignore | 1 + .../GraphLabs.Backend.Domain.csproj.user | 4 --- GraphLabs.Backend.Domain/Mark.cs | 31 +++++++++++++++++++ GraphLabs.Backend.Domain/TestQuestion.cs | 8 ++--- GraphLabs.Backend.Domain/TestResult.cs | 6 ++-- GraphLabs.Backend.Domain/TestResultAnswer.cs | 17 ++++++++++ .../TestResultQuestion.cs | 19 ++++++++++++ GraphLabs.Backend.Domain/TestStudentAnswer.cs | 19 ++++++++++++ 8 files changed, 92 insertions(+), 13 deletions(-) delete mode 100644 GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user create mode 100644 GraphLabs.Backend.Domain/Mark.cs create mode 100644 GraphLabs.Backend.Domain/TestResultAnswer.cs create mode 100644 GraphLabs.Backend.Domain/TestResultQuestion.cs create mode 100644 GraphLabs.Backend.Domain/TestStudentAnswer.cs diff --git a/.gitignore b/.gitignore index 4355b4a..ad18024 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.idea /.vs /*.user +/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user # Build results [Dd]ebug/ diff --git a/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user b/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user deleted file mode 100644 index 88a5509..0000000 --- a/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/GraphLabs.Backend.Domain/Mark.cs b/GraphLabs.Backend.Domain/Mark.cs new file mode 100644 index 0000000..4522062 --- /dev/null +++ b/GraphLabs.Backend.Domain/Mark.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public enum MarkRU + { + Two = 2, + Three = 3, + Four = 4, + Five = 5 + } + + public enum MarkEU + { + F = 0, + E = 60, + D = 65, + C = 75, + B = 85, + A = 90 + } + + public enum Difficulty + { + Three = 3, + Four = 4, + Five = 5 + } +} diff --git a/GraphLabs.Backend.Domain/TestQuestion.cs b/GraphLabs.Backend.Domain/TestQuestion.cs index b5c32f2..22459a8 100644 --- a/GraphLabs.Backend.Domain/TestQuestion.cs +++ b/GraphLabs.Backend.Domain/TestQuestion.cs @@ -8,16 +8,12 @@ public class TestQuestion { public virtual long Id { get; set; } - public virtual string Description { get; set; } + public virtual string PlainText { get; set; } - public enum Difficulty : int { Three, Four, Five } + public virtual Difficulty Difficulty { get; set; } public virtual int MaxScore { get; set; } - public virtual string ImageURL { get; set; } - - public virtual TestResult TestResult { get; set; } - public virtual Subject Subject { get; set; } public virtual ICollection Answers { get; set; } diff --git a/GraphLabs.Backend.Domain/TestResult.cs b/GraphLabs.Backend.Domain/TestResult.cs index f88fa83..9e0f398 100644 --- a/GraphLabs.Backend.Domain/TestResult.cs +++ b/GraphLabs.Backend.Domain/TestResult.cs @@ -12,12 +12,12 @@ public class TestResult public virtual int Mark { get; set; } - public enum MarkEU : int { F, E, D, C, B, A } + public virtual MarkEU MarkEU { get; set; } - public enum MarkRU : int { Two = 2, Three = 3, Four = 4, Five = 5 } + public virtual MarkRU MarkRU { get; set; } public virtual Student Student { get; set; } - public virtual ICollection Questions { get; set; } + public virtual ICollection TestResultQuestions { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestResultAnswer.cs b/GraphLabs.Backend.Domain/TestResultAnswer.cs new file mode 100644 index 0000000..7b41e09 --- /dev/null +++ b/GraphLabs.Backend.Domain/TestResultAnswer.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestResultAnswer + { + public virtual long Id { get; set; } + + public virtual string Answer { get; set; } + + public virtual bool IsRight { get; set; } + + public virtual TestResultQuestion TestResultQuestion { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TestResultQuestion.cs b/GraphLabs.Backend.Domain/TestResultQuestion.cs new file mode 100644 index 0000000..608e2ed --- /dev/null +++ b/GraphLabs.Backend.Domain/TestResultQuestion.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestResultQuestion + { + public virtual long Id { get; set; } + + public virtual string Question { get; set; } + + public virtual string Subject { get; set; } + + public virtual ICollection TestStudentAnswers { get; set; } + + public virtual ICollection TestResultAnswers { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TestStudentAnswer.cs b/GraphLabs.Backend.Domain/TestStudentAnswer.cs new file mode 100644 index 0000000..106cf88 --- /dev/null +++ b/GraphLabs.Backend.Domain/TestStudentAnswer.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestStudentAnswer + { + public virtual long Id { get; set; } + + public virtual long AnswerId { get; set; } + + public virtual string Answer { get; set; } + + public virtual bool IsRight { get; set; } + + public virtual TestResultQuestion TestResultQuestion { get; set; } + } +} From ad7ff92714a68a881a32d0aa137754e7cdc8ef09 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 19 Apr 2020 20:14:23 +0300 Subject: [PATCH 3/9] update | subject --- GraphLabs.Backend.Domain/Subject.cs | 2 ++ GraphLabs.Backend.Domain/TestResultQuestion.cs | 2 +- GraphLabs.Backend.Domain/User.cs | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GraphLabs.Backend.Domain/Subject.cs b/GraphLabs.Backend.Domain/Subject.cs index 1896a6d..dcf8fab 100644 --- a/GraphLabs.Backend.Domain/Subject.cs +++ b/GraphLabs.Backend.Domain/Subject.cs @@ -15,5 +15,7 @@ public class Subject public virtual ICollection TaskModules { get; set; } public virtual ICollection TestQuestions { get; set; } + + public virtual ICollection TestResultQuestions { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestResultQuestion.cs b/GraphLabs.Backend.Domain/TestResultQuestion.cs index 608e2ed..a3776c7 100644 --- a/GraphLabs.Backend.Domain/TestResultQuestion.cs +++ b/GraphLabs.Backend.Domain/TestResultQuestion.cs @@ -10,7 +10,7 @@ public class TestResultQuestion public virtual string Question { get; set; } - public virtual string Subject { get; set; } + public virtual Subject Subject { get; set; } public virtual ICollection TestStudentAnswers { get; set; } diff --git a/GraphLabs.Backend.Domain/User.cs b/GraphLabs.Backend.Domain/User.cs index 9a3ac14..baa3b6d 100644 --- a/GraphLabs.Backend.Domain/User.cs +++ b/GraphLabs.Backend.Domain/User.cs @@ -16,7 +16,5 @@ public abstract class User public virtual byte[] PasswordHash { get; set; } public virtual byte[] PasswordSalt { get; set; } - - public virtual string Token { get; set; } } } \ No newline at end of file From 1dd83dae701238ff524ccc60484417370efe1039 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 22 Apr 2020 09:27:52 +0300 Subject: [PATCH 4/9] update --- GraphLabs.Backend.Domain/Subject.cs | 2 -- GraphLabs.Backend.Domain/TestAnswer.cs | 2 +- GraphLabs.Backend.Domain/TestQuestion.cs | 8 +------ .../TestQuestionVersion.cs | 23 +++++++++++++++++++ GraphLabs.Backend.Domain/TestResult.cs | 4 ++-- GraphLabs.Backend.Domain/TestResultAnswer.cs | 17 -------------- .../TestResultQuestion.cs | 19 --------------- GraphLabs.Backend.Domain/TestStudentAnswer.cs | 4 +++- 8 files changed, 30 insertions(+), 49 deletions(-) create mode 100644 GraphLabs.Backend.Domain/TestQuestionVersion.cs delete mode 100644 GraphLabs.Backend.Domain/TestResultAnswer.cs delete mode 100644 GraphLabs.Backend.Domain/TestResultQuestion.cs diff --git a/GraphLabs.Backend.Domain/Subject.cs b/GraphLabs.Backend.Domain/Subject.cs index dcf8fab..1896a6d 100644 --- a/GraphLabs.Backend.Domain/Subject.cs +++ b/GraphLabs.Backend.Domain/Subject.cs @@ -15,7 +15,5 @@ public class Subject public virtual ICollection TaskModules { get; set; } public virtual ICollection TestQuestions { get; set; } - - public virtual ICollection TestResultQuestions { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestAnswer.cs b/GraphLabs.Backend.Domain/TestAnswer.cs index 922d1bc..51b1684 100644 --- a/GraphLabs.Backend.Domain/TestAnswer.cs +++ b/GraphLabs.Backend.Domain/TestAnswer.cs @@ -12,6 +12,6 @@ public class TestAnswer public virtual bool IsRight { get; set; } - public virtual TestQuestion Question { get; set; } + public virtual TestQuestionVersion TestQuestionVersion { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestQuestion.cs b/GraphLabs.Backend.Domain/TestQuestion.cs index 22459a8..efb129e 100644 --- a/GraphLabs.Backend.Domain/TestQuestion.cs +++ b/GraphLabs.Backend.Domain/TestQuestion.cs @@ -8,14 +8,8 @@ public class TestQuestion { public virtual long Id { get; set; } - public virtual string PlainText { get; set; } - - public virtual Difficulty Difficulty { get; set; } - - public virtual int MaxScore { get; set; } - public virtual Subject Subject { get; set; } - public virtual ICollection Answers { get; set; } + public virtual ICollection TestQuestionVersions { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestQuestionVersion.cs b/GraphLabs.Backend.Domain/TestQuestionVersion.cs new file mode 100644 index 0000000..78b4cb5 --- /dev/null +++ b/GraphLabs.Backend.Domain/TestQuestionVersion.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace GraphLabs.Backend.Domain +{ + public class TestQuestionVersion + { + public virtual long Id { get; set; } + + public virtual string PlainText { get; set; } + + public virtual Difficulty Difficulty { get; set; } + + public virtual int MaxScore { get; set; } + + public virtual TestQuestion TestQuestion { get; set; } + + public virtual ICollection TestStudentAnswers { get; set; } + + public virtual ICollection TestAnswers { get; set; } + } +} diff --git a/GraphLabs.Backend.Domain/TestResult.cs b/GraphLabs.Backend.Domain/TestResult.cs index 9e0f398..5fce67a 100644 --- a/GraphLabs.Backend.Domain/TestResult.cs +++ b/GraphLabs.Backend.Domain/TestResult.cs @@ -10,7 +10,7 @@ public class TestResult public virtual DateTime DateTime { get; set; } - public virtual int Mark { get; set; } + public virtual int Score { get; set; } public virtual MarkEU MarkEU { get; set; } @@ -18,6 +18,6 @@ public class TestResult public virtual Student Student { get; set; } - public virtual ICollection TestResultQuestions { get; set; } + public virtual ICollection TestStudentAnswer { get; set; } } } diff --git a/GraphLabs.Backend.Domain/TestResultAnswer.cs b/GraphLabs.Backend.Domain/TestResultAnswer.cs deleted file mode 100644 index 7b41e09..0000000 --- a/GraphLabs.Backend.Domain/TestResultAnswer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace GraphLabs.Backend.Domain -{ - public class TestResultAnswer - { - public virtual long Id { get; set; } - - public virtual string Answer { get; set; } - - public virtual bool IsRight { get; set; } - - public virtual TestResultQuestion TestResultQuestion { get; set; } - } -} diff --git a/GraphLabs.Backend.Domain/TestResultQuestion.cs b/GraphLabs.Backend.Domain/TestResultQuestion.cs deleted file mode 100644 index a3776c7..0000000 --- a/GraphLabs.Backend.Domain/TestResultQuestion.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace GraphLabs.Backend.Domain -{ - public class TestResultQuestion - { - public virtual long Id { get; set; } - - public virtual string Question { get; set; } - - public virtual Subject Subject { get; set; } - - public virtual ICollection TestStudentAnswers { get; set; } - - public virtual ICollection TestResultAnswers { get; set; } - } -} diff --git a/GraphLabs.Backend.Domain/TestStudentAnswer.cs b/GraphLabs.Backend.Domain/TestStudentAnswer.cs index 106cf88..f21412d 100644 --- a/GraphLabs.Backend.Domain/TestStudentAnswer.cs +++ b/GraphLabs.Backend.Domain/TestStudentAnswer.cs @@ -14,6 +14,8 @@ public class TestStudentAnswer public virtual bool IsRight { get; set; } - public virtual TestResultQuestion TestResultQuestion { get; set; } + public virtual TestResult TestResult { get; set; } + + public virtual TestQuestionVersion TestQuestionVersion { get; set; } } } From 550327e238c2ab086663b6572d171c26f78c8e3e Mon Sep 17 00:00:00 2001 From: Svyatoslav Zakhryapin Date: Thu, 23 Apr 2020 15:37:02 +0300 Subject: [PATCH 5/9] =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20200423115639_TestQuestions.Designer.cs | 323 ++++++++++++++++++ .../20200423115639_TestQuestions.cs | 226 ++++++++++++ .../GraphLabsContextModelSnapshot.cs | 162 +++++++++ GraphLabs.Backend.Api/Startup.cs | 11 +- 4 files changed, 721 insertions(+), 1 deletion(-) create mode 100644 GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.Designer.cs create mode 100644 GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.cs diff --git a/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.Designer.cs b/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.Designer.cs new file mode 100644 index 0000000..d4b4edb --- /dev/null +++ b/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.Designer.cs @@ -0,0 +1,323 @@ +// +using System; +using GraphLabs.Backend.DAL; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace GraphLabs.Backend.Api.Migrations +{ + [DbContext(typeof(GraphLabsContext))] + [Migration("20200423115639_TestQuestions")] + partial class TestQuestions + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Subject"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("Name"); + + b.Property("SubjectId"); + + b.Property("Version"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("TaskModules"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.Property("TaskModuleId"); + + b.Property("VariantData"); + + b.HasKey("Id"); + + b.HasIndex("TaskModuleId"); + + b.ToTable("TaskVariants"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariantLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action") + .IsRequired(); + + b.Property("DateTime"); + + b.Property("Penalty"); + + b.Property("StudentId"); + + b.Property("VariantId"); + + b.HasKey("Id"); + + b.HasIndex("DateTime"); + + b.HasIndex("StudentId"); + + b.HasIndex("VariantId"); + + b.ToTable("TaskVariantLogs"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("IsRight"); + + b.Property("TestQuestionVersionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionVersionId"); + + b.ToTable("TestAnswer"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("SubjectId"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("TestQuestion"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Difficulty"); + + b.Property("MaxScore"); + + b.Property("PlainText"); + + b.Property("TestQuestionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionId"); + + b.ToTable("TestQuestionVersion"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateTime"); + + b.Property("MarkEU"); + + b.Property("MarkRU"); + + b.Property("Score"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("StudentId"); + + b.ToTable("TestResult"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("AnswerId"); + + b.Property("IsRight"); + + b.Property("TestQuestionVersionId"); + + b.Property("TestResultId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionVersionId"); + + b.HasIndex("TestResultId"); + + b.ToTable("TestStudentAnswer"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Discriminator") + .IsRequired(); + + b.Property("Email") + .IsRequired(); + + b.Property("FatherName"); + + b.Property("FirstName") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.Property("PasswordHash") + .IsRequired(); + + b.Property("PasswordSalt") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + + b.HasDiscriminator("Discriminator").HasValue("User"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Student", b => + { + b.HasBaseType("GraphLabs.Backend.Domain.User"); + + b.Property("Group"); + + b.HasIndex("Group"); + + b.HasDiscriminator().HasValue("Student"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Teacher", b => + { + b.HasBaseType("GraphLabs.Backend.Domain.User"); + + b.HasDiscriminator().HasValue("Teacher"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TaskModules") + .HasForeignKey("SubjectId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => + { + b.HasOne("GraphLabs.Backend.Domain.TaskModule", "TaskModule") + .WithMany("Variants") + .HasForeignKey("TaskModuleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariantLog", b => + { + b.HasOne("GraphLabs.Backend.Domain.Student", "Student") + .WithMany("Logs") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("GraphLabs.Backend.Domain.TaskVariant", "Variant") + .WithMany("Logs") + .HasForeignKey("VariantId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestAnswers") + .HasForeignKey("TestQuestionVersionId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TestQuestions") + .HasForeignKey("SubjectId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestion", "TestQuestion") + .WithMany("TestQuestionVersions") + .HasForeignKey("TestQuestionId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.HasOne("GraphLabs.Backend.Domain.Student", "Student") + .WithMany("TestResults") + .HasForeignKey("StudentId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestStudentAnswers") + .HasForeignKey("TestQuestionVersionId"); + + b.HasOne("GraphLabs.Backend.Domain.TestResult", "TestResult") + .WithMany("TestStudentAnswer") + .HasForeignKey("TestResultId"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.cs b/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.cs new file mode 100644 index 0000000..19f0d9f --- /dev/null +++ b/GraphLabs.Backend.Api/Migrations/20200423115639_TestQuestions.cs @@ -0,0 +1,226 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace GraphLabs.Backend.Api.Migrations +{ + public partial class TestQuestions : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Subject", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Name = table.Column(nullable: true), + Description = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Subject", x => x.Id); + }); + + const long defaultSubjectId = 1; + migrationBuilder.Sql($"INSERT INTO \"Subject\" (\"Id\", \"Name\", \"Description\") VALUES " + + $"({defaultSubjectId}, 'Default', 'Default subject')"); + + migrationBuilder.AddColumn( + name: "SubjectId", + table: "TaskModules", + nullable: false, + defaultValue: defaultSubjectId); + + migrationBuilder.CreateTable( + name: "TestResult", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + DateTime = table.Column(nullable: false), + Score = table.Column(nullable: false), + MarkEU = table.Column(nullable: false), + MarkRU = table.Column(nullable: false), + StudentId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TestResult", x => x.Id); + table.ForeignKey( + name: "FK_TestResult_Users_StudentId", + column: x => x.StudentId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "TestQuestion", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + SubjectId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TestQuestion", x => x.Id); + table.ForeignKey( + name: "FK_TestQuestion_Subject_SubjectId", + column: x => x.SubjectId, + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "TestQuestionVersion", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + PlainText = table.Column(nullable: true), + Difficulty = table.Column(nullable: false), + MaxScore = table.Column(nullable: false), + TestQuestionId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TestQuestionVersion", x => x.Id); + table.ForeignKey( + name: "FK_TestQuestionVersion_TestQuestion_TestQuestionId", + column: x => x.TestQuestionId, + principalTable: "TestQuestion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "TestAnswer", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Answer = table.Column(nullable: true), + IsRight = table.Column(nullable: false), + TestQuestionVersionId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TestAnswer", x => x.Id); + table.ForeignKey( + name: "FK_TestAnswer_TestQuestionVersion_TestQuestionVersionId", + column: x => x.TestQuestionVersionId, + principalTable: "TestQuestionVersion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "TestStudentAnswer", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AnswerId = table.Column(nullable: false), + Answer = table.Column(nullable: true), + IsRight = table.Column(nullable: false), + TestResultId = table.Column(nullable: true), + TestQuestionVersionId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TestStudentAnswer", x => x.Id); + table.ForeignKey( + name: "FK_TestStudentAnswer_TestQuestionVersion_TestQuestionVersionId", + column: x => x.TestQuestionVersionId, + principalTable: "TestQuestionVersion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_TestStudentAnswer_TestResult_TestResultId", + column: x => x.TestResultId, + principalTable: "TestResult", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_TaskModules_SubjectId", + table: "TaskModules", + column: "SubjectId"); + + migrationBuilder.CreateIndex( + name: "IX_TestAnswer_TestQuestionVersionId", + table: "TestAnswer", + column: "TestQuestionVersionId"); + + migrationBuilder.CreateIndex( + name: "IX_TestQuestion_SubjectId", + table: "TestQuestion", + column: "SubjectId"); + + migrationBuilder.CreateIndex( + name: "IX_TestQuestionVersion_TestQuestionId", + table: "TestQuestionVersion", + column: "TestQuestionId"); + + migrationBuilder.CreateIndex( + name: "IX_TestResult_StudentId", + table: "TestResult", + column: "StudentId"); + + migrationBuilder.CreateIndex( + name: "IX_TestStudentAnswer_TestQuestionVersionId", + table: "TestStudentAnswer", + column: "TestQuestionVersionId"); + + migrationBuilder.CreateIndex( + name: "IX_TestStudentAnswer_TestResultId", + table: "TestStudentAnswer", + column: "TestResultId"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskModules_Subject_SubjectId", + table: "TaskModules", + column: "SubjectId", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TaskModules_Subject_SubjectId", + table: "TaskModules"); + + migrationBuilder.DropTable( + name: "TestAnswer"); + + migrationBuilder.DropTable( + name: "TestStudentAnswer"); + + migrationBuilder.DropTable( + name: "TestQuestionVersion"); + + migrationBuilder.DropTable( + name: "TestResult"); + + migrationBuilder.DropTable( + name: "TestQuestion"); + + migrationBuilder.DropTable( + name: "Subject"); + + migrationBuilder.DropIndex( + name: "IX_TaskModules_SubjectId", + table: "TaskModules"); + + migrationBuilder.DropColumn( + name: "SubjectId", + table: "TaskModules"); + } + } +} diff --git a/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs b/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs index 97f36a0..d48e5dd 100644 --- a/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs +++ b/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs @@ -19,6 +19,20 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") .HasAnnotation("Relational:MaxIdentifierLength", 63); + modelBuilder.Entity("GraphLabs.Backend.Domain.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Subject"); + }); + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => { b.Property("Id") @@ -28,10 +42,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Name"); + b.Property("SubjectId"); + b.Property("Version"); b.HasKey("Id"); + b.HasIndex("SubjectId"); + b.ToTable("TaskModules"); }); @@ -80,6 +98,104 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("TaskVariantLogs"); }); + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("IsRight"); + + b.Property("TestQuestionVersionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionVersionId"); + + b.ToTable("TestAnswer"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("SubjectId"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("TestQuestion"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Difficulty"); + + b.Property("MaxScore"); + + b.Property("PlainText"); + + b.Property("TestQuestionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionId"); + + b.ToTable("TestQuestionVersion"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateTime"); + + b.Property("MarkEU"); + + b.Property("MarkRU"); + + b.Property("Score"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("StudentId"); + + b.ToTable("TestResult"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("AnswerId"); + + b.Property("IsRight"); + + b.Property("TestQuestionVersionId"); + + b.Property("TestResultId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionVersionId"); + + b.HasIndex("TestResultId"); + + b.ToTable("TestStudentAnswer"); + }); + modelBuilder.Entity("GraphLabs.Backend.Domain.User", b => { b.Property("Id") @@ -133,6 +249,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("Teacher"); }); + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TaskModules") + .HasForeignKey("SubjectId"); + }); + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => { b.HasOne("GraphLabs.Backend.Domain.TaskModule", "TaskModule") @@ -153,6 +276,45 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("VariantId") .OnDelete(DeleteBehavior.Restrict); }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestAnswers") + .HasForeignKey("TestQuestionVersionId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TestQuestions") + .HasForeignKey("SubjectId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestion", "TestQuestion") + .WithMany("TestQuestionVersions") + .HasForeignKey("TestQuestionId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.HasOne("GraphLabs.Backend.Domain.Student", "Student") + .WithMany("TestResults") + .HasForeignKey("StudentId"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestStudentAnswers") + .HasForeignKey("TestQuestionVersionId"); + + b.HasOne("GraphLabs.Backend.Domain.TestResult", "TestResult") + .WithMany("TestStudentAnswer") + .HasForeignKey("TestResultId"); + }); #pragma warning restore 612, 618 } } diff --git a/GraphLabs.Backend.Api/Startup.cs b/GraphLabs.Backend.Api/Startup.cs index 42aff21..e367264 100644 --- a/GraphLabs.Backend.Api/Startup.cs +++ b/GraphLabs.Backend.Api/Startup.cs @@ -49,12 +49,21 @@ public void ConfigureServices(IServiceCollection services) var migrationsAssembly = GetType().Assembly.FullName; var postgresHost = Environment.GetEnvironmentVariable("DB_HOST"); + var postgresPort = Environment.GetEnvironmentVariable("DB_PORT"); + postgresPort = string.IsNullOrWhiteSpace(postgresPort) + ? "5432" + : postgresPort; var postgresDb = Environment.GetEnvironmentVariable("DB_NAME"); var postgresUser = Environment.GetEnvironmentVariable("DB_USER"); var postgresPassword = Environment.GetEnvironmentVariable("DB_PASSWORD"); services.AddDbContext( - o => o.UseNpgsql($"Host={postgresHost};Database={postgresDb};Username={postgresUser};Password={postgresPassword}", b => b.MigrationsAssembly(migrationsAssembly))); + o => + { + o.UseNpgsql( + $"Host={postgresHost};Port={postgresPort};Database={postgresDb};Username={postgresUser};Password={postgresPassword}", + b => b.MigrationsAssembly(migrationsAssembly)); + }); if (_environment.IsDevelopment()) { From 9320d7ecb383b14319ffd7f60fe45c5e29de77d4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 23 Apr 2020 19:10:35 +0300 Subject: [PATCH 6/9] new entities --- .gitignore | 4 +- GraphLabs.Backend.Api/Program.cs | 12 +++- .../Properties/launchSettings.json | 21 ++++-- GraphLabs.Backend.DAL/GraphLabsContext.cs | 70 ++++++++++++++++++- GraphLabs.Backend.DAL/InitialData.cs | 35 +++++++--- 5 files changed, 122 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index ad18024..18705da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ # IDE /.idea /.vs -/*.user -/GraphLabs.Backend.Domain/GraphLabs.Backend.Domain.csproj.user +*.user + # Build results [Dd]ebug/ diff --git a/GraphLabs.Backend.Api/Program.cs b/GraphLabs.Backend.Api/Program.cs index 9b24ee5..4d99190 100644 --- a/GraphLabs.Backend.Api/Program.cs +++ b/GraphLabs.Backend.Api/Program.cs @@ -57,10 +57,18 @@ private static IWebHostBuilder CreateWebHostBuilder(string[] args) private static async Task InitializeDb(GraphLabsContext context, InitialData initialData) { await context.Database.MigrateAsync(); - + + if (!context.Subjects.Any()) + { + foreach (var subject in initialData.GetSubjects()) + { + context.Subjects.Add(subject); + } + await context.SaveChangesAsync(); + } if (!context.TaskModules.Any()) { - foreach (var module in initialData.GetTaskModules()) + foreach (var module in initialData.GetTaskModules(context.Subjects)) { context.TaskModules.Add(module); } diff --git a/GraphLabs.Backend.Api/Properties/launchSettings.json b/GraphLabs.Backend.Api/Properties/launchSettings.json index d71f07d..b0f85da 100644 --- a/GraphLabs.Backend.Api/Properties/launchSettings.json +++ b/GraphLabs.Backend.Api/Properties/launchSettings.json @@ -1,19 +1,25 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", +{ "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, + "windowsAuthentication": false, + "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:42384", "sslPort": 44363 } }, + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "api/values", "environmentVariables": { + "DB_USER": "graphlabs-test", + "DB_NAME": "graphlabs-test", + "DB_PORT": "54032", + "DB_PASSWORD": "felelcrKKDSef!!!", + "DB_HOST": "109.173.118.8", + "ASPNETCORE_URLS": "https://localhost:5001;https://localhost:5000", "ASPNETCORE_ENVIRONMENT": "Development" } }, @@ -21,10 +27,13 @@ "commandName": "Project", "launchBrowser": true, "launchUrl": "api/values", - "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + }, + "Profile1": { + "commandName": "Executable" } } } \ No newline at end of file diff --git a/GraphLabs.Backend.DAL/GraphLabsContext.cs b/GraphLabs.Backend.DAL/GraphLabsContext.cs index a93918b..45c1180 100644 --- a/GraphLabs.Backend.DAL/GraphLabsContext.cs +++ b/GraphLabs.Backend.DAL/GraphLabsContext.cs @@ -59,6 +59,12 @@ private void DbConnectionOnStateChange(object sender, StateChangeEventArgs e) public DbSet Students { get; protected set; } public DbSet Teachers { get; protected set; } public DbSet TaskVariantLogs { get; protected set; } + public DbSet Subjects { get; protected set; } + public DbSet TestResults { get; protected set; } + public DbSet TestStudentAnswers { get; protected set; } + public DbSet TestQuestions { get; protected set; } + public DbSet TestQuestionVersions { get; protected set; } + public DbSet TestAnswers { get; protected set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { @@ -71,9 +77,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .IsRequired() .OnDelete(DeleteBehavior.Cascade); + var subject = modelBuilder.Entity(); + subject.HasKey(s => s.Id); + var taskModule = modelBuilder.Entity(); taskModule.HasKey(t => t.Id); - + taskModule + .HasOne(t => t.Subject) + .WithMany(s => s.TaskModules) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + var user = modelBuilder.Entity(); user.HasKey(u => u.Id); user.Property(u => u.Email).IsRequired(); @@ -103,6 +117,60 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .HasForeignKey(l => l.StudentId) .OnDelete(DeleteBehavior.Cascade); log.HasIndex(l => l.DateTime); + + var testQuestion = modelBuilder.Entity(); + testQuestion + .HasKey(q => q.Id); + testQuestion + .HasOne(s => s.Subject) + .WithMany(q => q.TestQuestions) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + var testQuestionVersion = modelBuilder.Entity(); + testQuestionVersion + .HasKey(v => v.Id); + testQuestionVersion + .HasOne(v => v.TestQuestion) + .WithMany(q => q.TestQuestionVersions) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + var testAnswer = modelBuilder.Entity(); + testAnswer + .HasKey(a => a.Id); + testAnswer + .HasOne(a => a.TestQuestionVersion) + .WithMany(v => v.TestAnswers) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + var testStudentAnswer = modelBuilder.Entity(); + testStudentAnswer + .HasKey(a => a.Id); + testStudentAnswer + .HasOne(a => a.TestQuestionVersion) + .WithMany(v => v.TestStudentAnswers) + .IsRequired() + .HasForeignKey(a => a.AnswerId) + .OnDelete(DeleteBehavior.Restrict); + testStudentAnswer + .HasOne(a => a.TestResult) + .WithMany(r => r.TestStudentAnswer) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); + + var testResult = modelBuilder.Entity(); + testResult.HasKey(r => r.Id); + testResult.Property(r => r.Score).IsRequired(); + testResult.Property(r => r.MarkEU).IsRequired(); + testResult.Property(r => r.MarkRU).IsRequired(); + testResult.HasIndex(r => r.DateTime); + testResult + .HasOne(r => r.Student) + .WithMany(s => s.TestResults) + .IsRequired() + .OnDelete(DeleteBehavior.Cascade); } public override void Dispose() diff --git a/GraphLabs.Backend.DAL/InitialData.cs b/GraphLabs.Backend.DAL/InitialData.cs index f511c2e..348c6fd 100644 --- a/GraphLabs.Backend.DAL/InitialData.cs +++ b/GraphLabs.Backend.DAL/InitialData.cs @@ -15,8 +15,18 @@ public InitialData(PasswordHashCalculator calculator) { _calculator = calculator; } - - public IEnumerable GetTaskModules() + + public IEnumerable GetSubjects() + { + yield return new Subject + { + Id = 1, + Name = "Тема 1", + Description = "Описание темы 1" + }; + } + + public IEnumerable GetTaskModules(IEnumerable subjects) { // taskModule #1 yield return new TaskModule @@ -24,7 +34,8 @@ public IEnumerable GetTaskModules() Id = 1, Name = "Шаблон", Description = "Шаблон модуля.", - Version = "2.0" + Version = "2.0", + Subject = subjects.ElementAt(0) }; // taskModule #2 @@ -33,7 +44,8 @@ public IEnumerable GetTaskModules() Id = 2, Name = "Внешняя устойчивость", Description = "Модуль Лизы", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; // taskModule #3 @@ -42,7 +54,8 @@ public IEnumerable GetTaskModules() Id = 3, Name = "Планарность", Description = "Модуль Насти", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; // taskModule #4 @@ -51,7 +64,8 @@ public IEnumerable GetTaskModules() Id = 4, Name = "Изоморфизм", Description = "Модуль Насти", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; // taskModule #5 @@ -60,7 +74,8 @@ public IEnumerable GetTaskModules() Id = 5, Name = "Построить граф по матрице смежности", Description = "Модуль Эллины", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; // taskModule #6 @@ -69,7 +84,8 @@ public IEnumerable GetTaskModules() Id = 6, Name = "Построить матрицу смежности по графу", Description = "Модуль Наташи", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; // taskModule #7 @@ -78,7 +94,8 @@ public IEnumerable GetTaskModules() Id = 7, Name = "Построить матрицу инцидентности по графу", Description = "Модуль Наташи", - Version = "1.0" + Version = "1.0", + Subject = subjects.ElementAt(0) }; } From 0db318a8c749cd3342158ed17dfc6f1588c2f6cb Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 Apr 2020 19:09:55 +0300 Subject: [PATCH 7/9] subject, get post --- .gitignore | 3 + .../Controllers/SubjectsController.cs | 91 ++++ .../GraphLabs.Backend.Api.csproj | 1 + ...00_20200426140200_TestQuestion.Designer.cs | 330 ++++++++++++ ...00426080500_20200426140200_TestQuestion.cs | 501 ++++++++++++++++++ .../GraphLabsContextModelSnapshot.cs | 53 +- GraphLabs.Backend.Api/Program.cs | 3 +- .../Properties/launchSettings.json | 16 +- GraphLabs.Backend.Api/Startup.cs | 6 + 9 files changed, 974 insertions(+), 30 deletions(-) create mode 100644 GraphLabs.Backend.Api/Controllers/SubjectsController.cs create mode 100644 GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.Designer.cs create mode 100644 GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.cs diff --git a/.gitignore b/.gitignore index 18705da..9417d65 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.idea /.vs *.user +*.csproj # Build results @@ -13,3 +14,5 @@ /GraphLabs.Backend.Api/db /GraphLabs.Backend.Api/wwwroot/modules /GraphLabs.Backend.Api/logs +/GraphLabs.Backend.Api/Properties/launchSettings.json + diff --git a/GraphLabs.Backend.Api/Controllers/SubjectsController.cs b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs new file mode 100644 index 0000000..638a62e --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("subjects")] + public class SubjectsController : Controller + { + private readonly GraphLabsContext _db; + + public SubjectsController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.Subjects; + } + + [ODataRoute("({key})")] + [EnableQuery] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.Subjects.Where(t => t.Id == key)); + } + + [HttpPost] + public async Task Post() + { + var subject = new Subject(); + var id = TryExecute(() => (_db.Subjects.Last().Id) + 1, "Не удалось извлечь subject id"); + subject.Id = id; + + var json = await Request.GetBodyAsString(); + var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); + + var name = TryExecute(() => jsonData["name"].Value(), "Не удалось прочитать значение subject name"); + if (name == null || name == "") + { + throw new SubjectConvertException("Полученное имя предмета пусто"); + } + subject.Name = name; + + var description = TryExecute(() => jsonData["description"].Value(), "Не удалось прочитать значение subject description"); + if (description == null || description == "") + { + throw new SubjectConvertException("Полученное описание предмета пусто"); + } + subject.Description = description; + + _db.Subjects.Add(subject); + await _db.SaveChangesAsync(); + + return Ok(); + } + + private class SubjectConvertException : Exception + { + public SubjectConvertException(string error) : base(error) + { + } + + public SubjectConvertException(string error, Exception inner) : base(error, inner) + { + } + } + + private static T TryExecute(Func f, string errorMessage) + { + try + { + return f(); + } + catch (Exception e) + { + throw new SubjectConvertException(errorMessage, e); + } + } + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/GraphLabs.Backend.Api.csproj b/GraphLabs.Backend.Api/GraphLabs.Backend.Api.csproj index 937f4b5..f339373 100644 --- a/GraphLabs.Backend.Api/GraphLabs.Backend.Api.csproj +++ b/GraphLabs.Backend.Api/GraphLabs.Backend.Api.csproj @@ -23,6 +23,7 @@ 2.0.3 + 12.0.1 diff --git a/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.Designer.cs b/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.Designer.cs new file mode 100644 index 0000000..b56048d --- /dev/null +++ b/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.Designer.cs @@ -0,0 +1,330 @@ +// +using System; +using GraphLabs.Backend.DAL; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace GraphLabs.Backend.Api.Migrations +{ + [DbContext(typeof(GraphLabsContext))] + [Migration("20200426080500_20200426140200_TestQuestion")] + partial class _20200426140200_TestQuestion + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Subject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("Subjects"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("Name"); + + b.Property("SubjectId"); + + b.Property("Version"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("TaskModules"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Name"); + + b.Property("TaskModuleId"); + + b.Property("VariantData"); + + b.HasKey("Id"); + + b.HasIndex("TaskModuleId"); + + b.ToTable("TaskVariants"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariantLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action") + .IsRequired(); + + b.Property("DateTime"); + + b.Property("Penalty"); + + b.Property("StudentId"); + + b.Property("VariantId"); + + b.HasKey("Id"); + + b.HasIndex("DateTime"); + + b.HasIndex("StudentId"); + + b.HasIndex("VariantId"); + + b.ToTable("TaskVariantLogs"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("IsRight"); + + b.Property("TestQuestionVersionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionVersionId"); + + b.ToTable("TestAnswers"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("SubjectId"); + + b.HasKey("Id"); + + b.HasIndex("SubjectId"); + + b.ToTable("TestQuestions"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Difficulty"); + + b.Property("MaxScore"); + + b.Property("PlainText"); + + b.Property("TestQuestionId"); + + b.HasKey("Id"); + + b.HasIndex("TestQuestionId"); + + b.ToTable("TestQuestionVersions"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateTime"); + + b.Property("MarkEU"); + + b.Property("MarkRU"); + + b.Property("Score"); + + b.Property("StudentId"); + + b.HasKey("Id"); + + b.HasIndex("DateTime"); + + b.HasIndex("StudentId"); + + b.ToTable("TestResults"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Answer"); + + b.Property("AnswerId"); + + b.Property("IsRight"); + + b.Property("TestResultId"); + + b.HasKey("Id"); + + b.HasIndex("AnswerId"); + + b.HasIndex("TestResultId"); + + b.ToTable("TestStudentAnswers"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Discriminator") + .IsRequired(); + + b.Property("Email") + .IsRequired(); + + b.Property("FatherName"); + + b.Property("FirstName") + .IsRequired(); + + b.Property("LastName") + .IsRequired(); + + b.Property("PasswordHash") + .IsRequired(); + + b.Property("PasswordSalt") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("Email") + .IsUnique(); + + b.ToTable("Users"); + + b.HasDiscriminator("Discriminator").HasValue("User"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Student", b => + { + b.HasBaseType("GraphLabs.Backend.Domain.User"); + + b.Property("Group"); + + b.HasIndex("Group"); + + b.HasDiscriminator().HasValue("Student"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.Teacher", b => + { + b.HasBaseType("GraphLabs.Backend.Domain.User"); + + b.HasDiscriminator().HasValue("Teacher"); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TaskModules") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => + { + b.HasOne("GraphLabs.Backend.Domain.TaskModule", "TaskModule") + .WithMany("Variants") + .HasForeignKey("TaskModuleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariantLog", b => + { + b.HasOne("GraphLabs.Backend.Domain.Student", "Student") + .WithMany("Logs") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("GraphLabs.Backend.Domain.TaskVariant", "Variant") + .WithMany("Logs") + .HasForeignKey("VariantId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestAnswers") + .HasForeignKey("TestQuestionVersionId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => + { + b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") + .WithMany("TestQuestions") + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestion", "TestQuestion") + .WithMany("TestQuestionVersions") + .HasForeignKey("TestQuestionId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => + { + b.HasOne("GraphLabs.Backend.Domain.Student", "Student") + .WithMany("TestResults") + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => + { + b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") + .WithMany("TestStudentAnswers") + .HasForeignKey("AnswerId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("GraphLabs.Backend.Domain.TestResult", "TestResult") + .WithMany("TestStudentAnswer") + .HasForeignKey("TestResultId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.cs b/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.cs new file mode 100644 index 0000000..458860d --- /dev/null +++ b/GraphLabs.Backend.Api/Migrations/20200426080500_20200426140200_TestQuestion.cs @@ -0,0 +1,501 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace GraphLabs.Backend.Api.Migrations +{ + public partial class _20200426140200_TestQuestion : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TaskModules_Subject_SubjectId", + table: "TaskModules"); + + migrationBuilder.DropForeignKey( + name: "FK_TestAnswer_TestQuestionVersion_TestQuestionVersionId", + table: "TestAnswer"); + + migrationBuilder.DropForeignKey( + name: "FK_TestQuestion_Subject_SubjectId", + table: "TestQuestion"); + + migrationBuilder.DropForeignKey( + name: "FK_TestQuestionVersion_TestQuestion_TestQuestionId", + table: "TestQuestionVersion"); + + migrationBuilder.DropForeignKey( + name: "FK_TestResult_Users_StudentId", + table: "TestResult"); + + migrationBuilder.DropForeignKey( + name: "FK_TestStudentAnswer_TestQuestionVersion_TestQuestionVersionId", + table: "TestStudentAnswer"); + + migrationBuilder.DropForeignKey( + name: "FK_TestStudentAnswer_TestResult_TestResultId", + table: "TestStudentAnswer"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestStudentAnswer", + table: "TestStudentAnswer"); + + migrationBuilder.DropIndex( + name: "IX_TestStudentAnswer_TestQuestionVersionId", + table: "TestStudentAnswer"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestResult", + table: "TestResult"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestQuestionVersion", + table: "TestQuestionVersion"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestQuestion", + table: "TestQuestion"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestAnswer", + table: "TestAnswer"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Subject", + table: "Subject"); + + migrationBuilder.DropColumn( + name: "TestQuestionVersionId", + table: "TestStudentAnswer"); + + migrationBuilder.RenameTable( + name: "TestStudentAnswer", + newName: "TestStudentAnswers"); + + migrationBuilder.RenameTable( + name: "TestResult", + newName: "TestResults"); + + migrationBuilder.RenameTable( + name: "TestQuestionVersion", + newName: "TestQuestionVersions"); + + migrationBuilder.RenameTable( + name: "TestQuestion", + newName: "TestQuestions"); + + migrationBuilder.RenameTable( + name: "TestAnswer", + newName: "TestAnswers"); + + migrationBuilder.RenameTable( + name: "Subject", + newName: "Subjects"); + + migrationBuilder.RenameIndex( + name: "IX_TestStudentAnswer_TestResultId", + table: "TestStudentAnswers", + newName: "IX_TestStudentAnswers_TestResultId"); + + migrationBuilder.RenameIndex( + name: "IX_TestResult_StudentId", + table: "TestResults", + newName: "IX_TestResults_StudentId"); + + migrationBuilder.RenameIndex( + name: "IX_TestQuestionVersion_TestQuestionId", + table: "TestQuestionVersions", + newName: "IX_TestQuestionVersions_TestQuestionId"); + + migrationBuilder.RenameIndex( + name: "IX_TestQuestion_SubjectId", + table: "TestQuestions", + newName: "IX_TestQuestions_SubjectId"); + + migrationBuilder.RenameIndex( + name: "IX_TestAnswer_TestQuestionVersionId", + table: "TestAnswers", + newName: "IX_TestAnswers_TestQuestionVersionId"); + + migrationBuilder.AlterColumn( + name: "SubjectId", + table: "TaskModules", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "TestResultId", + table: "TestStudentAnswers", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "StudentId", + table: "TestResults", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "TestQuestionId", + table: "TestQuestionVersions", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "SubjectId", + table: "TestQuestions", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "TestQuestionVersionId", + table: "TestAnswers", + nullable: false, + oldClrType: typeof(long), + oldNullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestStudentAnswers", + table: "TestStudentAnswers", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestResults", + table: "TestResults", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestQuestionVersions", + table: "TestQuestionVersions", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestQuestions", + table: "TestQuestions", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestAnswers", + table: "TestAnswers", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Subjects", + table: "Subjects", + column: "Id"); + + migrationBuilder.CreateIndex( + name: "IX_TestStudentAnswers_AnswerId", + table: "TestStudentAnswers", + column: "AnswerId"); + + migrationBuilder.CreateIndex( + name: "IX_TestResults_DateTime", + table: "TestResults", + column: "DateTime"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskModules_Subjects_SubjectId", + table: "TaskModules", + column: "SubjectId", + principalTable: "Subjects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TestAnswers_TestQuestionVersions_TestQuestionVersionId", + table: "TestAnswers", + column: "TestQuestionVersionId", + principalTable: "TestQuestionVersions", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TestQuestions_Subjects_SubjectId", + table: "TestQuestions", + column: "SubjectId", + principalTable: "Subjects", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TestQuestionVersions_TestQuestions_TestQuestionId", + table: "TestQuestionVersions", + column: "TestQuestionId", + principalTable: "TestQuestions", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TestResults_Users_StudentId", + table: "TestResults", + column: "StudentId", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_TestStudentAnswers_TestQuestionVersions_AnswerId", + table: "TestStudentAnswers", + column: "AnswerId", + principalTable: "TestQuestionVersions", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestStudentAnswers_TestResults_TestResultId", + table: "TestStudentAnswers", + column: "TestResultId", + principalTable: "TestResults", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_TaskModules_Subjects_SubjectId", + table: "TaskModules"); + + migrationBuilder.DropForeignKey( + name: "FK_TestAnswers_TestQuestionVersions_TestQuestionVersionId", + table: "TestAnswers"); + + migrationBuilder.DropForeignKey( + name: "FK_TestQuestions_Subjects_SubjectId", + table: "TestQuestions"); + + migrationBuilder.DropForeignKey( + name: "FK_TestQuestionVersions_TestQuestions_TestQuestionId", + table: "TestQuestionVersions"); + + migrationBuilder.DropForeignKey( + name: "FK_TestResults_Users_StudentId", + table: "TestResults"); + + migrationBuilder.DropForeignKey( + name: "FK_TestStudentAnswers_TestQuestionVersions_AnswerId", + table: "TestStudentAnswers"); + + migrationBuilder.DropForeignKey( + name: "FK_TestStudentAnswers_TestResults_TestResultId", + table: "TestStudentAnswers"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestStudentAnswers", + table: "TestStudentAnswers"); + + migrationBuilder.DropIndex( + name: "IX_TestStudentAnswers_AnswerId", + table: "TestStudentAnswers"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestResults", + table: "TestResults"); + + migrationBuilder.DropIndex( + name: "IX_TestResults_DateTime", + table: "TestResults"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestQuestionVersions", + table: "TestQuestionVersions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestQuestions", + table: "TestQuestions"); + + migrationBuilder.DropPrimaryKey( + name: "PK_TestAnswers", + table: "TestAnswers"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Subjects", + table: "Subjects"); + + migrationBuilder.RenameTable( + name: "TestStudentAnswers", + newName: "TestStudentAnswer"); + + migrationBuilder.RenameTable( + name: "TestResults", + newName: "TestResult"); + + migrationBuilder.RenameTable( + name: "TestQuestionVersions", + newName: "TestQuestionVersion"); + + migrationBuilder.RenameTable( + name: "TestQuestions", + newName: "TestQuestion"); + + migrationBuilder.RenameTable( + name: "TestAnswers", + newName: "TestAnswer"); + + migrationBuilder.RenameTable( + name: "Subjects", + newName: "Subject"); + + migrationBuilder.RenameIndex( + name: "IX_TestStudentAnswers_TestResultId", + table: "TestStudentAnswer", + newName: "IX_TestStudentAnswer_TestResultId"); + + migrationBuilder.RenameIndex( + name: "IX_TestResults_StudentId", + table: "TestResult", + newName: "IX_TestResult_StudentId"); + + migrationBuilder.RenameIndex( + name: "IX_TestQuestionVersions_TestQuestionId", + table: "TestQuestionVersion", + newName: "IX_TestQuestionVersion_TestQuestionId"); + + migrationBuilder.RenameIndex( + name: "IX_TestQuestions_SubjectId", + table: "TestQuestion", + newName: "IX_TestQuestion_SubjectId"); + + migrationBuilder.RenameIndex( + name: "IX_TestAnswers_TestQuestionVersionId", + table: "TestAnswer", + newName: "IX_TestAnswer_TestQuestionVersionId"); + + migrationBuilder.AlterColumn( + name: "SubjectId", + table: "TaskModules", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AlterColumn( + name: "TestResultId", + table: "TestStudentAnswer", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AddColumn( + name: "TestQuestionVersionId", + table: "TestStudentAnswer", + nullable: true); + + migrationBuilder.AlterColumn( + name: "StudentId", + table: "TestResult", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AlterColumn( + name: "TestQuestionId", + table: "TestQuestionVersion", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AlterColumn( + name: "SubjectId", + table: "TestQuestion", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AlterColumn( + name: "TestQuestionVersionId", + table: "TestAnswer", + nullable: true, + oldClrType: typeof(long)); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestStudentAnswer", + table: "TestStudentAnswer", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestResult", + table: "TestResult", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestQuestionVersion", + table: "TestQuestionVersion", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestQuestion", + table: "TestQuestion", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_TestAnswer", + table: "TestAnswer", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Subject", + table: "Subject", + column: "Id"); + + migrationBuilder.CreateIndex( + name: "IX_TestStudentAnswer_TestQuestionVersionId", + table: "TestStudentAnswer", + column: "TestQuestionVersionId"); + + migrationBuilder.AddForeignKey( + name: "FK_TaskModules_Subject_SubjectId", + table: "TaskModules", + column: "SubjectId", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestAnswer_TestQuestionVersion_TestQuestionVersionId", + table: "TestAnswer", + column: "TestQuestionVersionId", + principalTable: "TestQuestionVersion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestQuestion_Subject_SubjectId", + table: "TestQuestion", + column: "SubjectId", + principalTable: "Subject", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestQuestionVersion_TestQuestion_TestQuestionId", + table: "TestQuestionVersion", + column: "TestQuestionId", + principalTable: "TestQuestion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestResult_Users_StudentId", + table: "TestResult", + column: "StudentId", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestStudentAnswer_TestQuestionVersion_TestQuestionVersionId", + table: "TestStudentAnswer", + column: "TestQuestionVersionId", + principalTable: "TestQuestionVersion", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_TestStudentAnswer_TestResult_TestResultId", + table: "TestStudentAnswer", + column: "TestResultId", + principalTable: "TestResult", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs b/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs index d48e5dd..c5a4a96 100644 --- a/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs +++ b/GraphLabs.Backend.Api/Migrations/GraphLabsContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) - .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("GraphLabs.Backend.Domain.Subject", b => @@ -30,7 +30,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.ToTable("Subject"); + b.ToTable("Subjects"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TaskModule", b => @@ -42,7 +42,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Name"); - b.Property("SubjectId"); + b.Property("SubjectId"); b.Property("Version"); @@ -107,13 +107,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("IsRight"); - b.Property("TestQuestionVersionId"); + b.Property("TestQuestionVersionId"); b.HasKey("Id"); b.HasIndex("TestQuestionVersionId"); - b.ToTable("TestAnswer"); + b.ToTable("TestAnswers"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => @@ -121,13 +121,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Id") .ValueGeneratedOnAdd(); - b.Property("SubjectId"); + b.Property("SubjectId"); b.HasKey("Id"); b.HasIndex("SubjectId"); - b.ToTable("TestQuestion"); + b.ToTable("TestQuestions"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => @@ -141,13 +141,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("PlainText"); - b.Property("TestQuestionId"); + b.Property("TestQuestionId"); b.HasKey("Id"); b.HasIndex("TestQuestionId"); - b.ToTable("TestQuestionVersion"); + b.ToTable("TestQuestionVersions"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => @@ -163,13 +163,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Score"); - b.Property("StudentId"); + b.Property("StudentId"); b.HasKey("Id"); + b.HasIndex("DateTime"); + b.HasIndex("StudentId"); - b.ToTable("TestResult"); + b.ToTable("TestResults"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => @@ -183,17 +185,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("IsRight"); - b.Property("TestQuestionVersionId"); - - b.Property("TestResultId"); + b.Property("TestResultId"); b.HasKey("Id"); - b.HasIndex("TestQuestionVersionId"); + b.HasIndex("AnswerId"); b.HasIndex("TestResultId"); - b.ToTable("TestStudentAnswer"); + b.ToTable("TestStudentAnswers"); }); modelBuilder.Entity("GraphLabs.Backend.Domain.User", b => @@ -253,7 +253,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") .WithMany("TaskModules") - .HasForeignKey("SubjectId"); + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TaskVariant", b => @@ -281,39 +282,45 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") .WithMany("TestAnswers") - .HasForeignKey("TestQuestionVersionId"); + .HasForeignKey("TestQuestionVersionId") + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestion", b => { b.HasOne("GraphLabs.Backend.Domain.Subject", "Subject") .WithMany("TestQuestions") - .HasForeignKey("SubjectId"); + .HasForeignKey("SubjectId") + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestQuestionVersion", b => { b.HasOne("GraphLabs.Backend.Domain.TestQuestion", "TestQuestion") .WithMany("TestQuestionVersions") - .HasForeignKey("TestQuestionId"); + .HasForeignKey("TestQuestionId") + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestResult", b => { b.HasOne("GraphLabs.Backend.Domain.Student", "Student") .WithMany("TestResults") - .HasForeignKey("StudentId"); + .HasForeignKey("StudentId") + .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("GraphLabs.Backend.Domain.TestStudentAnswer", b => { b.HasOne("GraphLabs.Backend.Domain.TestQuestionVersion", "TestQuestionVersion") .WithMany("TestStudentAnswers") - .HasForeignKey("TestQuestionVersionId"); + .HasForeignKey("AnswerId") + .OnDelete(DeleteBehavior.Restrict); b.HasOne("GraphLabs.Backend.Domain.TestResult", "TestResult") .WithMany("TestStudentAnswer") - .HasForeignKey("TestResultId"); + .HasForeignKey("TestResultId") + .OnDelete(DeleteBehavior.Cascade); }); #pragma warning restore 612, 618 } diff --git a/GraphLabs.Backend.Api/Program.cs b/GraphLabs.Backend.Api/Program.cs index 4d99190..64386ef 100644 --- a/GraphLabs.Backend.Api/Program.cs +++ b/GraphLabs.Backend.Api/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -57,7 +58,7 @@ private static IWebHostBuilder CreateWebHostBuilder(string[] args) private static async Task InitializeDb(GraphLabsContext context, InitialData initialData) { await context.Database.MigrateAsync(); - + if (!context.Subjects.Any()) { foreach (var subject in initialData.GetSubjects()) diff --git a/GraphLabs.Backend.Api/Properties/launchSettings.json b/GraphLabs.Backend.Api/Properties/launchSettings.json index b0f85da..b2e449e 100644 --- a/GraphLabs.Backend.Api/Properties/launchSettings.json +++ b/GraphLabs.Backend.Api/Properties/launchSettings.json @@ -2,17 +2,20 @@ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, + "iis": { + "applicationUrl": "http://localhost/GraphLabs.Backend.Api", + "sslPort": 0 + }, "iisExpress": { - "applicationUrl": "http://localhost:42384", - "sslPort": 44363 + "applicationUrl": "https://localhost:44338", + "sslPort": 44338 } }, "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "IIS Express": { "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "auth/login", "environmentVariables": { "DB_USER": "graphlabs-test", "DB_NAME": "graphlabs-test", @@ -21,12 +24,13 @@ "DB_HOST": "109.173.118.8", "ASPNETCORE_URLS": "https://localhost:5001;https://localhost:5000", "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "applicationUrl": "https://localhost:5000" }, "GraphLabs.Backend": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "api/values", + "launchUrl": "auth/login", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/GraphLabs.Backend.Api/Startup.cs b/GraphLabs.Backend.Api/Startup.cs index e367264..28c9cfd 100644 --- a/GraphLabs.Backend.Api/Startup.cs +++ b/GraphLabs.Backend.Api/Startup.cs @@ -171,6 +171,12 @@ private static IEdmModel GetEdmModel() Namespace = "GraphLabs" }; + // Subjects ============================================================================================= + var subject = builder.EntitySet("Subjects").EntityType; + subject.HasKey(m => m.Id); + subject.HasMany(m => m.TaskModules); + subject.HasMany(m => m.TestQuestions); + // TaskModules ============================================================================================= var taskModule = builder.EntitySet("TaskModules").EntityType; taskModule.HasKey(m => m.Id); From 6e52b86c9a66ec28e20b392ec8f980d2b6293403 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 28 Apr 2020 00:27:32 +0300 Subject: [PATCH 8/9] all tables, get post --- .../Controllers/SubjectsController.cs | 14 +- .../Controllers/TestAnswersController.cs | 95 +++++++++++ .../TestQuestionVersionsController.cs | 37 ++++ .../Controllers/TestQuestionsController.cs | 161 ++++++++++++++++++ .../Controllers/TestResultsController.cs | 36 ++++ .../TestStudentAnswersController.cs | 100 +++++++++++ GraphLabs.Backend.Api/Startup.cs | 33 +++- 7 files changed, 468 insertions(+), 8 deletions(-) create mode 100644 GraphLabs.Backend.Api/Controllers/TestAnswersController.cs create mode 100644 GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs create mode 100644 GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs create mode 100644 GraphLabs.Backend.Api/Controllers/TestResultsController.cs create mode 100644 GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs diff --git a/GraphLabs.Backend.Api/Controllers/SubjectsController.cs b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs index 638a62e..199aeb4 100644 --- a/GraphLabs.Backend.Api/Controllers/SubjectsController.cs +++ b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs @@ -38,10 +38,6 @@ public SingleResult Get(long key) [HttpPost] public async Task Post() { - var subject = new Subject(); - var id = TryExecute(() => (_db.Subjects.Last().Id) + 1, "Не удалось извлечь subject id"); - subject.Id = id; - var json = await Request.GetBodyAsString(); var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); @@ -50,15 +46,19 @@ public async Task Post() { throw new SubjectConvertException("Полученное имя предмета пусто"); } - subject.Name = name; var description = TryExecute(() => jsonData["description"].Value(), "Не удалось прочитать значение subject description"); if (description == null || description == "") { throw new SubjectConvertException("Полученное описание предмета пусто"); } - subject.Description = description; - + + var subject = new Subject + { + Name = name, + Description = description + }; + _db.Subjects.Add(subject); await _db.SaveChangesAsync(); diff --git a/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs b/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs new file mode 100644 index 0000000..cb788ae --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("testAnswers")] + public class TestAnswersController : Controller + { + private readonly GraphLabsContext _db; + + public TestAnswersController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.TestAnswers; + } + + [EnableQuery] + [ODataRoute("({key})")] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.TestAnswers.Where(t => t.Id == key)); + } + + [HttpPost] + public async Task Post() + { + var json = await Request.GetBodyAsString(); + var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); + var key = TryExecute(() => jsonData["key"].Value(), "Не удалось прочитать значение key"); + var testQuestionVersion = TryExecute(() => _db.TestQuestionVersions.Single(v => v.Id == key), $"Не существует вопроса с ключом {key}"); + + var answer = TryExecute(() => jsonData["answer"].Value(), "Не удалось прочитать значение TestAnswer answer"); + if (answer == null || answer == "") + { + throw new TestAnswerConvertException("Полученное значение answer пусто"); + } + + var isRight = TryExecute(() => jsonData["is_right"].Value(), "Не удалось прочитать значение TestAnswer is_right"); + + var testAnswer = new TestAnswer + { + Answer = answer, + IsRight = isRight, + TestQuestionVersion = testQuestionVersion + }; + _db.TestAnswers.Add(testAnswer); + + var collection = testQuestionVersion.TestAnswers; + collection.Add(testAnswer); + + testQuestionVersion.TestAnswers = collection; + + await _db.SaveChangesAsync(); + return Ok(key); + } + + private class TestAnswerConvertException : Exception + { + public TestAnswerConvertException(string error) : base(error) + { + } + + public TestAnswerConvertException(string error, Exception inner) : base(error, inner) + { + } + } + + private static T TryExecute(Func f, string errorMessage) + { + try + { + return f(); + } + catch (Exception e) + { + throw new TestAnswerConvertException(errorMessage, e); + } + } + + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs b/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs new file mode 100644 index 0000000..83c6e04 --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("testQuestionVersions")] + public class TestQuestionVersionsController : Controller + { + private readonly GraphLabsContext _db; + + public TestQuestionVersionsController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.TestQuestionVersions; + } + + [EnableQuery] + [ODataRoute("({key})")] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.TestQuestionVersions.Where(t => t.Id == key)); + } + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs b/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs new file mode 100644 index 0000000..66338f3 --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("testQuestions")] + public class TestQuestionsController : Controller + { + private readonly GraphLabsContext _db; + + public TestQuestionsController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.TestQuestions; + } + + + [EnableQuery] + [ODataRoute("({key})")] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.TestQuestions.Where(t => t.Id == key)); + } + + + // не работает route, что странно, в TaskVariantsLogsController это есть + // передаю TestQuestion.Id(то есть key) в json + // если key == null, то создается новый вопрос, иначе дополняется в ветку версий вопросов + [HttpPost] + public async Task Post() + { + //Проверка полученных данных + var json = await Request.GetBodyAsString(); + var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); + var key = jsonData["key"]; + + var plainText = TryExecute(() => jsonData["plain_text"].Value(), "Не удалось прочитать значение TestQuestion plain_text"); + if (plainText == null || plainText == "") + { + throw new TestQuestionConvertException("Полученное значение plain_text пусто"); + } + + var difficulty = new Difficulty(); + var difficultyString = TryExecute(() => jsonData["difficulty"].Value(), "Не удалось прочитать значение TestQuestion difficulty"); + if (difficultyString == null || difficultyString == "") + { + throw new TestQuestionConvertException("Полученное значение difficulty пусто"); + } + // костыль start + switch (difficultyString) + { + case "Three": + difficulty = Difficulty.Three; + break; + case "Four": + difficulty = Difficulty.Four; + break; + case "Five": + difficulty = Difficulty.Five; + break; + default: + throw new TestQuestionConvertException("Полученное значение difficulty не соответсвует требованиям"); + } + // костыль end + + var maxScore = TryExecute(() => jsonData["max_score"].Value(), "Не удалось прочитать значение TestQuestion max_score"); + if (maxScore.Equals(null)) + { + throw new TestQuestionConvertException("Полученное значение max_score пусто"); + } + + if (key.Type != JTokenType.Null) + { + //Update + var testQuestion = _db.TestQuestions.Single(q => q.Id == (long)key); + if (testQuestion == null) + { + throw new TestQuestionConvertException("Идентификатор key не совпадает ни с одним TestQuestion.Id"); + } + + var testQuestionVersion = new TestQuestionVersion + { + PlainText = plainText, + Difficulty = difficulty, + MaxScore = maxScore, + TestQuestion = testQuestion + }; + + _db.TestQuestionVersions.Add(testQuestionVersion); + } + else + { + //Create + var idSubject = TryExecute(() => jsonData["subject"].Value(), "Не удалось прочитать значение TestQuestion subject"); + if (idSubject.Equals(null)) + { + throw new TestQuestionConvertException("Полученное значение subject пусто"); + } + + var testQuestion = new TestQuestion(); + testQuestion.Subject = _db.Subjects.Single(s => s.Id == idSubject); + + var testQuestionVersion = new TestQuestionVersion + { + PlainText = plainText, + Difficulty = difficulty, + MaxScore = maxScore, + TestQuestion = testQuestion + }; + + var collection = new Collection(); + collection.Add(testQuestionVersion); + + testQuestion.TestQuestionVersions = collection; + + _db.TestQuestionVersions.Add(testQuestionVersion); + _db.TestQuestions.Add(testQuestion); + } + // сделать добавление в таблицу Subjects + await _db.SaveChangesAsync(); + return Ok(); + } + + private class TestQuestionConvertException : Exception + { + public TestQuestionConvertException(string error) : base(error) + { + } + + public TestQuestionConvertException(string error, Exception inner) : base(error, inner) + { + } + } + + private static T TryExecute(Func f, string errorMessage) + { + try + { + return f(); + } + catch (Exception e) + { + throw new TestQuestionConvertException(errorMessage, e); + } + } + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestResultsController.cs b/GraphLabs.Backend.Api/Controllers/TestResultsController.cs new file mode 100644 index 0000000..b3eeaa7 --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/TestResultsController.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Mvc; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("testResults")] + public class TestResultsController : Controller + { + private readonly GraphLabsContext _db; + + public TestResultsController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.TestResults; + } + + [ODataRoute("({key})")] + [EnableQuery] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.TestResults.Where(t => t.Id == key)); + } + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs b/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs new file mode 100644 index 0000000..7de57ae --- /dev/null +++ b/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GraphLabs.Backend.DAL; +using GraphLabs.Backend.Domain; +using Microsoft.AspNet.OData; +using Microsoft.AspNet.OData.Routing; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; + +namespace GraphLabs.Backend.Api.Controllers +{ + [ODataRoutePrefix("testStudentAnswers")] + public class TestStudentAnswersController : Controller + { + private readonly GraphLabsContext _db; + + public TestStudentAnswersController(GraphLabsContext context) + { + _db = context; + } + + [EnableQuery] + public IQueryable Get() + { + return _db.TestStudentAnswers; + } + + [ODataRoute("({key})")] + [EnableQuery] + public SingleResult Get(long key) + { + return SingleResult.Create(_db.TestStudentAnswers.Where(t => t.Id == key)); + } + + [HttpPost] + public async Task Post() + { + var json = await Request.GetBodyAsString(); + var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); + var key = TryExecute(() => jsonData["key"].Value(), "Не удалось прочитать значение key"); + var testQuestionVersion = TryExecute(() => _db.TestQuestionVersions.Single(v => v.Id == key), $"Не существует вопроса с ключом {key}"); + + var answer = TryExecute(() => jsonData["answer"].Value(), "Не удалось прочитать значение TestStudentAnswer answer"); + if (answer == null || answer == "") + { + throw new TestStudentAnswerConvertException("Полученное значение answer пусто"); + } + + var answerId = TryExecute(() => jsonData["answer_id"].Value(), "Не удалось прочитать значение TestStudentAnswer answer_id"); + var checkAnswerId = TryExecute(() => _db.TestAnswers.Single(v => v.Id == answerId), $"Не существует ответа с answer_id {answerId}"); + + var isRight = TryExecute(() => jsonData["is_right"].Value(), "Не удалось прочитать значение TestStudentAnswer is_right"); + + var testStudentAnswer = new TestStudentAnswer + { + Answer = answer, + AnswerId = answerId, + IsRight = isRight, + TestQuestionVersion = testQuestionVersion + }; + _db.TestStudentAnswers.Add(testStudentAnswer); + + var collection = testQuestionVersion.TestStudentAnswers; + collection.Add(testStudentAnswer); + + testQuestionVersion.TestStudentAnswers = collection; + + // сделать добавление в таблицу TestResults, а значит нужно еще + // написать метод проверки ответов + + await _db.SaveChangesAsync(); + return Ok(key); + } + + private class TestStudentAnswerConvertException : Exception + { + public TestStudentAnswerConvertException(string error) : base(error) + { + } + + public TestStudentAnswerConvertException(string error, Exception inner) : base(error, inner) + { + } + } + + private static T TryExecute(Func f, string errorMessage) + { + try + { + return f(); + } + catch (Exception e) + { + throw new TestStudentAnswerConvertException(errorMessage, e); + } + } + } +} \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Startup.cs b/GraphLabs.Backend.Api/Startup.cs index 28c9cfd..66e096b 100644 --- a/GraphLabs.Backend.Api/Startup.cs +++ b/GraphLabs.Backend.Api/Startup.cs @@ -171,16 +171,47 @@ private static IEdmModel GetEdmModel() Namespace = "GraphLabs" }; - // Subjects ============================================================================================= + // Subjects ================================================================================================ var subject = builder.EntitySet("Subjects").EntityType; subject.HasKey(m => m.Id); subject.HasMany(m => m.TaskModules); subject.HasMany(m => m.TestQuestions); + // TestQuestions =========================================================================================== + var testQuestion = builder.EntitySet("TestQuestions").EntityType; + testQuestion.HasKey(q => q.Id); + testQuestion.HasMany(q => q.TestQuestionVersions); + testQuestion.HasRequired(q => q.Subject); + + // TestQuestionVersions ==================================================================================== + var testQuestionVersion = builder.EntitySet("TestQuestionVersions").EntityType; + testQuestionVersion.HasKey(v => v.Id); + testQuestionVersion.HasMany(v => v.TestStudentAnswers); + testQuestionVersion.HasMany(v => v.TestAnswers); + testQuestionVersion.HasRequired(v => v.TestQuestion); + + // TesAnswers ============================================================================================== + var testAnswer = builder.EntitySet("TestAnswers").EntityType; + testAnswer.HasKey(a => a.Id); + testAnswer.HasRequired(a => a.TestQuestionVersion); + + // TestStudentAnswers ====================================================================================== + var testStudentAnswer = builder.EntitySet("TestStudentAnswers").EntityType; + testStudentAnswer.HasKey(a => a.Id); + testStudentAnswer.HasRequired(a => a.TestQuestionVersion); + testStudentAnswer.HasRequired(a => a.TestResult); + + // TestResults ============================================================================================= + var testResult = builder.EntitySet("TestResults").EntityType; + testResult.HasKey(r => r.Id); + testResult.HasMany(r => r.TestStudentAnswer); + testResult.HasRequired(r => r.Student); + // TaskModules ============================================================================================= var taskModule = builder.EntitySet("TaskModules").EntityType; taskModule.HasKey(m => m.Id); taskModule.HasMany(m => m.Variants); + taskModule.HasRequired(m => m.Subject); taskModule.Function(nameof(TaskModulesController.RandomVariant)).Returns(); From c1eaa62c15cc95bf647d6e6f8585e7bf3bd9b639 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 10 May 2020 19:15:13 +0300 Subject: [PATCH 9/9] get, post, delete(only answers), update readme --- .../Controllers/SubjectsController.cs | 50 ++---- .../Controllers/TestAnswersController.cs | 75 +++++---- .../TestQuestionVersionsController.cs | 51 +++++- .../Controllers/TestQuestionsController.cs | 152 +++++++----------- .../Controllers/TestResultsController.cs | 116 ++++++++++++- .../TestStudentAnswersController.cs | 65 +------- GraphLabs.Backend.Api/Startup.cs | 2 + README.md | 130 ++++++++++++++- 8 files changed, 400 insertions(+), 241 deletions(-) diff --git a/GraphLabs.Backend.Api/Controllers/SubjectsController.cs b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs index 199aeb4..6ba9212 100644 --- a/GraphLabs.Backend.Api/Controllers/SubjectsController.cs +++ b/GraphLabs.Backend.Api/Controllers/SubjectsController.cs @@ -13,7 +13,7 @@ namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("subjects")] - public class SubjectsController : Controller + public class SubjectsController : ODataController { private readonly GraphLabsContext _db; @@ -36,56 +36,30 @@ public SingleResult Get(long key) } [HttpPost] - public async Task Post() + public async Task Post([FromBody]CreateRequest request) { - var json = await Request.GetBodyAsString(); - var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); - - var name = TryExecute(() => jsonData["name"].Value(), "Не удалось прочитать значение subject name"); - if (name == null || name == "") - { - throw new SubjectConvertException("Полученное имя предмета пусто"); - } - - var description = TryExecute(() => jsonData["description"].Value(), "Не удалось прочитать значение subject description"); - if (description == null || description == "") - { - throw new SubjectConvertException("Полученное описание предмета пусто"); - } + if (request == null || + string.IsNullOrEmpty(request.Name) || + string.IsNullOrEmpty(request.Description)) + return BadRequest(); var subject = new Subject { - Name = name, - Description = description + Name = request.Name, + Description = request.Description }; _db.Subjects.Add(subject); await _db.SaveChangesAsync(); - return Ok(); + return Ok(subject.Id); } - private class SubjectConvertException : Exception + public class CreateRequest { - public SubjectConvertException(string error) : base(error) - { - } + public string Name { get; set; } - public SubjectConvertException(string error, Exception inner) : base(error, inner) - { - } - } - - private static T TryExecute(Func f, string errorMessage) - { - try - { - return f(); - } - catch (Exception e) - { - throw new SubjectConvertException(errorMessage, e); - } + public string Description { get; set; } } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs b/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs index cb788ae..f30d72d 100644 --- a/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs +++ b/GraphLabs.Backend.Api/Controllers/TestAnswersController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using GraphLabs.Backend.DAL; @@ -8,12 +7,11 @@ using Microsoft.AspNet.OData; using Microsoft.AspNet.OData.Routing; using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("testAnswers")] - public class TestAnswersController : Controller + public class TestAnswersController : ODataController { private readonly GraphLabsContext _db; @@ -36,60 +34,59 @@ public SingleResult Get(long key) } [HttpPost] - public async Task Post() + [ODataRoute("({key})")] + public async Task Post([FromBody]CreateRequest request, long key) { - var json = await Request.GetBodyAsString(); - var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); - var key = TryExecute(() => jsonData["key"].Value(), "Не удалось прочитать значение key"); - var testQuestionVersion = TryExecute(() => _db.TestQuestionVersions.Single(v => v.Id == key), $"Не существует вопроса с ключом {key}"); - - var answer = TryExecute(() => jsonData["answer"].Value(), "Не удалось прочитать значение TestAnswer answer"); - if (answer == null || answer == "") - { - throw new TestAnswerConvertException("Полученное значение answer пусто"); - } + if (request == null || string.IsNullOrEmpty(request.Answer)) + return BadRequest(); + + var testQuestionVersion = _db.TestQuestionVersions.Single(v => v.Id == key); + if (testQuestionVersion == null) + return BadRequest(); - var isRight = TryExecute(() => jsonData["is_right"].Value(), "Не удалось прочитать значение TestAnswer is_right"); - var testAnswer = new TestAnswer { - Answer = answer, - IsRight = isRight, + Answer = request.Answer, + IsRight = request.IsRight, TestQuestionVersion = testQuestionVersion }; - _db.TestAnswers.Add(testAnswer); - - var collection = testQuestionVersion.TestAnswers; - collection.Add(testAnswer); - - testQuestionVersion.TestAnswers = collection; - - await _db.SaveChangesAsync(); - return Ok(key); - } - - private class TestAnswerConvertException : Exception - { - public TestAnswerConvertException(string error) : base(error) + + if (testQuestionVersion.TestAnswers == null) { + testQuestionVersion.TestAnswers = new List { testAnswer }; } - - public TestAnswerConvertException(string error, Exception inner) : base(error, inner) + else { + testQuestionVersion.TestAnswers.Add(testAnswer); } + + await _db.SaveChangesAsync(); + return Ok(testAnswer.Id); } - private static T TryExecute(Func f, string errorMessage) + [HttpDelete] + [ODataRoute("({key})")] + public async Task Delete(long key) { - try + var answer = _db.TestAnswers.Single(v => v.Id == key); + if (answer != null) { - return f(); + _db.TestAnswers.Remove(answer); + await _db.SaveChangesAsync(); } - catch (Exception e) + else { - throw new TestAnswerConvertException(errorMessage, e); + return NotFound(); } + + return Ok(); } + public class CreateRequest + { + public string Answer { get; set; } + + public bool IsRight { get; set; } + } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs b/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs index 83c6e04..fbeea55 100644 --- a/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs +++ b/GraphLabs.Backend.Api/Controllers/TestQuestionVersionsController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using GraphLabs.Backend.DAL; @@ -7,12 +8,13 @@ using Microsoft.AspNet.OData; using Microsoft.AspNet.OData.Routing; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("testQuestionVersions")] - public class TestQuestionVersionsController : Controller + public class TestQuestionVersionsController : ODataController { private readonly GraphLabsContext _db; @@ -33,5 +35,52 @@ public SingleResult Get(long key) { return SingleResult.Create(_db.TestQuestionVersions.Where(t => t.Id == key)); } + + + //ODataRoute("createVariant") not working + [HttpPost] + public async Task Post([FromBody]CreateRequest[] request) + { + if (request == null) + return BadRequest(); + + var variant = new Collection(); + + foreach (var r in request) + { + if (r.SubjectId == 0 || r.Quantity == 0) + return BadRequest(); + + var subjectId = r.SubjectId; + var quantity = r.Quantity; + + var question = _db.TestQuestions.Where(w => w.Subject.Id == subjectId); + var questionLength = question.Count(); + + if (quantity > questionLength) + quantity = questionLength; + if (questionLength == 0) + return new NotFoundResult(); + + var questionArray = question.Select(s => s.Id).ToArray(); + for (var i = 0; i w != questionArrayRandomId).ToArray(); + var questionVersion = _db.TestQuestionVersions.Last(p => p.TestQuestion.Id == questionArrayRandomId); + variant.Add(questionVersion); + } + } + + return Ok(variant); + } + + public class CreateRequest + { + public long SubjectId { get; set; } + + public int Quantity { get; set; } + } + } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs b/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs index 66338f3..118e940 100644 --- a/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs +++ b/GraphLabs.Backend.Api/Controllers/TestQuestionsController.cs @@ -8,12 +8,13 @@ using Microsoft.AspNet.OData; using Microsoft.AspNet.OData.Routing; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json.Linq; namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("testQuestions")] - public class TestQuestionsController : Controller + public class TestQuestionsController : ODataController { private readonly GraphLabsContext _db; @@ -28,7 +29,6 @@ public IQueryable Get() return _db.TestQuestions; } - [EnableQuery] [ODataRoute("({key})")] public SingleResult Get(long key) @@ -36,126 +36,84 @@ public SingleResult Get(long key) return SingleResult.Create(_db.TestQuestions.Where(t => t.Id == key)); } - - // не работает route, что странно, в TaskVariantsLogsController это есть - // передаю TestQuestion.Id(то есть key) в json - // если key == null, то создается новый вопрос, иначе дополняется в ветку версий вопросов [HttpPost] - public async Task Post() + [ODataRoute("({key})")] + public async Task Post([FromBody]CreateRequest request, long key) { - //Проверка полученных данных - var json = await Request.GetBodyAsString(); - var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); - var key = jsonData["key"]; - - var plainText = TryExecute(() => jsonData["plain_text"].Value(), "Не удалось прочитать значение TestQuestion plain_text"); - if (plainText == null || plainText == "") + if (request == null || + request.MaxScore == 0 || + string.IsNullOrEmpty(request.PlainText) || + string.IsNullOrEmpty(request.Difficulty)) + return BadRequest(); + + TestQuestion testQuestion; + var testQuestionVersion = new TestQuestionVersion { - throw new TestQuestionConvertException("Полученное значение plain_text пусто"); - } + PlainText = request.PlainText, + Difficulty = GetDifficulty(request.Difficulty), + MaxScore = request.MaxScore + }; - var difficulty = new Difficulty(); - var difficultyString = TryExecute(() => jsonData["difficulty"].Value(), "Не удалось прочитать значение TestQuestion difficulty"); - if (difficultyString == null || difficultyString == "") - { - throw new TestQuestionConvertException("Полученное значение difficulty пусто"); - } - // костыль start - switch (difficultyString) + if (key == 0) { - case "Three": - difficulty = Difficulty.Three; - break; - case "Four": - difficulty = Difficulty.Four; - break; - case "Five": - difficulty = Difficulty.Five; - break; - default: - throw new TestQuestionConvertException("Полученное значение difficulty не соответсвует требованиям"); - } - // костыль end + //Create TestQuestion and TestQuestion.TestQuestionVersion + var subject = _db.Subjects.Single(s => s.Id == request.SubjectId); + if (subject == null) + return BadRequest(); - var maxScore = TryExecute(() => jsonData["max_score"].Value(), "Не удалось прочитать значение TestQuestion max_score"); - if (maxScore.Equals(null)) - { - throw new TestQuestionConvertException("Полученное значение max_score пусто"); - } + testQuestion = new TestQuestion + { + TestQuestionVersions = new List { testQuestionVersion }, + Subject = subject + }; - if (key.Type != JTokenType.Null) - { - //Update - var testQuestion = _db.TestQuestions.Single(q => q.Id == (long)key); - if (testQuestion == null) + if (subject.TestQuestions == null) { - throw new TestQuestionConvertException("Идентификатор key не совпадает ни с одним TestQuestion.Id"); + subject.TestQuestions = new List { testQuestion }; } - - var testQuestionVersion = new TestQuestionVersion + else { - PlainText = plainText, - Difficulty = difficulty, - MaxScore = maxScore, - TestQuestion = testQuestion - }; - - _db.TestQuestionVersions.Add(testQuestionVersion); + subject.TestQuestions.Add(testQuestion); + } + _db.TestQuestions.Add(testQuestion); } else { - //Create - var idSubject = TryExecute(() => jsonData["subject"].Value(), "Не удалось прочитать значение TestQuestion subject"); - if (idSubject.Equals(null)) - { - throw new TestQuestionConvertException("Полученное значение subject пусто"); - } - - var testQuestion = new TestQuestion(); - testQuestion.Subject = _db.Subjects.Single(s => s.Id == idSubject); - - var testQuestionVersion = new TestQuestionVersion - { - PlainText = plainText, - Difficulty = difficulty, - MaxScore = maxScore, - TestQuestion = testQuestion - }; - - var collection = new Collection(); - collection.Add(testQuestionVersion); + //Update TestQuestion.TestQuestionVersion + testQuestion = _db.TestQuestions.Include(q => q.TestQuestionVersions).Single(q => q.Id == key); + testQuestion.TestQuestionVersions.Add(testQuestionVersion); + } - testQuestion.TestQuestionVersions = collection; + testQuestionVersion.TestQuestion = testQuestion; + _db.TestQuestionVersions.Add(testQuestionVersion); - _db.TestQuestionVersions.Add(testQuestionVersion); - _db.TestQuestions.Add(testQuestion); - } - // сделать добавление в таблицу Subjects await _db.SaveChangesAsync(); - return Ok(); + return Ok(testQuestionVersion.Id); } - private class TestQuestionConvertException : Exception + public class CreateRequest { - public TestQuestionConvertException(string error) : base(error) - { - } + public string PlainText { get; set; } - public TestQuestionConvertException(string error, Exception inner) : base(error, inner) - { - } + public string Difficulty { get; set; } + + public int MaxScore { get; set; } + + public long? SubjectId { get; set; } } - private static T TryExecute(Func f, string errorMessage) + private Difficulty GetDifficulty(string diff) { - try + switch (diff) { - return f(); - } - catch (Exception e) - { - throw new TestQuestionConvertException(errorMessage, e); + case "Three": + return Difficulty.Three; + case "Four": + return Difficulty.Four; + case "Five": + return Difficulty.Five; } + return Difficulty.Three; } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestResultsController.cs b/GraphLabs.Backend.Api/Controllers/TestResultsController.cs index b3eeaa7..027761e 100644 --- a/GraphLabs.Backend.Api/Controllers/TestResultsController.cs +++ b/GraphLabs.Backend.Api/Controllers/TestResultsController.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using GraphLabs.Backend.DAL; @@ -11,7 +12,7 @@ namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("testResults")] - public class TestResultsController : Controller + public class TestResultsController : ODataController { private readonly GraphLabsContext _db; @@ -32,5 +33,118 @@ public SingleResult Get(long key) { return SingleResult.Create(_db.TestResults.Where(t => t.Id == key)); } + + [HttpPost] + public async Task Post([FromBody]CreateRequest[] request) + { + if (request == null) + return BadRequest(); + + var testResult = new TestResult(); + float fullScore = 0; + float studentScore = 0; + var collectionStudentAnswers = new Collection(); + foreach (var r in request) + { + if (r == null || + r.AnswerId == 0 || + r.StudentId == 0 || + r.TestQuestionVersionId == 0 || + string.IsNullOrEmpty(r.Answer)) + { + return BadRequest(); + } + + var testQuestionVersion = _db.TestQuestionVersions.Single(v => v.Id == r.TestQuestionVersionId); + var testStudentAnswer = new TestStudentAnswer + { + AnswerId = r.AnswerId, + Answer = r.Answer, + IsRight = r.IsRight, + TestQuestionVersion = testQuestionVersion, + TestResult = testResult + }; + var testAnswer = _db.TestAnswers.Single(p => p.Id == r.AnswerId); + float maxScoreForTask = (float) testStudentAnswer.TestQuestionVersion.MaxScore; + float maxScoreForOneQuestion = (float) (maxScoreForTask / _db.TestAnswers.Count(t => t.TestQuestionVersion.Id == testStudentAnswer.TestQuestionVersion.Id)); + if (testStudentAnswer.Answer == testAnswer.Answer && testStudentAnswer.IsRight == testAnswer.IsRight) + studentScore += maxScoreForOneQuestion; + fullScore += maxScoreForOneQuestion; + + if (testQuestionVersion.TestStudentAnswers == null) + { + testQuestionVersion.TestStudentAnswers = new List { testStudentAnswer }; + } + else + { + testQuestionVersion.TestStudentAnswers.Add(testStudentAnswer); + } + collectionStudentAnswers.Add(testStudentAnswer); + } + + var student = _db.Students.Single(s => s.Id == request[0].StudentId); + int score = (int)((100 * studentScore) / fullScore); + testResult.Score = score; + testResult.DateTime = DateTime.Now; + testResult.MarkEU = GetMarkEU(score); + testResult.MarkRU = GetMarkRU(score); + testResult.TestStudentAnswer = collectionStudentAnswers; + testResult.Student = student; + + if (student.TestResults == null) + { + student.TestResults = new List { testResult }; + } + else + { + student.TestResults.Add(testResult); + } + + //await _db.SaveChangesAsync(); + return Created(testResult.Id); + } + + public class CreateRequest + { + public long TestQuestionVersionId { get; set; } + + public string Answer { get; set; } + + public long AnswerId { get; set; } + + public bool IsRight { get; set; } + + public long StudentId { get; set; } + } + + private MarkRU GetMarkRU(int score) + { + if (score >= 0 && score <= 59) + return MarkRU.Two; + if (score >= 60 && score <= 69) + return MarkRU.Three; + if (score >= 70 && score <= 89) + return MarkRU.Four; + if (score >= 90 && score <= 100) + return MarkRU.Five; + return MarkRU.Two; + } + + private MarkEU GetMarkEU(int score) + { + if (score >= 0 && score <= 59) + return MarkEU.F; + if (score >= 60 && score <= 64) + return MarkEU.E; + if (score >= 65 && score <= 74) + return MarkEU.D; + if (score >= 75 && score <= 84) + return MarkEU.C; + if (score >= 85 && score <= 89) + return MarkEU.B; + if (score >= 90 && score <= 100) + return MarkEU.A; + return MarkEU.F; + } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs b/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs index 7de57ae..fb388bb 100644 --- a/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs +++ b/GraphLabs.Backend.Api/Controllers/TestStudentAnswersController.cs @@ -12,7 +12,7 @@ namespace GraphLabs.Backend.Api.Controllers { [ODataRoutePrefix("testStudentAnswers")] - public class TestStudentAnswersController : Controller + public class TestStudentAnswersController : ODataController { private readonly GraphLabsContext _db; @@ -33,68 +33,5 @@ public SingleResult Get(long key) { return SingleResult.Create(_db.TestStudentAnswers.Where(t => t.Id == key)); } - - [HttpPost] - public async Task Post() - { - var json = await Request.GetBodyAsString(); - var jsonData = TryExecute(() => JObject.Parse(json), "Не удалось распарсить данные."); - var key = TryExecute(() => jsonData["key"].Value(), "Не удалось прочитать значение key"); - var testQuestionVersion = TryExecute(() => _db.TestQuestionVersions.Single(v => v.Id == key), $"Не существует вопроса с ключом {key}"); - - var answer = TryExecute(() => jsonData["answer"].Value(), "Не удалось прочитать значение TestStudentAnswer answer"); - if (answer == null || answer == "") - { - throw new TestStudentAnswerConvertException("Полученное значение answer пусто"); - } - - var answerId = TryExecute(() => jsonData["answer_id"].Value(), "Не удалось прочитать значение TestStudentAnswer answer_id"); - var checkAnswerId = TryExecute(() => _db.TestAnswers.Single(v => v.Id == answerId), $"Не существует ответа с answer_id {answerId}"); - - var isRight = TryExecute(() => jsonData["is_right"].Value(), "Не удалось прочитать значение TestStudentAnswer is_right"); - - var testStudentAnswer = new TestStudentAnswer - { - Answer = answer, - AnswerId = answerId, - IsRight = isRight, - TestQuestionVersion = testQuestionVersion - }; - _db.TestStudentAnswers.Add(testStudentAnswer); - - var collection = testQuestionVersion.TestStudentAnswers; - collection.Add(testStudentAnswer); - - testQuestionVersion.TestStudentAnswers = collection; - - // сделать добавление в таблицу TestResults, а значит нужно еще - // написать метод проверки ответов - - await _db.SaveChangesAsync(); - return Ok(key); - } - - private class TestStudentAnswerConvertException : Exception - { - public TestStudentAnswerConvertException(string error) : base(error) - { - } - - public TestStudentAnswerConvertException(string error, Exception inner) : base(error, inner) - { - } - } - - private static T TryExecute(Func f, string errorMessage) - { - try - { - return f(); - } - catch (Exception e) - { - throw new TestStudentAnswerConvertException(errorMessage, e); - } - } } } \ No newline at end of file diff --git a/GraphLabs.Backend.Api/Startup.cs b/GraphLabs.Backend.Api/Startup.cs index 66e096b..9aa6bf6 100644 --- a/GraphLabs.Backend.Api/Startup.cs +++ b/GraphLabs.Backend.Api/Startup.cs @@ -190,6 +190,8 @@ private static IEdmModel GetEdmModel() testQuestionVersion.HasMany(v => v.TestAnswers); testQuestionVersion.HasRequired(v => v.TestQuestion); + //testQuestionVersion.Function(nameof(TestQuestionVersionsController.CreateVariant)).Returns(); + // TesAnswers ============================================================================================== var testAnswer = builder.EntitySet("TestAnswers").EntityType; testAnswer.HasKey(a => a.Id); diff --git a/README.md b/README.md index 879cbe6..ed22e16 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - [X] Научить логи заданий получать пользователя из данных аутентификации - [ ] Logout - [x] Лог выполнения +- [x] Подсистема тестирования студентов ## Технологии * Asp.Net Core @@ -65,6 +66,7 @@ _Authorization_ : "Bearer бла-бла-бла", где бла-бла-бла - ## Примеры использования +#### Лабораторный комплекс **Метаданные:** > **GET** http://localhost:5000/odata/$metadata @@ -187,4 +189,130 @@ _Body:_ ```binary data: zip archive``` **Запросить информацию о текущем пользователе:** -> **GET** http://localhost:5000/odata/currentUser \ No newline at end of file +> **GET** http://localhost:5000/odata/currentUser + +#### Подсистема тестирования студентов + +**Список тем:** +> **GET** http://localhost:5000/odata/subjects + +**Тема с идентификатором 1:** +> **GET** http://localhost:5000/odata/subjects(1) + +**Загрузить название новой темы:** +> **POST** http://localhost:5000/odata/subjects +_Content-Type:_ application/json +_Body:_ +```json +{ + "Name": "Название темы", + "Description": "Описание темы" +} +``` + +**Список вопросов:** +> **GET** http://localhost:5000/odata/testQuestions + +**Вопрос с идентификатором 1:** +> **GET** http://localhost:5000/odata/testQuestions(1) + +**Загрузить новый вопрос:** +> **POST** http://localhost:5000/odata/testQuestions +_Content-Type:_ application/json +_Body:_ +```json +{ + "PlainText": "Текст задания", + "Difficulty": "Four", + "MaxScore": 10, + "SubjectId": 2 +} +``` + +**Обновить вопрос с идентификатором 1:** +> **POST** http://localhost:5000/odata/testQuestions(1) +_Content-Type:_ application/json +_Body:_ +```json +{ + "PlainText": "Текст задания", + "Difficulty": "Five", + "MaxScore": 15 +} +``` + +**Список версий вопроса:** +> **GET** http://localhost:5000/odata/testQuestionVersions + +**Версия вопроса с идентификатором 1:** +> **GET** http://localhost:5000/odata/testQuestionVersions(1) + +**Создание варианта с одним вопросом по теме 1 и двумя вопросами по теме 2:** +> **POST** http://localhost:5000/odata/testQuestions +_Content-Type:_ application/json +_Body:_ +```json +[ + { + "SubjectId": 1, + "Quantity": 1 + }, + { + "SubjectId": 2, + "Quantity": 2 + } +] +``` + +**Список ответов:** +> **GET** http://localhost:5000/odata/testAnswers + +**Ответ с идентификатором 1:** +> **GET** http://localhost:5000/odata/testAnswers(1) + +**Загрузить новый ответ для вопроса 2 (TestQuestionVersionId = 2):** +> **POST** http://localhost:5000/odata/testAnswers(2) +_Content-Type:_ application/json +_Body:_ +```json +{ + "Answer": "Ответ на задание", + "IsRight": 1, +} +``` + +**Список ответов студента:** +> **GET** http://localhost:5000/odata/testStudentAnswers + +**Ответ студента с идентификатором 1:** +> **GET** http://localhost:5000/odata/testStudentAnswers(1) + +**Список всех результатов:** +> **GET** http://localhost:5000/odata/testResults + +**Результат с идентификатором 1:** +> **GET** http://localhost:5000/odata/testResults(1) + +**Загрузить новый результат:** +> **POST** http://localhost:5000/odata/testAnswers(2) +_Content-Type:_ application/json +_Body:_ +```json +[ + { + "TestQuestionVersionId": 1, + "Answer": "Ответ на первое задание", + "AnswerId": 1, + "IsRight": 1, + "StudentId": 2 + }, + { + "TestQuestionVersionId": 2, + "Answer": "Ответ на второе задание", + "AnswerId": 3, + "IsRight": 0, + "StudentId": 2 + } +] +``` +