Question Pool ve Question
This commit is contained in:
parent
f64f13557e
commit
7fdf4627d0
47 changed files with 2905 additions and 691 deletions
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Kurs.Platform.Questions;
|
||||
|
||||
public class QuestionDto : FullAuditedEntityDto<Guid>
|
||||
{
|
||||
public string QuestionType { get; set; }
|
||||
public int Points { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string MediaUrl { get; set; }
|
||||
public string MediaType { get; set; }
|
||||
public string CorrectAnswer { get; set; }
|
||||
public string Difficulty { get; set; }
|
||||
public int TimeLimit { get; set; }
|
||||
public string Explanation { get; set; }
|
||||
|
||||
public Guid QuestionPoolId { get; set; }
|
||||
public List<QuestionOptionDto> Options { get; set; } = new();
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Kurs.Platform.Questions;
|
||||
|
||||
public class QuestionOptionDto : FullAuditedEntityDto<Guid>
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public bool IsCorrect { get; set; }
|
||||
|
||||
public Guid QuestionId { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
|
||||
namespace Kurs.Platform.Questions;
|
||||
|
||||
public class QuestionPoolDto : FullAuditedEntityDto<Guid>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Tags { get; set; }
|
||||
|
||||
public List<QuestionDto> Questions { get; set; } = new();
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using Kurs.Platform.Entities;
|
||||
using Kurs.Platform.Questions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using static Kurs.Platform.Data.Seeds.SeedConsts;
|
||||
|
||||
namespace Kurs.Platform.DataSources;
|
||||
|
||||
public class QuestionAppService : CrudAppService<
|
||||
Question,
|
||||
QuestionDto,
|
||||
Guid,
|
||||
PagedAndSortedResultRequestDto>
|
||||
{
|
||||
public QuestionAppService(IRepository<Question, Guid> repo) : base(repo)
|
||||
{
|
||||
GetPolicyName = AppCodes.Definitions.Question;
|
||||
GetListPolicyName = AppCodes.Definitions.Question;
|
||||
CreatePolicyName = AppCodes.Definitions.Question + ".Create";
|
||||
UpdatePolicyName = AppCodes.Definitions.Question + ".Update";
|
||||
DeletePolicyName = AppCodes.Definitions.Question + ".Delete";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using AutoMapper;
|
||||
using Kurs.Platform.Entities;
|
||||
using Kurs.Platform.Questions;
|
||||
|
||||
namespace Kurs.Platform.DataSources;
|
||||
|
||||
public class QuestionAutoMapperProfile : Profile
|
||||
{
|
||||
public QuestionAutoMapperProfile()
|
||||
{
|
||||
CreateMap<Question, QuestionDto>().ReverseMap();
|
||||
}
|
||||
}
|
||||
|
|
@ -7881,10 +7881,22 @@
|
|||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom.Tag",
|
||||
"key": "App.Definitions.Tag",
|
||||
"tr": "Etiketler",
|
||||
"en": "Tags"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Definitions.QuestionPool",
|
||||
"tr": "Soru Havuzu",
|
||||
"en": "Question Pools"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Definitions.Question",
|
||||
"tr": "Sorular",
|
||||
"en": "Questions"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Definitions.RegistrationType",
|
||||
|
|
@ -11985,31 +11997,31 @@
|
|||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom",
|
||||
"key": "App.Coordinator.Classroom",
|
||||
"tr": "Sınıf",
|
||||
"en": "Classroom"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom.Dashboard",
|
||||
"key": "App.Coordinator.Classroom.Dashboard",
|
||||
"tr": "Gösterge Paneli",
|
||||
"en": "Dashboard"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom.List",
|
||||
"key": "App.Coordinator.Classroom.List",
|
||||
"tr": "Sınıflar",
|
||||
"en": "Classes"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom.RoomDetail",
|
||||
"key": "App.Coordinator.Classroom.RoomDetail",
|
||||
"tr": "Sanal Sınıf",
|
||||
"en": "Virtul Classroom"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Classroom.Planning",
|
||||
"key": "App.Coordinator.Classroom.Planning",
|
||||
"tr": "Sınıf Planlama",
|
||||
"en": "Classroom Planning"
|
||||
},
|
||||
|
|
@ -12797,41 +12809,42 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"key": "admin.classroom.dashboard",
|
||||
"path": "/admin/classroom/dashboard",
|
||||
"componentPath": "@/views/classroom/Dashboard",
|
||||
"key": "admin.coordinator.classroom.dashboard",
|
||||
"path": "/admin/coordinator/classroom/dashboard",
|
||||
"componentPath": "@/views/coordinator/Classroom/Dashboard",
|
||||
"routeType": "protected",
|
||||
"authority": [
|
||||
"App.Classroom.Dashboard"
|
||||
"App.Coordinator.Classroom.Dashboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "admin.classroom.classes",
|
||||
"path": "/admin/classroom/classes",
|
||||
"componentPath": "@/views/classroom/ClassList",
|
||||
"key": "admin.coordinator.classroom.classes",
|
||||
"path": "/admin/coordinator/classroom/classes",
|
||||
"componentPath": "@/views/coordinator/Classroom/ClassList",
|
||||
"routeType": "protected",
|
||||
"authority": [
|
||||
"App.Classroom.List"
|
||||
"App.Coordinator.Classroom.List"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "admin.classroom.classroom",
|
||||
"path": "/admin/classroom/room/:id",
|
||||
"componentPath": "@/views/classroom/RoomDetail",
|
||||
"key": "admin.coordinator.classroom.classroom",
|
||||
"path": "/admin/coordinator/classroom/room/:id",
|
||||
"componentPath": "@/views/coordinator/Classroom/RoomDetail",
|
||||
"routeType": "protected",
|
||||
"authority": [
|
||||
"App.Classroom.RoomDetail"
|
||||
"App.Coordinator.Classroom.RoomDetail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "admin.classroom.planning",
|
||||
"path": "/admin/classroom/planning/:id",
|
||||
"componentPath": "@/views/classroom/PlanningPage",
|
||||
"key": "admin.coordinator.classroom.planning",
|
||||
"path": "/admin/coordinator/classroom/planning/:id",
|
||||
"componentPath": "@/views/coordinator/Classroom/PlanningPage",
|
||||
"routeType": "protected",
|
||||
"authority": [
|
||||
"App.Classroom.Planning"
|
||||
"App.Coordinator.Classroom.Planning"
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"key": "admin.supplychain.materialTypes",
|
||||
"path": "/admin/supplychain/materials/types",
|
||||
|
|
@ -14599,22 +14612,32 @@
|
|||
},
|
||||
{
|
||||
"ParentCode": "App.Coordinator.Definitions",
|
||||
"Code": "App.Classroom.Tag",
|
||||
"DisplayName": "App.Classroom.Tag",
|
||||
"Code": "App.Definitions.Tag",
|
||||
"DisplayName": "App.Definitions.Tag",
|
||||
"Order": 10,
|
||||
"Url": "/admin/list/list-tag",
|
||||
"Icon": "FcTags",
|
||||
"RequiredPermissionName": "App.Classroom.Tag",
|
||||
"RequiredPermissionName": "App.Definitions.Tag",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Coordinator.Definitions",
|
||||
"Code": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "App.Definitions.QuestionPool",
|
||||
"Order": 11,
|
||||
"Url": "/admin/list/list-questionpool",
|
||||
"Icon": "FcQuestions",
|
||||
"RequiredPermissionName": "App.Definitions.QuestionPool",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
"ParentCode": "App.Coordinator",
|
||||
"Code": "App.Classroom",
|
||||
"DisplayName": "App.Classroom",
|
||||
"Code": "App.Coordinator.Classroom",
|
||||
"DisplayName": "App.Coordinator.Classroom",
|
||||
"Order": 2,
|
||||
"Url": "/admin/classroom/dashboard",
|
||||
"Url": "/admin/coordinator/classroom/dashboard",
|
||||
"Icon": "FcNeutralDecision",
|
||||
"RequiredPermissionName": "App.Classroom.Dashboard",
|
||||
"RequiredPermissionName": "App.Coordinator.Classroom.Dashboard",
|
||||
"IsDisabled": false
|
||||
},
|
||||
{
|
||||
|
|
@ -21895,62 +21918,17 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom",
|
||||
"Name": "App.Definitions.Tag",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Classroom",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Dashboard",
|
||||
"ParentName": "App.Classroom",
|
||||
"DisplayName": "App.Classroom.Dashboard",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.List",
|
||||
"ParentName": "App.Classroom",
|
||||
"DisplayName": "App.Classroom.List",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.RoomDetail",
|
||||
"ParentName": "App.Classroom",
|
||||
"DisplayName": "App.Classroom.RoomDetail",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Planning",
|
||||
"ParentName": "App.Classroom",
|
||||
"DisplayName": "App.Classroom.Planning",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Classroom.Tag",
|
||||
"DisplayName": "App.Definitions.Tag",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Create",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Create",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
|
|
@ -21958,8 +21936,8 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Update",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Update",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
|
|
@ -21967,8 +21945,8 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Delete",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Delete",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
|
|
@ -21976,8 +21954,8 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Export",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Export",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
|
|
@ -21985,8 +21963,8 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Import",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Import",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
|
|
@ -21994,13 +21972,185 @@
|
|||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Classroom.Tag.Activity",
|
||||
"ParentName": "App.Classroom.Tag",
|
||||
"Name": "App.Definitions.Tag.Activity",
|
||||
"ParentName": "App.Definitions.Tag",
|
||||
"DisplayName": "Activity",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Definitions.QuestionPool",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Create",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Update",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Delete",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Export",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Import",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.QuestionPool.Activity",
|
||||
"ParentName": "App.Definitions.QuestionPool",
|
||||
"DisplayName": "Activity",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Definitions.Question",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Create",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Update",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Delete",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Export",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Import",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Definitions.Question.Activity",
|
||||
"ParentName": "App.Definitions.Question",
|
||||
"DisplayName": "Activity",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Coordinator.Classroom",
|
||||
"ParentName": null,
|
||||
"DisplayName": "App.Coordinator.Classroom",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Coordinator.Classroom.Dashboard",
|
||||
"ParentName": "App.Coordinator.Classroom",
|
||||
"DisplayName": "App.Coordinator.Classroom.Dashboard",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Coordinator.Classroom.List",
|
||||
"ParentName": "App.Coordinator.Classroom",
|
||||
"DisplayName": "App.Coordinator.Classroom.List",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Coordinator.Classroom.RoomDetail",
|
||||
"ParentName": "App.Coordinator.Classroom",
|
||||
"DisplayName": "App.Coordinator.Classroom.RoomDetail",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Coordinator",
|
||||
"Name": "App.Coordinator.Classroom.Planning",
|
||||
"ParentName": "App.Coordinator.Classroom",
|
||||
"DisplayName": "App.Coordinator.Classroom.Planning",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 2,
|
||||
"MenuGroup": "Kurs"
|
||||
},
|
||||
|
||||
{
|
||||
"GroupName": "App.SupplyChain",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -149,6 +149,22 @@ public static class PlatformConsts
|
|||
$"\"{SelectCommandByTableName("InstallmentOption", Prefix.DbTableWeb)}\".\"Name\" AS \"Name\" " +
|
||||
$"FROM \"{SelectCommandByTableName("InstallmentOption", Prefix.DbTableWeb)}\" " +
|
||||
$"ORDER BY \"{SelectCommandByTableName("InstallmentOption", Prefix.DbTableWeb)}\".\"Installment\";";
|
||||
|
||||
public static string QuestionPoolValues =
|
||||
$"SELECT " +
|
||||
$"\"Id\" AS \"Key\", " +
|
||||
$"\"Name\" AS \"Name\" " +
|
||||
$"FROM \"{SelectCommandByTableName("QuestionPool", Prefix.DbTableCoordinator)}\" " +
|
||||
$"WHERE " +
|
||||
$"\"IsDeleted\" = 'false' ";
|
||||
|
||||
public static string QuestionTagValues =
|
||||
$"SELECT " +
|
||||
$"\"Id\" AS \"Key\", " +
|
||||
$"\"Name\" AS \"Name\" " +
|
||||
$"FROM \"{SelectCommandByTableName("Tag", Prefix.DbTableCoordinator)}\" " +
|
||||
$"WHERE " +
|
||||
$"\"IsDeleted\" = 'false' ";
|
||||
}
|
||||
|
||||
public static class Prefix
|
||||
|
|
@ -508,10 +524,11 @@ public static class PlatformConsts
|
|||
{
|
||||
public static class Forms
|
||||
{
|
||||
public const string FormTenant = "form-tenant";
|
||||
public const string FormLanguage = "form-language";
|
||||
public const string FormUomCategory = "form-uomcategory";
|
||||
public const string FormSkillType = "form-skilltype";
|
||||
public const string FormTenant = "form-tenant";
|
||||
public const string FormQuestionPool = "form-questionpool";
|
||||
public const string FormBank = "form-bank";
|
||||
}
|
||||
|
||||
|
|
@ -596,6 +613,8 @@ public static class PlatformConsts
|
|||
public const string Class = "list-class";
|
||||
public const string Level = "list-level";
|
||||
public const string Tag = "list-tag";
|
||||
public const string QuestionPool = "list-questionpool";
|
||||
public const string Question = "list-question";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -438,12 +438,14 @@ public static class SeedConsts
|
|||
public const string ClassType = Default + ".ClassType";
|
||||
public const string Class = Default + ".Class";
|
||||
public const string Level = Default + ".Level";
|
||||
public const string Tag = Default + ".Tag";
|
||||
public const string QuestionPool = Default + ".QuestionPool";
|
||||
public const string Question = Default + ".Question";
|
||||
}
|
||||
|
||||
public static class Classroom
|
||||
public static class Coordinator
|
||||
{
|
||||
public const string Default = Prefix.App + ".Classroom";
|
||||
public const string Tag = Default + ".Tag";
|
||||
}
|
||||
|
||||
public static class Accounting
|
||||
|
|
|
|||
32
api/src/Kurs.Platform.Domain/Entities/Tenant/Question.cs
Normal file
32
api/src/Kurs.Platform.Domain/Entities/Tenant/Question.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Kurs.Platform.Entities;
|
||||
|
||||
public class Question : FullAuditedEntity<Guid>, IMultiTenant
|
||||
{
|
||||
public Guid? TenantId;
|
||||
|
||||
public string QuestionType { get; set; } // "multiple-choice", "fill-blank" vb.
|
||||
public int Points { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string MediaUrl { get; set; }
|
||||
public string MediaType { get; set; }
|
||||
public string CorrectAnswer { get; set; }
|
||||
public string Difficulty { get; set; } // "easy", "medium", "hard"
|
||||
public int TimeLimit { get; set; }
|
||||
public string Explanation { get; set; }
|
||||
|
||||
public ICollection<QuestionOption> Options { get; set; } = [];
|
||||
|
||||
// Foreign key
|
||||
public Guid QuestionPoolId { get; set; }
|
||||
public QuestionPool QuestionPool { get; set; }
|
||||
|
||||
|
||||
Guid? IMultiTenant.TenantId => TenantId;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Kurs.Platform.Entities;
|
||||
|
||||
public class QuestionOption : FullAuditedEntity<Guid>, IMultiTenant
|
||||
{
|
||||
public Guid? TenantId;
|
||||
|
||||
public string Text { get; set; }
|
||||
public bool IsCorrect { get; set; }
|
||||
|
||||
// Foreign key
|
||||
public Guid QuestionId { get; set; }
|
||||
public Question Question { get; set; }
|
||||
|
||||
Guid? IMultiTenant.TenantId => TenantId;
|
||||
}
|
||||
19
api/src/Kurs.Platform.Domain/Entities/Tenant/QuestionPool.cs
Normal file
19
api/src/Kurs.Platform.Domain/Entities/Tenant/QuestionPool.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Kurs.Platform.Entities;
|
||||
|
||||
public class QuestionPool : FullAuditedEntity<Guid>, IMultiTenant
|
||||
{
|
||||
public Guid? TenantId;
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Tags { get; set; } // İstersen JSON veya ayrı tablo da olabilir
|
||||
|
||||
public ICollection<Question> Questions { get; set; } = new List<Question>();
|
||||
|
||||
Guid? IMultiTenant.TenantId => TenantId;
|
||||
}
|
||||
|
|
@ -141,6 +141,9 @@ public class PlatformDbContext :
|
|||
public DbSet<ClassroomChat> ChatMessages { get; set; }
|
||||
|
||||
public DbSet<Tag> Tags { get; set; }
|
||||
public DbSet<QuestionPool> QuestionPools { get; set; }
|
||||
public DbSet<Question> Questions { get; set; }
|
||||
public DbSet<QuestionOption> QuestionOptions { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -488,6 +491,16 @@ public class PlatformDbContext :
|
|||
b.Property(x => x.ErrorsJson).HasColumnType("text");
|
||||
});
|
||||
|
||||
builder.Entity<Activity>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(Activity), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Type).IsRequired();
|
||||
b.Property(x => x.Subject).IsRequired().HasMaxLength(256);
|
||||
b.Property(x => x.Content).IsRequired().HasMaxLength(2000);
|
||||
});
|
||||
|
||||
builder.Entity<BackgroundWorker>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(BackgroundWorker), Prefix.DbSchema);
|
||||
|
|
@ -1487,7 +1500,7 @@ public class PlatformDbContext :
|
|||
//Coordinator
|
||||
builder.Entity<Classroom>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(Classroom), Prefix.DbSchema);
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(Classroom), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(200);
|
||||
|
|
@ -1516,7 +1529,7 @@ public class PlatformDbContext :
|
|||
|
||||
builder.Entity<ClassroomParticipant>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(ClassroomParticipant), Prefix.DbSchema);
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(ClassroomParticipant), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.UserName).IsRequired().HasMaxLength(100);
|
||||
|
|
@ -1531,7 +1544,7 @@ public class PlatformDbContext :
|
|||
|
||||
builder.Entity<ClassroomAttandance>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(ClassroomAttandance), Prefix.DbSchema);
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(ClassroomAttandance), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.StudentName).IsRequired().HasMaxLength(100);
|
||||
|
|
@ -1543,7 +1556,7 @@ public class PlatformDbContext :
|
|||
|
||||
builder.Entity<ClassroomChat>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(ClassroomChat), Prefix.DbSchema);
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(ClassroomChat), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.SenderName).IsRequired().HasMaxLength(100);
|
||||
|
|
@ -1554,18 +1567,6 @@ public class PlatformDbContext :
|
|||
b.HasIndex(x => x.Timestamp);
|
||||
});
|
||||
|
||||
// Form Activity Entities
|
||||
builder.Entity<Activity>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableDefault + nameof(Activity), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Type).IsRequired();
|
||||
b.Property(x => x.Subject).IsRequired().HasMaxLength(256);
|
||||
b.Property(x => x.Content).IsRequired().HasMaxLength(2000);
|
||||
});
|
||||
|
||||
// Classroom
|
||||
builder.Entity<Tag>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(Tag), Prefix.DbSchema);
|
||||
|
|
@ -1576,5 +1577,41 @@ public class PlatformDbContext :
|
|||
b.Property(x => x.Color).HasMaxLength(7);
|
||||
b.Property(x => x.UsageCount).HasDefaultValue(0);
|
||||
});
|
||||
|
||||
builder.Entity<QuestionPool>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(QuestionPool), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Name).IsRequired().HasMaxLength(100);
|
||||
b.Property(x => x.Description).HasMaxLength(500);
|
||||
b.Property(x => x.Tags).HasMaxLength(500);
|
||||
});
|
||||
|
||||
builder.Entity<Question>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(Question), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.QuestionType).IsRequired().HasMaxLength(100);
|
||||
b.Property(x => x.Points).HasDefaultValue(0);
|
||||
b.Property(x => x.Title).IsRequired().HasMaxLength(500);
|
||||
b.Property(x => x.Content).HasMaxLength(500);
|
||||
b.Property(x => x.MediaUrl).HasMaxLength(500);
|
||||
b.Property(x => x.MediaType).HasMaxLength(500);
|
||||
b.Property(x => x.CorrectAnswer).HasMaxLength(50);
|
||||
b.Property(x => x.Difficulty).HasMaxLength(10);
|
||||
b.Property(x => x.TimeLimit).HasDefaultValue(0);
|
||||
b.Property(x => x.Explanation).HasMaxLength(500);
|
||||
});
|
||||
|
||||
builder.Entity<QuestionOption>(b =>
|
||||
{
|
||||
b.ToTable(Prefix.DbTableCoordinator + nameof(QuestionOption), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.Property(x => x.Text).HasMaxLength(100);
|
||||
b.Property(x => x.IsCorrect).HasDefaultValue(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
|||
namespace Kurs.Platform.Migrations
|
||||
{
|
||||
[DbContext(typeof(PlatformDbContext))]
|
||||
[Migration("20251015192202_Initial")]
|
||||
[Migration("20251016120353_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -1780,7 +1780,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("TeacherId");
|
||||
|
||||
b.ToTable("PClassroom", (string)null);
|
||||
b.ToTable("CClassroom", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomAttandance", b =>
|
||||
|
|
@ -1853,7 +1853,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("StudentId");
|
||||
|
||||
b.ToTable("PClassroomAttandance", (string)null);
|
||||
b.ToTable("CClassroomAttandance", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomChat", b =>
|
||||
|
|
@ -1937,7 +1937,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("Timestamp");
|
||||
|
||||
b.ToTable("PClassroomChat", (string)null);
|
||||
b.ToTable("CClassroomChat", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomParticipant", b =>
|
||||
|
|
@ -2032,7 +2032,7 @@ namespace Kurs.Platform.Migrations
|
|||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("PClassroomParticipant", (string)null);
|
||||
b.ToTable("CClassroomParticipant", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Contact", b =>
|
||||
|
|
@ -5103,6 +5103,214 @@ namespace Kurs.Platform.Migrations
|
|||
b.ToTable("DPsychologist", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("CorrectAnswer")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<string>("Difficulty")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Explanation")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<string>("MediaType")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("MediaUrl")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Points")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<Guid>("QuestionPoolId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("QuestionType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<int>("TimeLimit")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("QuestionPoolId");
|
||||
|
||||
b.ToTable("CQuestion", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionOption", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<bool>("IsCorrect")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false);
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<Guid>("QuestionId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("QuestionId");
|
||||
|
||||
b.ToTable("CQuestionOption", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionPool", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Tags")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CQuestionPool", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationMethod", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -6115,7 +6323,6 @@ namespace Kurs.Platform.Migrations
|
|||
modelBuilder.Entity("Kurs.Platform.Entities.Tag", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Color")
|
||||
|
|
@ -8969,6 +9176,28 @@ namespace Kurs.Platform.Migrations
|
|||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.QuestionPool", "QuestionPool")
|
||||
.WithMany("Questions")
|
||||
.HasForeignKey("QuestionPoolId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("QuestionPool");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionOption", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.Question", "Question")
|
||||
.WithMany("Options")
|
||||
.HasForeignKey("QuestionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Question");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationMethod", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.RegistrationType", "RegistrationType")
|
||||
|
|
@ -9298,6 +9527,16 @@ namespace Kurs.Platform.Migrations
|
|||
b.Navigation("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.Navigation("Options");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionPool", b =>
|
||||
{
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationType", b =>
|
||||
{
|
||||
b.Navigation("ClassTypes");
|
||||
|
|
@ -434,6 +434,61 @@ namespace Kurs.Platform.Migrations
|
|||
table.PrimaryKey("PK_AbpUsers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CClassroom",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||
Subject = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
TeacherId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
TeacherName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
ScheduledStartTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ScheduledEndTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Duration = table.Column<int>(type: "int", nullable: false),
|
||||
ActualStartTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ActualEndTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
MaxParticipants = table.Column<int>(type: "int", nullable: false),
|
||||
ParticipantCount = table.Column<int>(type: "int", nullable: false),
|
||||
SettingsJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CClassroom", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CQuestionPool",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
Tags = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CQuestionPool", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CTag",
|
||||
columns: table => new
|
||||
|
|
@ -1370,39 +1425,6 @@ namespace Kurs.Platform.Migrations
|
|||
table.PrimaryKey("PK_PBranchUsers", x => new { x.UserId, x.BranchId });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PClassroom",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
|
||||
Subject = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
TeacherId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
TeacherName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
ScheduledStartTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ScheduledEndTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Duration = table.Column<int>(type: "int", nullable: false),
|
||||
ActualStartTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ActualEndTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
MaxParticipants = table.Column<int>(type: "int", nullable: false),
|
||||
ParticipantCount = table.Column<int>(type: "int", nullable: false),
|
||||
SettingsJson = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PClassroom", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PCustomComponent",
|
||||
columns: table => new
|
||||
|
|
@ -2325,6 +2347,146 @@ namespace Kurs.Platform.Migrations
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CClassroomAttandance",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
StudentId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
StudentName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
JoinTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LeaveTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
TotalDurationMinutes = table.Column<int>(type: "int", nullable: false),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CClassroomAttandance", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CClassroomAttandance_CClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "CClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CClassroomChat",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
SenderId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SenderName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Message = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
|
||||
Timestamp = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RecipientId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
RecipientName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
IsTeacher = table.Column<bool>(type: "bit", nullable: false),
|
||||
MessageType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CClassroomChat", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CClassroomChat_CClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "CClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CClassroomParticipant",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UserName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
IsTeacher = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsAudioMuted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsVideoMuted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsHandRaised = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsKicked = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
JoinTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ConnectionId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CClassroomParticipant", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CClassroomParticipant_CClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "CClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CQuestion",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
QuestionType = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Points = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||
Title = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
Content = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
MediaUrl = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
MediaType = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
CorrectAnswer = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
Difficulty = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: true),
|
||||
TimeLimit = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||
Explanation = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
QuestionPoolId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CQuestion", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CQuestion_CQuestionPool_QuestionPoolId",
|
||||
column: x => x.QuestionPoolId,
|
||||
principalTable: "CQuestionPool",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DCountry",
|
||||
columns: table => new
|
||||
|
|
@ -2674,110 +2836,6 @@ namespace Kurs.Platform.Migrations
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PClassroomAttandance",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
StudentId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
StudentName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
JoinTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LeaveTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
TotalDurationMinutes = table.Column<int>(type: "int", nullable: false),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PClassroomAttandance", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PClassroomAttandance_PClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "PClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PClassroomChat",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
SenderId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SenderName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Message = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: false),
|
||||
Timestamp = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RecipientId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
RecipientName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
IsTeacher = table.Column<bool>(type: "bit", nullable: false),
|
||||
MessageType = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PClassroomChat", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PClassroomChat_PClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "PClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PClassroomParticipant",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
BranchId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
SessionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
UserName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
IsTeacher = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsAudioMuted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsVideoMuted = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsHandRaised = table.Column<bool>(type: "bit", nullable: false),
|
||||
IsKicked = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||
JoinTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ConnectionId = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PClassroomParticipant", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PClassroomParticipant_PClassroom_SessionId",
|
||||
column: x => x.SessionId,
|
||||
principalTable: "PClassroom",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PApiEndpoint",
|
||||
columns: table => new
|
||||
|
|
@ -3215,6 +3273,34 @@ namespace Kurs.Platform.Migrations
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CQuestionOption",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Text = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
IsCorrect = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
QuestionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CQuestionOption", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CQuestionOption_CQuestion_QuestionId",
|
||||
column: x => x.QuestionId,
|
||||
principalTable: "CQuestion",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DCity",
|
||||
columns: table => new
|
||||
|
|
@ -3748,6 +3834,73 @@ namespace Kurs.Platform.Migrations
|
|||
table: "AbpUsers",
|
||||
column: "UserName");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroom_ScheduledStartTime",
|
||||
table: "CClassroom",
|
||||
column: "ScheduledStartTime");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroom_TeacherId",
|
||||
table: "CClassroom",
|
||||
column: "TeacherId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomAttandance_JoinTime",
|
||||
table: "CClassroomAttandance",
|
||||
column: "JoinTime");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomAttandance_SessionId",
|
||||
table: "CClassroomAttandance",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomAttandance_StudentId",
|
||||
table: "CClassroomAttandance",
|
||||
column: "StudentId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomChat_SenderId",
|
||||
table: "CClassroomChat",
|
||||
column: "SenderId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomChat_SessionId",
|
||||
table: "CClassroomChat",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomChat_Timestamp",
|
||||
table: "CClassroomChat",
|
||||
column: "Timestamp");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomParticipant_SessionId",
|
||||
table: "CClassroomParticipant",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomParticipant_SessionId_UserId",
|
||||
table: "CClassroomParticipant",
|
||||
columns: new[] { "SessionId", "UserId" },
|
||||
unique: true,
|
||||
filter: "[UserId] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CClassroomParticipant_UserId",
|
||||
table: "CClassroomParticipant",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CQuestion_QuestionPoolId",
|
||||
table: "CQuestion",
|
||||
column: "QuestionPoolId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CQuestionOption_QuestionId",
|
||||
table: "CQuestionOption",
|
||||
column: "QuestionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_DBankAccount_BankId",
|
||||
table: "DBankAccount",
|
||||
|
|
@ -3905,63 +4058,6 @@ namespace Kurs.Platform.Migrations
|
|||
columns: new[] { "TableName", "Order" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroom_ScheduledStartTime",
|
||||
table: "PClassroom",
|
||||
column: "ScheduledStartTime");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroom_TeacherId",
|
||||
table: "PClassroom",
|
||||
column: "TeacherId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomAttandance_JoinTime",
|
||||
table: "PClassroomAttandance",
|
||||
column: "JoinTime");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomAttandance_SessionId",
|
||||
table: "PClassroomAttandance",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomAttandance_StudentId",
|
||||
table: "PClassroomAttandance",
|
||||
column: "StudentId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomChat_SenderId",
|
||||
table: "PClassroomChat",
|
||||
column: "SenderId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomChat_SessionId",
|
||||
table: "PClassroomChat",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomChat_Timestamp",
|
||||
table: "PClassroomChat",
|
||||
column: "Timestamp");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomParticipant_SessionId",
|
||||
table: "PClassroomParticipant",
|
||||
column: "SessionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomParticipant_SessionId_UserId",
|
||||
table: "PClassroomParticipant",
|
||||
columns: new[] { "SessionId", "UserId" },
|
||||
unique: true,
|
||||
filter: "[UserId] IS NOT NULL");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PClassroomParticipant_UserId",
|
||||
table: "PClassroomParticipant",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PCustomEntityField_EntityId",
|
||||
table: "PCustomEntityField",
|
||||
|
|
@ -4165,6 +4261,18 @@ namespace Kurs.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "AbpUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CClassroomAttandance");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CClassroomChat");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CClassroomParticipant");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CQuestionOption");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CTag");
|
||||
|
||||
|
|
@ -4294,15 +4402,6 @@ namespace Kurs.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "PBranchUsers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PClassroomAttandance");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PClassroomChat");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PClassroomParticipant");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PCustomComponent");
|
||||
|
||||
|
|
@ -4396,6 +4495,12 @@ namespace Kurs.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "AbpUsers");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CClassroom");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CQuestion");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "DBank");
|
||||
|
||||
|
|
@ -4429,9 +4534,6 @@ namespace Kurs.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "PBackgroundWorker_MailQueue");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PClassroom");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PCustomEntity");
|
||||
|
||||
|
|
@ -4462,6 +4564,9 @@ namespace Kurs.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "AbpAuditLogs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "CQuestionPool");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "DCountry");
|
||||
|
||||
|
|
@ -1777,7 +1777,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("TeacherId");
|
||||
|
||||
b.ToTable("PClassroom", (string)null);
|
||||
b.ToTable("CClassroom", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomAttandance", b =>
|
||||
|
|
@ -1850,7 +1850,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("StudentId");
|
||||
|
||||
b.ToTable("PClassroomAttandance", (string)null);
|
||||
b.ToTable("CClassroomAttandance", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomChat", b =>
|
||||
|
|
@ -1934,7 +1934,7 @@ namespace Kurs.Platform.Migrations
|
|||
|
||||
b.HasIndex("Timestamp");
|
||||
|
||||
b.ToTable("PClassroomChat", (string)null);
|
||||
b.ToTable("CClassroomChat", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.ClassroomParticipant", b =>
|
||||
|
|
@ -2029,7 +2029,7 @@ namespace Kurs.Platform.Migrations
|
|||
.IsUnique()
|
||||
.HasFilter("[UserId] IS NOT NULL");
|
||||
|
||||
b.ToTable("PClassroomParticipant", (string)null);
|
||||
b.ToTable("CClassroomParticipant", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Contact", b =>
|
||||
|
|
@ -5100,6 +5100,214 @@ namespace Kurs.Platform.Migrations
|
|||
b.ToTable("DPsychologist", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("CorrectAnswer")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<string>("Difficulty")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<string>("Explanation")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<string>("MediaType")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("MediaUrl")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("Points")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<Guid>("QuestionPoolId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("QuestionType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<int>("TimeLimit")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasDefaultValue(0);
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("QuestionPoolId");
|
||||
|
||||
b.ToTable("CQuestion", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionOption", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<bool>("IsCorrect")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false);
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<Guid>("QuestionId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("QuestionId");
|
||||
|
||||
b.ToTable("CQuestionOption", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionPool", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Tags")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CQuestionPool", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationMethod", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -6112,7 +6320,6 @@ namespace Kurs.Platform.Migrations
|
|||
modelBuilder.Entity("Kurs.Platform.Entities.Tag", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Color")
|
||||
|
|
@ -8966,6 +9173,28 @@ namespace Kurs.Platform.Migrations
|
|||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.QuestionPool", "QuestionPool")
|
||||
.WithMany("Questions")
|
||||
.HasForeignKey("QuestionPoolId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("QuestionPool");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionOption", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.Question", "Question")
|
||||
.WithMany("Options")
|
||||
.HasForeignKey("QuestionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Question");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationMethod", b =>
|
||||
{
|
||||
b.HasOne("Kurs.Platform.Entities.RegistrationType", "RegistrationType")
|
||||
|
|
@ -9295,6 +9524,16 @@ namespace Kurs.Platform.Migrations
|
|||
b.Navigation("Items");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.Question", b =>
|
||||
{
|
||||
b.Navigation("Options");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.QuestionPool", b =>
|
||||
{
|
||||
b.Navigation("Questions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kurs.Platform.Entities.RegistrationType", b =>
|
||||
{
|
||||
b.Navigation("ClassTypes");
|
||||
|
|
|
|||
|
|
@ -1827,6 +1827,61 @@
|
|||
"Name": "Writing",
|
||||
"Description": "Writing skills development",
|
||||
"Color": "#EF4444"
|
||||
},
|
||||
{
|
||||
"Name": "Verbs",
|
||||
"Description": "Verbs and their usage",
|
||||
"Color": "#EA580C"
|
||||
}
|
||||
],
|
||||
"QuestionPools": [
|
||||
{
|
||||
"Name": "Grammar Fundamentals",
|
||||
"Description": "Essential grammar concepts and structures",
|
||||
"Tags": "Grammar|Verbs"
|
||||
},
|
||||
{
|
||||
"Name": "Vocabulary Expansion",
|
||||
"Description": "Exercises to enhance vocabulary",
|
||||
"Tags": "Vocabulary|Reading"
|
||||
},
|
||||
{
|
||||
"Name": "Reading Comprehension",
|
||||
"Description": "Passages and questions to improve reading skills",
|
||||
"Tags": "Reading|Verbs"
|
||||
},
|
||||
{
|
||||
"Name": "Writing Practice",
|
||||
"Description": "Prompts and exercises for writing improvement",
|
||||
"Tags": "Writing"
|
||||
}
|
||||
],
|
||||
"Questions": [
|
||||
{
|
||||
"QuestionPoolName": "Grammar Fundamentals",
|
||||
"QuestionType": "multiple-choice",
|
||||
"Points": 10,
|
||||
"Title": "Verb Tenses",
|
||||
"Content": "Select the appropriate tense form for the given context.",
|
||||
"MediaType": "image",
|
||||
"MediaUrl": "",
|
||||
"CorrectAnswer": "opt2",
|
||||
"Difficulty": "easy",
|
||||
"TimeLimit": 0,
|
||||
"Explanation": ""
|
||||
},
|
||||
{
|
||||
"QuestionPoolName": "Grammar Fundamentals",
|
||||
"QuestionType": "fill-blank",
|
||||
"Points": 15,
|
||||
"Title": "Articles",
|
||||
"Content": "Fill in the blank: \"I saw _____ elephant at the zoo yesterday.\"",
|
||||
"MediaType": "image",
|
||||
"MediaUrl": "",
|
||||
"CorrectAnswer": "an",
|
||||
"Difficulty": "medium",
|
||||
"TimeLimit": 0,
|
||||
"Explanation": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ using Volo.Abp.Data;
|
|||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kurs.Platform.Data.Seeds;
|
||||
|
||||
|
|
@ -53,6 +55,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
private readonly IRepository<WorkHour, Guid> _workHourRepository;
|
||||
private readonly IRepository<Classroom, Guid> _classroomRepository;
|
||||
private readonly IRepository<Tag, Guid> _tagRepository;
|
||||
private readonly IRepository<QuestionPool, Guid> _questionPoolRepository;
|
||||
private readonly IRepository<Question, Guid> _questionRepository;
|
||||
|
||||
public TenantDataSeeder(
|
||||
IRepository<GlobalSearch, int> globalSearch,
|
||||
|
|
@ -92,7 +96,9 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
IRepository<Interesting, Guid> interestingRepository,
|
||||
IRepository<Program, Guid> programRepository,
|
||||
IRepository<ForumCategory, Guid> forumCategoryRepository,
|
||||
IRepository<Tag, Guid> tagRepository
|
||||
IRepository<Tag, Guid> tagRepository,
|
||||
IRepository<QuestionPool, Guid> questionPoolRepository,
|
||||
IRepository<Question, Guid> questionRepository
|
||||
)
|
||||
{
|
||||
_globalSearch = globalSearch;
|
||||
|
|
@ -133,6 +139,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
_programRepository = programRepository;
|
||||
_forumCategoryRepository = forumCategoryRepository;
|
||||
_tagRepository = tagRepository;
|
||||
_questionPoolRepository = questionPoolRepository;
|
||||
_questionRepository = questionRepository;
|
||||
}
|
||||
|
||||
private static IConfigurationRoot BuildConfiguration()
|
||||
|
|
@ -743,5 +751,74 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in items.QuestionPools)
|
||||
{
|
||||
var exists = await _questionPoolRepository.AnyAsync(x => x.Name == item.Name);
|
||||
if (exists)
|
||||
continue;
|
||||
|
||||
var tagNames = item.Tags.Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim())
|
||||
.ToList();
|
||||
|
||||
var tagIds = new List<Guid>();
|
||||
foreach (var tagName in tagNames)
|
||||
{
|
||||
var tagEntity = items.Tags.FirstOrDefault(t =>
|
||||
string.Equals(t.Name, tagName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (tagEntity != null)
|
||||
{
|
||||
var existingTag = await _tagRepository.FirstOrDefaultAsync(x => x.Name == tagEntity.Name);
|
||||
if (existingTag == null)
|
||||
{
|
||||
existingTag = await _tagRepository.InsertAsync(new Tag
|
||||
{
|
||||
Name = tagEntity.Name,
|
||||
Description = tagEntity.Description,
|
||||
Color = tagEntity.Color
|
||||
});
|
||||
}
|
||||
|
||||
tagIds.Add(existingTag.Id);
|
||||
}
|
||||
}
|
||||
|
||||
var tagIdString = string.Join(PlatformConsts.MultiValueDelimiter, tagIds);
|
||||
await _questionPoolRepository.InsertAsync(new QuestionPool
|
||||
{
|
||||
Name = item.Name,
|
||||
Description = item.Description,
|
||||
Tags = tagIdString
|
||||
}, autoSave: true);
|
||||
}
|
||||
|
||||
foreach (var item in items.Questions)
|
||||
{
|
||||
var exists = await _questionRepository.AnyAsync(x => x.Title == item.Title);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
var questionPool = await _questionPoolRepository.FirstOrDefaultAsync(x => x.Name == item.QuestionPoolName);
|
||||
if (questionPool != null)
|
||||
{
|
||||
await _questionRepository.InsertAsync(new Question
|
||||
{
|
||||
QuestionPoolId = questionPool.Id,
|
||||
Title = item.Title,
|
||||
QuestionType = item.QuestionType,
|
||||
Points = item.Points,
|
||||
Content = item.Content,
|
||||
MediaUrl = item.MediaUrl,
|
||||
MediaType = item.MediaType,
|
||||
CorrectAnswer = item.CorrectAnswer,
|
||||
Difficulty = item.Difficulty,
|
||||
TimeLimit = item.TimeLimit,
|
||||
Explanation = item.Explanation
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ public class TenantSeederDto
|
|||
public List<ContactSeedDto> Contacts { get; set; }
|
||||
public List<ClassroomSeedDto> Classrooms { get; set; }
|
||||
public List<TagSeedDto> Tags { get; set; }
|
||||
public List<QuestionPoolSeedDto> QuestionPools { get; set; }
|
||||
public List<QuestionSeedDto> Questions { get; set; }
|
||||
|
||||
//Tanımlamalar
|
||||
public List<SectorSeedDto> Sectors { get; set; }
|
||||
|
|
@ -351,4 +353,26 @@ public class TagSeedDto
|
|||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Color { get; set; }
|
||||
}
|
||||
|
||||
public class QuestionPoolSeedDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Tags { get; set; }
|
||||
}
|
||||
|
||||
public class QuestionSeedDto
|
||||
{
|
||||
public string QuestionPoolName { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string QuestionType { get; set; }
|
||||
public int Points { get; set; }
|
||||
public string Content { get; set; }
|
||||
public string MediaUrl { get; set; }
|
||||
public string MediaType { get; set; }
|
||||
public string CorrectAnswer { get; set; }
|
||||
public string Difficulty { get; set; }
|
||||
public int TimeLimit { get; set; }
|
||||
public string Explanation { get; set; }
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { QuestionPool } from "@/types/coordinator";
|
||||
import { QuestionPoolDto } from "@/types/coordinator";
|
||||
|
||||
// Dynamic data - no hardcoded content
|
||||
export const generateMockPools = (): QuestionPool[] => [
|
||||
export const generateMockPools = (): QuestionPoolDto[] => [
|
||||
{
|
||||
id: "pool-1",
|
||||
name: "Grammar Fundamentals",
|
||||
|
|
|
|||
|
|
@ -73,13 +73,19 @@ export const ROUTES_ENUM = {
|
|||
formEdit: '/admin/form/:listFormCode/:id/edit',
|
||||
chart: '/admin/chart/:listFormCode',
|
||||
pivot: '/admin/pivot/:listFormCode',
|
||||
},
|
||||
|
||||
participant: {},
|
||||
|
||||
coordinator: {
|
||||
classroom: {
|
||||
dashboard: '/admin/classroom/dashboard',
|
||||
classes: '/admin/classroom/classes',
|
||||
roomDetail: '/admin/classroom/room/:id',
|
||||
planning: '/admin/classroom/planning/:id',
|
||||
dashboard: '/admin/coordinator/classroom/dashboard',
|
||||
classes: '/admin/coordinator/classroom/classes',
|
||||
roomDetail: '/admin/coordinator/classroom/room/:id',
|
||||
planning: '/admin/coordinator/classroom/planning/:id',
|
||||
},
|
||||
},
|
||||
|
||||
supplychain: {
|
||||
materialTypes: '/admin/supplychain/materials/types',
|
||||
materialGroups: '/admin/supplychain/materials/groups',
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ export class SignalRService {
|
|||
}
|
||||
|
||||
this.currentSessionId = undefined
|
||||
window.location.href = ROUTES_ENUM.protected.admin.classroom.classes
|
||||
window.location.href = ROUTES_ENUM.protected.coordinator.classroom.classes
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
48
ui/src/services/question.service.ts
Normal file
48
ui/src/services/question.service.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { PagedResultDto } from '@/proxy'
|
||||
import apiService from './api.service'
|
||||
import { QuestionDto } from '@/types/coordinator'
|
||||
|
||||
class QuestionService {
|
||||
async getQuestions(): Promise<PagedResultDto<QuestionDto>> {
|
||||
const response = await apiService.fetchData<PagedResultDto<QuestionDto>>({
|
||||
url: '/api/app/question',
|
||||
method: 'GET',
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
|
||||
async getQuestion(id: string): Promise<QuestionDto> {
|
||||
const response = await apiService.fetchData<QuestionDto>({
|
||||
url: `/api/app/question/${id}`,
|
||||
method: 'GET',
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
|
||||
async updateQuestion(id: string, input: QuestionDto) {
|
||||
const response = await apiService.fetchData<QuestionDto>({
|
||||
url: `/api/app/question/${id}`,
|
||||
method: 'PUT',
|
||||
data: input as any,
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
|
||||
async createQuestion(input: QuestionDto) {
|
||||
const response = await apiService.fetchData<QuestionDto>({
|
||||
method: 'POST',
|
||||
url: '/api/app/question',
|
||||
data: input as any,
|
||||
})
|
||||
return response.data
|
||||
}
|
||||
|
||||
async deleteQuestion(id: string) {
|
||||
await apiService.fetchData<void>({
|
||||
method: 'DELETE',
|
||||
url: `/api/app/question/${id}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const questionService = new QuestionService()
|
||||
|
|
@ -14,24 +14,24 @@ export type MediaType = 'image' | 'video';
|
|||
export type QuestionDifficulty = 'easy' | 'medium' | 'hard';
|
||||
export type ExamSessionStatus = 'in-progress' | 'completed' | 'submitted';
|
||||
|
||||
export interface QuestionPool {
|
||||
export interface QuestionPoolDto {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
questions: Question[];
|
||||
questions: QuestionDto[];
|
||||
tags: string[];
|
||||
createdBy: string;
|
||||
creationTime: Date;
|
||||
}
|
||||
|
||||
export interface Question {
|
||||
export interface QuestionDto {
|
||||
id: string;
|
||||
type: QuestionType;
|
||||
title: string;
|
||||
content: string;
|
||||
mediaUrl?: string;
|
||||
mediaType?: MediaType;
|
||||
options?: QuestionOption[];
|
||||
options?: QuestionOptionDto[];
|
||||
correctAnswer?: string | string[];
|
||||
points: number;
|
||||
timeLimit?: number;
|
||||
|
|
@ -42,7 +42,7 @@ export interface Question {
|
|||
lastModificationTime: Date;
|
||||
}
|
||||
|
||||
export interface QuestionOption {
|
||||
export interface QuestionOptionDto {
|
||||
id: string;
|
||||
text: string;
|
||||
isCorrect: boolean;
|
||||
|
|
@ -60,7 +60,7 @@ export interface Exam {
|
|||
name: string;
|
||||
};
|
||||
answerKeyTemplate?: AnswerKeyItem[];
|
||||
questions: Question[];
|
||||
questions: QuestionDto[];
|
||||
timeLimit: number;
|
||||
totalPoints: number;
|
||||
passingScore: number;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { QuestionPool, Exam, TagItem, ExamSession } from "@/types/coordinator";
|
||||
import { QuestionPoolDto, Exam, TagItem, ExamSession } from "@/types/coordinator";
|
||||
import { useState } from "react";
|
||||
|
||||
export function useCoordinator() {
|
||||
const [currentPath, setCurrentPath] = useState("/admin/dashboard");
|
||||
const [pools, setPools] = useState<QuestionPool[]>([]);
|
||||
const [pools, setPools] = useState<QuestionPoolDto[]>([]);
|
||||
const [exams, setExams] = useState<Exam[]>([]);
|
||||
const [tags, setTags] = useState<TagItem[]>([]);
|
||||
const [currentExam, setCurrentExam] = useState<Exam | null>(null);
|
||||
|
|
@ -19,9 +19,9 @@ export function useCoordinator() {
|
|||
};
|
||||
|
||||
const handleCreatePool = (
|
||||
poolData: Omit<QuestionPool, "id" | "creationTime">
|
||||
poolData: Omit<QuestionPoolDto, "id" | "creationTime">
|
||||
) => {
|
||||
const newPool: QuestionPool = {
|
||||
const newPool: QuestionPoolDto = {
|
||||
...poolData,
|
||||
id: `pool-${Date.now()}`,
|
||||
creationTime: new Date(),
|
||||
|
|
@ -29,7 +29,7 @@ export function useCoordinator() {
|
|||
setPools((prev) => [...prev, newPool]);
|
||||
};
|
||||
|
||||
const handleUpdatePool = (updatedPool: QuestionPool) => {
|
||||
const handleUpdatePool = (updatedPool: QuestionPoolDto) => {
|
||||
setPools((prev) =>
|
||||
prev.map((pool) => (pool.id === updatedPool.id ? updatedPool : pool))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { QuestionPool, Exam, Question } from "@/types/coordinator";
|
||||
import { QuestionPoolDto, Exam, QuestionDto } from "@/types/coordinator";
|
||||
import React, { useState } from "react";
|
||||
import { FaPlus, FaClock, FaUsers, FaCog, FaSave } from "react-icons/fa";
|
||||
|
||||
interface ExamCreatorProps {
|
||||
pools: QuestionPool[];
|
||||
pools: QuestionPoolDto[];
|
||||
onCreateExam: (exam: Omit<Exam, "id" | "creationTime" | "lastModificationTime">) => void;
|
||||
onCancel?: () => void;
|
||||
editingExam?: Exam;
|
||||
|
|
@ -30,7 +30,7 @@ export const ExamCreator: React.FC<ExamCreatorProps> = ({
|
|||
isActive: editingExam?.isActive ?? true,
|
||||
});
|
||||
|
||||
const [selectedQuestions, setSelectedQuestions] = useState<Question[]>(
|
||||
const [selectedQuestions, setSelectedQuestions] = useState<QuestionDto[]>(
|
||||
editingExam?.questions || []
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ import {
|
|||
import { useNavigate } from 'react-router-dom'
|
||||
import { generateMockExam } from '@/mocks/mockExams'
|
||||
import { generateMockPools } from '@/mocks/mockPools'
|
||||
import { Exam, QuestionPool } from '@/types/coordinator'
|
||||
import { Exam, QuestionPoolDto } from '@/types/coordinator'
|
||||
|
||||
const Assignments: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const [assignments, setAssignments] = useState<Exam[]>(generateMockExam())
|
||||
const [pools] = useState<QuestionPool[]>(generateMockPools())
|
||||
const [pools] = useState<QuestionPoolDto[]>(generateMockPools())
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [statusFilter, setStatusFilter] = useState('')
|
||||
const [isCreating, setIsCreating] = useState(false)
|
||||
|
|
|
|||
|
|
@ -179,13 +179,13 @@ const ClassList: React.FC = () => {
|
|||
|
||||
const handleJoinClass = (classSession: ClassroomDto) => {
|
||||
if (classSession.id) {
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.roomDetail.replace(':id', classSession.id))
|
||||
navigate(ROUTES_ENUM.protected.coordinator.classroom.roomDetail.replace(':id', classSession.id))
|
||||
}
|
||||
}
|
||||
|
||||
const handlePlanningClass = (classSession: ClassroomDto) => {
|
||||
if (classSession.id) {
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.planning.replace(':id', classSession.id))
|
||||
navigate(ROUTES_ENUM.protected.coordinator.classroom.planning.replace(':id', classSession.id))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +258,7 @@ const ClassList: React.FC = () => {
|
|||
<>
|
||||
<Helmet
|
||||
titleTemplate="%s | Sözsoft Kurs Platform"
|
||||
title={translate('::' + 'App.Classroom.List')}
|
||||
title={translate('::' + 'App.Coordinator.Classroom.List')}
|
||||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
<Container>
|
||||
|
|
@ -20,14 +20,14 @@ const Dashboard: React.FC = () => {
|
|||
role,
|
||||
})
|
||||
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.classes, { replace: true })
|
||||
navigate(ROUTES_ENUM.protected.coordinator.classroom.classes, { replace: true })
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet
|
||||
titleTemplate="%s | Sözsoft Kurs Platform"
|
||||
title={translate('::' + 'App.Classroom.Dashboard')}
|
||||
title={translate('::' + 'App.Coordinator.Classroom.Dashboard')}
|
||||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
<div className="flex items-center justify-center p-4">
|
||||
|
|
@ -164,7 +164,7 @@ const PlanningPage: React.FC = () => {
|
|||
<>
|
||||
<Helmet
|
||||
titleTemplate="%s | Sözsoft Kurs Platform"
|
||||
title={translate('::' + 'App.Classroom.Planning')}
|
||||
title={translate('::' + 'App.Coordinator.Classroom.Planning')}
|
||||
defaultTitle="Sözsoft Kurs Platform"
|
||||
/>
|
||||
<Container>
|
||||
|
|
@ -482,12 +482,12 @@ const RoomDetail: React.FC = () => {
|
|||
await cleanup()
|
||||
|
||||
// Başka sayfaya yönlendir
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.classes)
|
||||
navigate(ROUTES_ENUM.protected.coordinator.classroom.classes)
|
||||
} catch (err) {
|
||||
toast.push(<Notification title="⚠️ Çıkış sırasında hata oluştu" type="warning" />, {
|
||||
placement: 'top-end',
|
||||
})
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.classes)
|
||||
navigate(ROUTES_ENUM.protected.coordinator.classroom.classes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -855,7 +855,7 @@ const RoomDetail: React.FC = () => {
|
|||
<>
|
||||
<Helmet
|
||||
titleTemplate="%s | Sözsoft Kurs Platform"
|
||||
title={translate('::' + 'App.Classroom.RoomDetail')}
|
||||
title={translate('::' + 'App.Coordinator.Classroom.RoomDetail')}
|
||||
defaultTitle="Sözsoft Kurs Platform"
|
||||
></Helmet>
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React from 'react';
|
||||
|
||||
interface ExamNavigationProps {
|
||||
questions: Question[];
|
||||
questions: QuestionDto[];
|
||||
answers: StudentAnswer[];
|
||||
currentQuestionIndex: number;
|
||||
onQuestionSelect: (index: number) => void;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import { MultipleChoiceQuestion } from '../QuestionTypes/MultipleChoiceQuestion'
|
|||
import { OpenEndedQuestion } from '../QuestionTypes/OpenEndedQuestion';
|
||||
import { OrderingQuestion } from '../QuestionTypes/OrderingQuestion';
|
||||
import { TrueFalseQuestion } from '../QuestionTypes/TrueFalseQuestion';
|
||||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
|
||||
interface QuestionRendererProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string | string[]) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ import {
|
|||
import { useNavigate } from 'react-router-dom'
|
||||
import { generateMockExam } from '@/mocks/mockExams'
|
||||
import { generateMockPools } from '@/mocks/mockPools'
|
||||
import { Exam, QuestionPool } from '@/types/coordinator'
|
||||
import { Exam, QuestionPoolDto } from '@/types/coordinator'
|
||||
|
||||
const Exams: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const [exams, setExams] = useState<Exam[]>(generateMockExam())
|
||||
const [pools] = useState<QuestionPool[]>(generateMockPools())
|
||||
const [pools] = useState<QuestionPoolDto[]>(generateMockPools())
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [statusFilter, setStatusFilter] = useState('')
|
||||
const [isCreating, setIsCreating] = useState(false)
|
||||
|
|
|
|||
|
|
@ -1,34 +1,49 @@
|
|||
import { Question, QuestionType, QuestionDifficulty, QuestionOption } from "@/types/coordinator";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { FaSave, FaPlus, FaTrash, FaTimes } from "react-icons/fa";
|
||||
import { questionService } from '@/services/question.service'
|
||||
import {
|
||||
QuestionDto,
|
||||
QuestionType,
|
||||
QuestionDifficulty,
|
||||
QuestionOptionDto,
|
||||
} from '@/types/coordinator'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { FaSave, FaPlus, FaTrash, FaTimes } from 'react-icons/fa'
|
||||
|
||||
interface QuestionEditorProps {
|
||||
question?: Question;
|
||||
onSave: (question: Omit<Question, "id" | "creationTime" | "lastModificationTime">) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
||||
question,
|
||||
onSave,
|
||||
onCancel,
|
||||
}) => {
|
||||
function QuestionDialog({
|
||||
open,
|
||||
onDialogClose,
|
||||
id,
|
||||
}: {
|
||||
open: boolean
|
||||
onDialogClose: () => void
|
||||
id: string
|
||||
}) {
|
||||
const [question, setQuestion] = useState<QuestionDto>()
|
||||
const [formData, setFormData] = useState({
|
||||
type: "multiple-choice" as QuestionType,
|
||||
title: "",
|
||||
content: "",
|
||||
mediaUrl: "",
|
||||
mediaType: "image" as "image" | "video",
|
||||
type: 'multiple-choice' as QuestionType,
|
||||
title: '',
|
||||
content: '',
|
||||
mediaUrl: '',
|
||||
mediaType: 'image' as 'image' | 'video',
|
||||
points: 10,
|
||||
timeLimit: 0,
|
||||
explanation: "",
|
||||
tags: [] as string[],
|
||||
difficulty: "medium" as QuestionDifficulty,
|
||||
});
|
||||
explanation: '',
|
||||
difficulty: 'medium' as QuestionDifficulty,
|
||||
})
|
||||
|
||||
const [options, setOptions] = useState<QuestionOption[]>([]);
|
||||
const [correctAnswer, setCorrectAnswer] = useState<string | string[]>("");
|
||||
const [tagInput, setTagInput] = useState("");
|
||||
const [options, setOptions] = useState<QuestionOptionDto[]>([])
|
||||
const [correctAnswer, setCorrectAnswer] = useState<string | string[]>('')
|
||||
const [tagInput, setTagInput] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
const fetchQuestion = async () => {
|
||||
if (open) {
|
||||
const entity = await questionService.getQuestion(id)
|
||||
setQuestion(entity)
|
||||
}
|
||||
}
|
||||
|
||||
fetchQuestion()
|
||||
}, [open])
|
||||
|
||||
useEffect(() => {
|
||||
if (question) {
|
||||
|
|
@ -36,136 +51,103 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
type: question.type,
|
||||
title: question.title,
|
||||
content: question.content,
|
||||
mediaUrl: question.mediaUrl || "",
|
||||
mediaType: question.mediaType || "image",
|
||||
mediaUrl: question.mediaUrl || '',
|
||||
mediaType: question.mediaType || 'image',
|
||||
points: question.points,
|
||||
timeLimit: question.timeLimit || 0,
|
||||
explanation: question.explanation || "",
|
||||
tags: question.tags,
|
||||
explanation: question.explanation || '',
|
||||
difficulty: question.difficulty,
|
||||
});
|
||||
setOptions(question.options || []);
|
||||
setCorrectAnswer(question.correctAnswer || "");
|
||||
})
|
||||
setOptions(question.options || [])
|
||||
setCorrectAnswer(question.correctAnswer || '')
|
||||
}
|
||||
}, [question]);
|
||||
}, [question])
|
||||
|
||||
const handleInputChange = (field: string, value: any) => {
|
||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||
};
|
||||
setFormData((prev) => ({ ...prev, [field]: value }))
|
||||
}
|
||||
|
||||
const addOption = () => {
|
||||
const newOption: QuestionOption = {
|
||||
const newOption: QuestionOptionDto = {
|
||||
id: `opt-${Date.now()}`,
|
||||
text: "",
|
||||
text: '',
|
||||
isCorrect: false,
|
||||
order: options.length,
|
||||
};
|
||||
setOptions((prev) => [...prev, newOption]);
|
||||
};
|
||||
}
|
||||
setOptions((prev) => [...prev, newOption])
|
||||
}
|
||||
|
||||
const updateOption = (index: number, field: string, value: any) => {
|
||||
setOptions((prev) =>
|
||||
prev.map((opt, i) => (i === index ? { ...opt, [field]: value } : opt))
|
||||
);
|
||||
};
|
||||
setOptions((prev) => prev.map((opt, i) => (i === index ? { ...opt, [field]: value } : opt)))
|
||||
}
|
||||
|
||||
const removeOption = (index: number) => {
|
||||
setOptions((prev) => prev.filter((_, i) => i !== index));
|
||||
};
|
||||
|
||||
const addTag = () => {
|
||||
if (tagInput.trim() && !formData.tags.includes(tagInput.trim())) {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
tags: [...prev.tags, tagInput.trim()],
|
||||
}));
|
||||
setTagInput("");
|
||||
}
|
||||
};
|
||||
|
||||
const removeTag = (tag: string) => {
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
tags: prev.tags.filter((t) => t !== tag),
|
||||
}));
|
||||
};
|
||||
setOptions((prev) => prev.filter((_, i) => i !== index))
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
if (!formData.title.trim() || !formData.content.trim()) {
|
||||
alert("Please fill in the title and content fields.");
|
||||
return;
|
||||
alert('Please fill in the title and content fields.')
|
||||
return
|
||||
}
|
||||
|
||||
if (formData.points <= 0) {
|
||||
alert("Points must be greater than 0.");
|
||||
return;
|
||||
alert('Points must be greater than 0.')
|
||||
return
|
||||
}
|
||||
|
||||
// Validate based on question type
|
||||
if (
|
||||
["multiple-choice", "multiple-answer"].includes(formData.type) &&
|
||||
options.length < 2
|
||||
) {
|
||||
alert("Please add at least 2 options.");
|
||||
return;
|
||||
if (['multiple-choice', 'multiple-answer'].includes(formData.type) && options.length < 2) {
|
||||
alert('Please add at least 2 options.')
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
formData.type === "multiple-choice" &&
|
||||
!options.some((opt) => opt.isCorrect)
|
||||
) {
|
||||
alert("Please mark the correct answer.");
|
||||
return;
|
||||
if (formData.type === 'multiple-choice' && !options.some((opt) => opt.isCorrect)) {
|
||||
alert('Please mark the correct answer.')
|
||||
return
|
||||
}
|
||||
|
||||
const questionData = {
|
||||
...formData,
|
||||
options: [
|
||||
"multiple-choice",
|
||||
"multiple-answer",
|
||||
"matching",
|
||||
"ordering",
|
||||
].includes(formData.type)
|
||||
options: ['multiple-choice', 'multiple-answer', 'matching', 'ordering'].includes(
|
||||
formData.type,
|
||||
)
|
||||
? options
|
||||
: undefined,
|
||||
correctAnswer: getCorrectAnswer(),
|
||||
};
|
||||
}
|
||||
|
||||
onSave(questionData);
|
||||
};
|
||||
// onSave(questionData)
|
||||
}
|
||||
|
||||
const getCorrectAnswer = (): string | string[] => {
|
||||
switch (formData.type) {
|
||||
case "multiple-choice":
|
||||
return options.find((opt) => opt.isCorrect)?.id || "";
|
||||
case "multiple-answer":
|
||||
return options.filter((opt) => opt.isCorrect).map((opt) => opt.id);
|
||||
case "true-false":
|
||||
return correctAnswer as string;
|
||||
case "fill-blank":
|
||||
case "open-ended":
|
||||
case "calculation":
|
||||
return correctAnswer as string;
|
||||
case "matching":
|
||||
return options.map((opt) => opt.id);
|
||||
case "ordering":
|
||||
return options
|
||||
.sort((a, b) => (a.order || 0) - (b.order || 0))
|
||||
.map((opt) => opt.id);
|
||||
case 'multiple-choice':
|
||||
return options.find((opt) => opt.isCorrect)?.id || ''
|
||||
case 'multiple-answer':
|
||||
return options.filter((opt) => opt.isCorrect).map((opt) => opt.id)
|
||||
case 'true-false':
|
||||
return correctAnswer as string
|
||||
case 'fill-blank':
|
||||
case 'open-ended':
|
||||
case 'calculation':
|
||||
return correctAnswer as string
|
||||
case 'matching':
|
||||
return options.map((opt) => opt.id)
|
||||
case 'ordering':
|
||||
return options.sort((a, b) => (a.order || 0) - (b.order || 0)).map((opt) => opt.id)
|
||||
default:
|
||||
return correctAnswer as string;
|
||||
return correctAnswer as string
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const renderQuestionTypeSpecificFields = () => {
|
||||
switch (formData.type) {
|
||||
case "multiple-choice":
|
||||
case 'multiple-choice':
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-sm font-medium text-gray-900">
|
||||
Yanıtlar (A, B, C, D, E)
|
||||
</h4>
|
||||
<h4 className="text-sm font-medium text-gray-900">Yanıtlar (A, B, C, D, E)</h4>
|
||||
<button
|
||||
type="button"
|
||||
onClick={addOption}
|
||||
|
|
@ -194,15 +176,15 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
prev.map((opt, i) => ({
|
||||
...opt,
|
||||
isCorrect: i === index ? e.target.checked : false,
|
||||
}))
|
||||
);
|
||||
})),
|
||||
)
|
||||
}}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={option.text}
|
||||
onChange={(e) => updateOption(index, "text", e.target.value)}
|
||||
onChange={(e) => updateOption(index, 'text', e.target.value)}
|
||||
placeholder={`${String.fromCharCode(65 + index)} şıkkı`}
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
|
|
@ -216,9 +198,9 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "multiple-answer":
|
||||
case 'multiple-answer':
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
|
|
@ -243,21 +225,17 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
<input
|
||||
type="checkbox"
|
||||
checked={option.isCorrect}
|
||||
onChange={(e) =>
|
||||
updateOption(index, "isCorrect", e.target.checked)
|
||||
}
|
||||
onChange={(e) => updateOption(index, 'isCorrect', e.target.checked)}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={option.text}
|
||||
onChange={(e) => updateOption(index, "text", e.target.value)}
|
||||
onChange={(e) => updateOption(index, 'text', e.target.value)}
|
||||
placeholder={`Yanıt ${index + 1}`}
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<div className="text-sm text-gray-600">
|
||||
{option.isCorrect ? "Doğru" : "Yanlış"}
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">{option.isCorrect ? 'Doğru' : 'Yanlış'}</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeOption(index)}
|
||||
|
|
@ -268,21 +246,19 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "true-false":
|
||||
case 'true-false':
|
||||
return (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Doğru Cevap
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Doğru Cevap</label>
|
||||
<div className="flex space-x-4">
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
name="true-false"
|
||||
value="true"
|
||||
checked={correctAnswer === "true"}
|
||||
checked={correctAnswer === 'true'}
|
||||
onChange={(e) => setCorrectAnswer(e.target.value)}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
|
||||
/>
|
||||
|
|
@ -293,7 +269,7 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
type="radio"
|
||||
name="true-false"
|
||||
value="false"
|
||||
checked={correctAnswer === "false"}
|
||||
checked={correctAnswer === 'false'}
|
||||
onChange={(e) => setCorrectAnswer(e.target.value)}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
|
||||
/>
|
||||
|
|
@ -301,9 +277,9 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "fill-blank":
|
||||
case 'fill-blank':
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
|
|
@ -314,9 +290,7 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
|
||||
<div className="space-y-3">
|
||||
{Array.from({ length: 10 }, (_, index) => {
|
||||
const blankAnswers = ((correctAnswer as string) || "").split(
|
||||
"|"
|
||||
);
|
||||
const blankAnswers = ((correctAnswer as string) || '').split('|')
|
||||
return (
|
||||
<div key={index} className="flex items-center space-x-3">
|
||||
<div className="bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1 rounded min-w-16 text-center">
|
||||
|
|
@ -324,41 +298,35 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={blankAnswers[index] || ""}
|
||||
value={blankAnswers[index] || ''}
|
||||
onChange={(e) => {
|
||||
const newAnswers = [...blankAnswers];
|
||||
newAnswers[index] = e.target.value;
|
||||
const newAnswers = [...blankAnswers]
|
||||
newAnswers[index] = e.target.value
|
||||
// Remove empty answers from the end
|
||||
while (
|
||||
newAnswers.length > 0 &&
|
||||
!newAnswers[newAnswers.length - 1]
|
||||
) {
|
||||
newAnswers.pop();
|
||||
while (newAnswers.length > 0 && !newAnswers[newAnswers.length - 1]) {
|
||||
newAnswers.pop()
|
||||
}
|
||||
setCorrectAnswer(newAnswers.join("|"));
|
||||
setCorrectAnswer(newAnswers.join('|'))
|
||||
}}
|
||||
placeholder={`${index + 1}. boşluk için kelime/cümle`}
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-gray-500 mt-2">
|
||||
Soru içeriğinde _____ veya [blank] kullanarak boşlukları
|
||||
işaretleyin
|
||||
Soru içeriğinde _____ veya [blank] kullanarak boşlukları işaretleyin
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "matching":
|
||||
case 'matching':
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-md font-medium text-gray-900">
|
||||
Eşleştirme Çiftleri
|
||||
</h4>
|
||||
<h4 className="text-md font-medium text-gray-900">Eşleştirme Çiftleri</h4>
|
||||
<button
|
||||
type="button"
|
||||
onClick={addOption}
|
||||
|
|
@ -376,14 +344,10 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
>
|
||||
<input
|
||||
type="text"
|
||||
value={option.text.split("|")[0] || ""}
|
||||
value={option.text.split('|')[0] || ''}
|
||||
onChange={(e) => {
|
||||
const rightSide = option.text.split("|")[1] || "";
|
||||
updateOption(
|
||||
index,
|
||||
"text",
|
||||
`${e.target.value}|${rightSide}`
|
||||
);
|
||||
const rightSide = option.text.split('|')[1] || ''
|
||||
updateOption(index, 'text', `${e.target.value}|${rightSide}`)
|
||||
}}
|
||||
placeholder="Sol taraf (örn: PLUS)"
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
|
|
@ -391,14 +355,10 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
<span className="text-gray-400">↔</span>
|
||||
<input
|
||||
type="text"
|
||||
value={option.text.split("|")[1] || ""}
|
||||
value={option.text.split('|')[1] || ''}
|
||||
onChange={(e) => {
|
||||
const leftSide = option.text.split("|")[0] || "";
|
||||
updateOption(
|
||||
index,
|
||||
"text",
|
||||
`${leftSide}|${e.target.value}`
|
||||
);
|
||||
const leftSide = option.text.split('|')[0] || ''
|
||||
updateOption(index, 'text', `${leftSide}|${e.target.value}`)
|
||||
}}
|
||||
placeholder="Sağ taraf (örn: ARTI)"
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
|
|
@ -413,15 +373,13 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "ordering":
|
||||
case 'ordering':
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="text-md font-medium text-gray-900">
|
||||
Sıralanacak Öğeler
|
||||
</h4>
|
||||
<h4 className="text-md font-medium text-gray-900">Sıralanacak Öğeler</h4>
|
||||
<button
|
||||
type="button"
|
||||
onClick={addOption}
|
||||
|
|
@ -443,16 +401,14 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
<input
|
||||
type="number"
|
||||
value={option.order || index + 1}
|
||||
onChange={(e) =>
|
||||
updateOption(index, "order", parseInt(e.target.value))
|
||||
}
|
||||
onChange={(e) => updateOption(index, 'order', parseInt(e.target.value))}
|
||||
min="1"
|
||||
className="w-20 text-sm border border-gray-300 rounded-lg px-2 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={option.text}
|
||||
onChange={(e) => updateOption(index, "text", e.target.value)}
|
||||
onChange={(e) => updateOption(index, 'text', e.target.value)}
|
||||
placeholder={`Öğe ${index + 1} (örn: I, TAKE, A SHOWER)`}
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
|
|
@ -467,13 +423,12 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
))}
|
||||
|
||||
<p className="text-xs text-gray-500 mt-2">
|
||||
Öğrenciler bu öğeleri doğru sıraya göre düzenleyecek (drag & drop
|
||||
veya butonlarla)
|
||||
Öğrenciler bu öğeleri doğru sıraya göre düzenleyecek (drag & drop veya butonlarla)
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "open-ended":
|
||||
case 'open-ended':
|
||||
return (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
|
|
@ -486,13 +441,11 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
rows={4}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Öğrenci bu soruya açıklama yazabilecek
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 mt-1">Öğrenci bu soruya açıklama yazabilecek</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
case "calculation":
|
||||
case 'calculation':
|
||||
return (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
|
|
@ -509,24 +462,21 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
Öğrenci matematiksel hesaplama yapıp sayısal sonuç yazacak
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
||||
default:
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-lg max-w-4xl w-full max-h-[90vh] overflow-y-auto">
|
||||
<div className="sticky top-0 bg-white border-b border-gray-200 px-5 py-3 flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold text-gray-900">
|
||||
{question ? "Edit Question" : "Create New Question"}
|
||||
{question ? 'Edit Question' : 'Create New Question'}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onCancel}
|
||||
className="text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
<button onClick={onDialogClose} className="text-gray-400 hover:text-gray-600">
|
||||
<FaTimes className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -540,7 +490,7 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</label>
|
||||
<select
|
||||
value={formData.type}
|
||||
onChange={(e) => handleInputChange("type", e.target.value)}
|
||||
onChange={(e) => handleInputChange('type', e.target.value)}
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="multiple-choice">Multiple Choice</option>
|
||||
|
|
@ -555,15 +505,11 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Points
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Points</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.points}
|
||||
onChange={(e) =>
|
||||
handleInputChange("points", parseInt(e.target.value))
|
||||
}
|
||||
onChange={(e) => handleInputChange('points', parseInt(e.target.value))}
|
||||
min="1"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
|
|
@ -571,25 +517,21 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Question Title
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Question Title</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.title}
|
||||
onChange={(e) => handleInputChange("title", e.target.value)}
|
||||
onChange={(e) => handleInputChange('title', e.target.value)}
|
||||
placeholder="Enter question title..."
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Question Content
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Question Content</label>
|
||||
<textarea
|
||||
value={formData.content}
|
||||
onChange={(e) => handleInputChange("content", e.target.value)}
|
||||
onChange={(e) => handleInputChange('content', e.target.value)}
|
||||
placeholder="Enter the question content..."
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
rows={4}
|
||||
|
|
@ -605,19 +547,17 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
<input
|
||||
type="url"
|
||||
value={formData.mediaUrl}
|
||||
onChange={(e) => handleInputChange("mediaUrl", e.target.value)}
|
||||
onChange={(e) => handleInputChange('mediaUrl', e.target.value)}
|
||||
placeholder="https://example.com/image.jpg"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
Media Type
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Media Type</label>
|
||||
<select
|
||||
value={formData.mediaType}
|
||||
onChange={(e) => handleInputChange("mediaType", e.target.value)}
|
||||
onChange={(e) => handleInputChange('mediaType', e.target.value)}
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="image">Image</option>
|
||||
|
|
@ -632,14 +572,10 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
{/* Additional Settings */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Difficulty
|
||||
</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Difficulty</label>
|
||||
<select
|
||||
value={formData.difficulty}
|
||||
onChange={(e) =>
|
||||
handleInputChange("difficulty", e.target.value)
|
||||
}
|
||||
onChange={(e) => handleInputChange('difficulty', e.target.value)}
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="easy">Easy</option>
|
||||
|
|
@ -655,71 +591,20 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
<input
|
||||
type="number"
|
||||
value={formData.timeLimit}
|
||||
onChange={(e) =>
|
||||
handleInputChange("timeLimit", parseInt(e.target.value))
|
||||
}
|
||||
onChange={(e) => handleInputChange('timeLimit', parseInt(e.target.value))}
|
||||
min="0"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Add Tag
|
||||
</label>
|
||||
<div className="flex space-x-2">
|
||||
<input
|
||||
type="text"
|
||||
value={tagInput}
|
||||
onChange={(e) => setTagInput(e.target.value)}
|
||||
onKeyPress={(e) => e.key === "Enter" && addTag()}
|
||||
placeholder="grammar, vocabulary..."
|
||||
className="flex-1 text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={addTag}
|
||||
className="px-3 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
|
||||
>
|
||||
<FaPlus className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tags Display */}
|
||||
{formData.tags.length > 0 && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
Tags
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{formData.tags.map((tag) => (
|
||||
<span
|
||||
key={tag}
|
||||
className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"
|
||||
>
|
||||
{tag}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeTag(tag)}
|
||||
className="ml-1.5 text-blue-600 hover:text-blue-800"
|
||||
>
|
||||
<FaTimes className="w-2.5 h-2.5" />
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
Explanation (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.explanation}
|
||||
onChange={(e) => handleInputChange("explanation", e.target.value)}
|
||||
onChange={(e) => handleInputChange('explanation', e.target.value)}
|
||||
placeholder="Provide an explanation for the correct answer..."
|
||||
className="w-full text-sm border border-gray-300 rounded-lg px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
rows={3}
|
||||
|
|
@ -730,7 +615,7 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
{/* Footer */}
|
||||
<div className="sticky bottom-0 bg-gray-50 border-t border-gray-200 px-5 py-3 flex justify-end space-x-2">
|
||||
<button
|
||||
onClick={onCancel}
|
||||
onClick={onDialogClose}
|
||||
className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 font-medium transition-colors"
|
||||
>
|
||||
Cancel
|
||||
|
|
@ -745,5 +630,7 @@ export const QuestionEditor: React.FC<QuestionEditorProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default QuestionDialog
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
import React, { useState } from "react";
|
||||
import { QuestionEditor } from "./QuestionEditor";
|
||||
import { FaPlus, FaSearch, FaFilter, FaEdit, FaTrash } from "react-icons/fa";
|
||||
import { generateMockPools } from "@/mocks/mockPools";
|
||||
import { QuestionPool, Question } from "@/types/coordinator";
|
||||
import { QuestionPoolDto, QuestionDto } from "@/types/coordinator";
|
||||
import QuestionDialog from "./QuestionDialog";
|
||||
|
||||
export const QuestionPoolManager: React.FC = () => {
|
||||
const [pools, setPools] = useState<QuestionPool[]>(generateMockPools());
|
||||
const [pools, setPools] = useState<QuestionPoolDto[]>(generateMockPools());
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [selectedTag, setSelectedTag] = useState("");
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [editingPool, setEditingPool] = useState<QuestionPool | null>(null);
|
||||
const [editingQuestion, setEditingQuestion] = useState<Question | null>(null);
|
||||
const [editingPool, setEditingPool] = useState<QuestionPoolDto | null>(null);
|
||||
const [editingQuestion, setEditingQuestion] = useState<QuestionDto | null>(null);
|
||||
const [showQuestionEditor, setShowQuestionEditor] = useState(false);
|
||||
const [selectedPoolForQuestion, setSelectedPoolForQuestion] =
|
||||
useState<string>("");
|
||||
|
|
@ -34,7 +34,7 @@ export const QuestionPoolManager: React.FC = () => {
|
|||
const handleCreatePool = () => {
|
||||
if (!newPool.name.trim()) return;
|
||||
|
||||
const newPoolData: QuestionPool = {
|
||||
const newPoolData: QuestionPoolDto = {
|
||||
id: `pool-${Date.now()}`,
|
||||
name: newPool.name,
|
||||
description: newPool.description,
|
||||
|
|
@ -63,19 +63,19 @@ export const QuestionPoolManager: React.FC = () => {
|
|||
setShowQuestionEditor(true);
|
||||
};
|
||||
|
||||
const handleEditQuestion = (question: Question, poolId: string) => {
|
||||
const handleEditQuestion = (question: QuestionDto, poolId: string) => {
|
||||
setSelectedPoolForQuestion(poolId);
|
||||
setEditingQuestion(question);
|
||||
setShowQuestionEditor(true);
|
||||
};
|
||||
|
||||
const handleSaveQuestion = (
|
||||
questionData: Omit<Question, "id" | "creationTime" | "lastModificationTime">
|
||||
questionData: Omit<QuestionDto, "id" | "creationTime" | "lastModificationTime">
|
||||
) => {
|
||||
const pool = pools.find((p) => p.id === selectedPoolForQuestion);
|
||||
if (!pool) return;
|
||||
|
||||
const newQuestion: Question = {
|
||||
const newQuestion: QuestionDto = {
|
||||
...questionData,
|
||||
id: editingQuestion?.id || `q-${Date.now()}`,
|
||||
creationTime: editingQuestion?.creationTime || new Date(),
|
||||
|
|
@ -278,7 +278,7 @@ export const QuestionPoolManager: React.FC = () => {
|
|||
|
||||
{/* Question Editor Modal */}
|
||||
{showQuestionEditor && (
|
||||
<QuestionEditor
|
||||
<QuestionDialog
|
||||
question={editingQuestion || undefined}
|
||||
onSave={handleSaveQuestion}
|
||||
onCancel={() => setShowQuestionEditor(false)}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface CalculationQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface FillBlankQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string[]) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface MatchingQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string[]) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface MultipleAnswerQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string[]) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React from 'react';
|
||||
|
||||
interface MultipleChoiceQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface OpenEndedQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface OrderingQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string[]) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Question, StudentAnswer } from '@/types/coordinator';
|
||||
import { QuestionDto, StudentAnswer } from '@/types/coordinator';
|
||||
import React from 'react';
|
||||
|
||||
interface TrueFalseQuestionProps {
|
||||
question: Question;
|
||||
question: QuestionDto;
|
||||
answer?: StudentAnswer;
|
||||
onAnswerChange: (questionId: string, answer: string) => void;
|
||||
disabled?: boolean;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ const TagBoxEditorComponent = ({
|
|||
{...editorOptions}
|
||||
{...(setDefaultValue ? { defaultValue: val } : { value: val })}
|
||||
dataSource={editorOptions?.dataSource}
|
||||
valueExpr={lookupDto?.valueExpr}
|
||||
displayExpr={lookupDto?.displayExpr}
|
||||
valueExpr={lookupDto?.valueExpr?.toLocaleLowerCase()}
|
||||
displayExpr={lookupDto?.displayExpr?.toLocaleLowerCase()}
|
||||
showClearButton={options?.showClearButton}
|
||||
showSelectionControls={options?.showSelectionControls ?? true}
|
||||
maxDisplayedTags={options?.maxDisplayedTags}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import AuditLogDetail from '@/views/admin/auditLog/AuditLogDetail'
|
|||
import RolesPermission from '@/views/admin/role-management/RolesPermission'
|
||||
import UsersPermission from '@/views/admin/user-management/UsersPermission'
|
||||
import BranchSeed from '@/views/branch/BranchSeed'
|
||||
import QuestionDialog from '@/views/coordinator/QuestionDialog'
|
||||
|
||||
const DialogShowComponent = (): JSX.Element => {
|
||||
const dialogContext: any = useDialogContext()
|
||||
|
|
@ -59,6 +60,14 @@ const DialogShowComponent = (): JSX.Element => {
|
|||
{...dialogContext.config?.props}
|
||||
></BranchSeed>
|
||||
)
|
||||
case 'QuestionAnswers':
|
||||
return (
|
||||
<QuestionDialog
|
||||
open={true}
|
||||
onDialogClose={() => dialogContext.setConfig({})}
|
||||
{...dialogContext.config?.props}
|
||||
></QuestionDialog>
|
||||
)
|
||||
default:
|
||||
return <></>
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue