|
|
@ -0,0 +1,857 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
//using System.Web.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Nop.Core;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Factories;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Services;
|
||||
using Nop.Services.Customers;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Services.Logging;
|
||||
using Nop.Services.Messages;
|
||||
using Nop.Services.Security;
|
||||
using Nop.Web.Areas.Admin.Controllers;
|
||||
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
|
||||
using Nop.Web.Framework.Mvc.Filters;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Controllers
|
||||
{
|
||||
public partial class CourseController : BaseAdminController
|
||||
{
|
||||
private readonly IWorkContext _workContext;
|
||||
private readonly IPermissionService _permissionService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly ICustomerActivityService _customerActivityService;
|
||||
private readonly AdminCourseModelFactory _courseModelFactory;
|
||||
private readonly CourseService _courseService;
|
||||
private readonly INotificationService _notificationService;
|
||||
|
||||
public CourseController(IPermissionService permissionService
|
||||
, ILocalizationService localizationService
|
||||
, ICustomerActivityService customerActivityService
|
||||
, ICustomerService customerService
|
||||
, AdminCourseModelFactory courseModelFactory
|
||||
, CourseService courseService
|
||||
, INotificationService notificationService
|
||||
, IWorkContext workContext)
|
||||
{
|
||||
_permissionService = permissionService;
|
||||
_localizationService = localizationService;
|
||||
_customerActivityService = customerActivityService;
|
||||
_courseModelFactory = courseModelFactory;
|
||||
_courseService = courseService;
|
||||
_notificationService = notificationService;
|
||||
_workContext = workContext;
|
||||
}
|
||||
|
||||
public virtual IActionResult Index()
|
||||
{
|
||||
return RedirectToAction("List");
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> List()
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseSearchModel = new CourseSearchModel();
|
||||
|
||||
//prepare model
|
||||
var model = await _courseModelFactory.PrepareCourseSearchModelAsync(courseSearchModel);
|
||||
|
||||
return View("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/List.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public virtual async Task<IActionResult> CourseList(CourseSearchModel searchModel)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
searchModel.InstructorGUID = customer.CustomerGuid.ToString();
|
||||
|
||||
//prepare model
|
||||
var model = await _courseModelFactory.PrepareCourseListModelAsync(searchModel);
|
||||
|
||||
return Json(model);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> Create()
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var model = await _courseModelFactory.PrepareCourseModelAsync(new CourseModel(), null);
|
||||
|
||||
return View("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/Create.cshtml", model);
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> Sections(int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(courseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
|
||||
|
||||
var model = await _courseModelFactory.PrepareCourseModelAsync(new CourseModel(), courseExisting);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Sections.cshtml", model.Sections);
|
||||
}
|
||||
|
||||
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> Create(CourseModel model, bool continueEditing)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
var course = model.ToEntity<Course>();
|
||||
|
||||
course.InstructorId = customer.Id;
|
||||
course.InstructorGuid = customer.CustomerGuid;
|
||||
course.CreatedOnUtc = DateTime.UtcNow;
|
||||
course.UpdatedOnUtc = DateTime.UtcNow;
|
||||
|
||||
await _courseService.InsertOrUpdateCourseAsync(course);
|
||||
|
||||
//foreach (var sectionModel in model.Sections)
|
||||
//{
|
||||
// var section = sectionModel.ToEntity<Section>();
|
||||
// section.CourseId = course.Id;
|
||||
// await _courseService.InsertOrUpdateSectionAsync(section);
|
||||
// foreach (var lessonModel in sectionModel.Lessons)
|
||||
// {
|
||||
// var lesson = lessonModel.ToEntity<Lesson>();
|
||||
// await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
// await _courseService.InsertOrUpdateSectionLessonAsync(new SectionLesson
|
||||
// {
|
||||
// CourseId = course.Id,
|
||||
// DisplayOrder = lessonModel.DisplayOrder,
|
||||
// LessonId = lesson.Id,
|
||||
// IsFreeLesson = lessonModel.IsFreeLesson,
|
||||
// SectionId = section.Id
|
||||
// });
|
||||
|
||||
// if (lessonModel.LessonType == LessonType.Document)
|
||||
// {
|
||||
// foreach (var attachmentModel in lessonModel.Attachments)
|
||||
// {
|
||||
// var attachment = attachmentModel.ToEntity<Attachment>();
|
||||
// attachment.InstructorId = customer.Id;
|
||||
// attachment.InstructorGuid = customer.CustomerGuid;
|
||||
// await _courseService.InsertOrUpdateAttachmentAsync(attachment);
|
||||
// await _courseService.InsertOrUpdateLessonAttachmentAsync(new LessonAttachment
|
||||
// {
|
||||
// AttachmentId = attachment.Id,
|
||||
// LessonId = lesson.Id
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// else if (lessonModel.LessonType == LessonType.Video)
|
||||
// {
|
||||
// if (lessonModel.Video != null)
|
||||
// {
|
||||
// var video = lessonModel.Video.ToEntity<Video>();
|
||||
// await _courseService.InsertOrUpdateVideoAsync(video);
|
||||
// lesson.VideoId = video.Id;
|
||||
// await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
if (!continueEditing)
|
||||
return RedirectToAction("List");
|
||||
|
||||
model = await _courseModelFactory.PrepareCourseModelAsync(new CourseModel(), null);
|
||||
|
||||
return RedirectToAction("Edit", new { id = course.Id });
|
||||
}
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> Edit(int id)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
|
||||
var course = await _courseService.GetCourseById(id);
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (course.InstructorGuid != customer.CustomerGuid && course.Id != id)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
//prepare model
|
||||
var model = await _courseModelFactory.PrepareCourseModelAsync(new CourseModel(), course);
|
||||
|
||||
return View("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/Edit.cshtml", model);
|
||||
}
|
||||
|
||||
|
||||
[HttpPost, ParameterBasedOnFormName("save-continue", "continueEditing")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> Edit(CourseModel model, bool continueEditing)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(model.Id);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid && courseExisting.Id != model.Id)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var courseNew = courseExisting;
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var course = model.ToEntity<Course>();
|
||||
courseNew = course;
|
||||
course.CreatedOnUtc = courseExisting.CreatedOnUtc;
|
||||
course.UpdatedOnUtc = DateTime.UtcNow;
|
||||
|
||||
course.InstructorId = customer.Id;
|
||||
course.InstructorGuid = customer.CustomerGuid;
|
||||
|
||||
await _courseService.InsertOrUpdateCourseAsync(course);
|
||||
|
||||
//var existingSections = await _courseService.GetSectionsByCourseIdAsync(course.Id);
|
||||
|
||||
|
||||
|
||||
//var lstSectionsToDelete = existingSections.Select(p => p.Id).ToList();
|
||||
|
||||
//foreach (var sectionModel in model.Sections)
|
||||
//{
|
||||
// if (sectionModel.Id > 0)
|
||||
// {
|
||||
// lstSectionsToDelete.Remove(sectionModel.Id);
|
||||
// }
|
||||
|
||||
// var section = sectionModel.ToEntity<Section>();
|
||||
// section.CourseId = course.Id;
|
||||
// await _courseService.InsertOrUpdateSectionAsync(section);
|
||||
|
||||
// foreach (var lessonModel in sectionModel.Lessons)
|
||||
// {
|
||||
// var lesson = lessonModel.ToEntity<Lesson>();
|
||||
// await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
// await _courseService.InsertOrUpdateSectionLessonAsync(new SectionLesson
|
||||
// {
|
||||
// CourseId = course.Id,
|
||||
// DisplayOrder = lessonModel.DisplayOrder,
|
||||
// LessonId = lesson.Id,
|
||||
// IsFreeLesson = lessonModel.IsFreeLesson,
|
||||
// SectionId = section.Id
|
||||
// });
|
||||
|
||||
// if (lessonModel.LessonType == LessonType.Document)
|
||||
// {
|
||||
// foreach (var attachmentModel in lessonModel.Attachments)
|
||||
// {
|
||||
// var attachment = attachmentModel.ToEntity<Attachment>();
|
||||
// attachment.InstructorId = customer.Id;
|
||||
// attachment.InstructorGuid = customer.CustomerGuid;
|
||||
// await _courseService.InsertOrUpdateAttachmentAsync(attachment);
|
||||
// await _courseService.InsertOrUpdateLessonAttachmentAsync(new LessonAttachment
|
||||
// {
|
||||
// AttachmentId = attachment.Id,
|
||||
// LessonId = lesson.Id
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// else if (lessonModel.LessonType == LessonType.Video)
|
||||
// {
|
||||
// if (lessonModel.Video != null)
|
||||
// {
|
||||
// var video = lessonModel.Video.ToEntity<Video>();
|
||||
// await _courseService.InsertOrUpdateVideoAsync(video);
|
||||
// lesson.VideoId = video.Id;
|
||||
// await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//await NormalizeSections(lstSectionsToDelete);
|
||||
|
||||
if (!continueEditing)
|
||||
return RedirectToAction("List");
|
||||
|
||||
return RedirectToAction("Edit", new { id = course.Id });
|
||||
}
|
||||
|
||||
//prepare model
|
||||
model = await _courseModelFactory.PrepareCourseModelAsync(model, courseNew);
|
||||
|
||||
//if we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> Delete(int id)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(id);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid && courseExisting.Id != id)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
await _courseService.DeleteCourseFullByIdAsync(courseExisting.Id);
|
||||
|
||||
_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("SimpleLMS.Course") + " "
|
||||
+ await _localizationService.GetResourceAsync("SimpleLMS.Deleted"));
|
||||
|
||||
return RedirectToAction("List");
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> CreateSection(int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(courseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var model = await _courseModelFactory.PrepareSectionModelAsync(new SectionModel(), courseExisting, null);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Section_CreateOrEdit.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> CreateSection(SectionModel sectionModel)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (sectionModel.Id > 0)
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(sectionModel.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var section = sectionModel.ToEntity<Section>();
|
||||
await _courseService.InsertOrUpdateSectionAsync(section);
|
||||
|
||||
return Json(new { success = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
responseText = await _localizationService.GetResourceAsync("SimpleLMS.InvalidData")
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> EditSection(int sectionId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var sectionExisting = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
var courseExisting = await _courseService.GetCourseById(sectionExisting.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var model = await _courseModelFactory.PrepareSectionModelAsync(new SectionModel(), courseExisting, sectionExisting);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Section_CreateOrEdit.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> EditSection(SectionModel sectionModel)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (sectionModel.Id == 0)
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(sectionModel.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var section = sectionModel.ToEntity<Section>();
|
||||
await _courseService.InsertOrUpdateSectionAsync(section);
|
||||
|
||||
return Json(new { success = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
responseText = await _localizationService.GetResourceAsync("SimpleLMS.InvalidData")
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> SortLessons(int sectionId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var sectionExisting = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
var courseExisting = await _courseService.GetCourseById(sectionExisting.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
var sectionLessons = await _courseService.GetSectionLessonsBySectionIdAsync(sectionExisting.Id);
|
||||
var lessons = await _courseService.GetLessonsBySectionIdAsync(sectionExisting.Id);
|
||||
|
||||
var doModels = from sl in sectionLessons
|
||||
select new DisplayOrderRecord
|
||||
{
|
||||
Id = sl.Id,
|
||||
DisplayOrder = sl.DisplayOrder,
|
||||
DisplayText = lessons.Where(p => p.Id == sl.LessonId).Select(l => l.Name).FirstOrDefault()
|
||||
};
|
||||
|
||||
var model = await _courseModelFactory.PrepareSortableEntityModelAsync(new SortableEntity(), doModels, SortRecordType.Lesson, sectionExisting.Id);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Sortable.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> SortLessons(SortableEntity sortableEntity)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var sectionExisting = await _courseService.GetSectionByIdAsync(sortableEntity.ParentId);
|
||||
var courseExisting = await _courseService.GetCourseById(sectionExisting.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
var sectionLessons = await _courseService.GetSectionLessonsBySectionIdAsync(sectionExisting.Id);
|
||||
|
||||
if (sectionLessons != null && sectionLessons.Count > 0)
|
||||
{
|
||||
|
||||
for (int i = 0; i < sortableEntity.NewSortOrderValues.Count; i++)
|
||||
{
|
||||
sortableEntity.NewSortOrderValues[i] = Regex.Match(sortableEntity.NewSortOrderValues[i], @"\d+").Value;
|
||||
}
|
||||
|
||||
foreach (var sl in sectionLessons)
|
||||
{
|
||||
sl.DisplayOrder = Array.FindIndex(sortableEntity.NewSortOrderValues.ToArray()
|
||||
, x => x == sl.Id.ToString()) + 1;
|
||||
}
|
||||
|
||||
await _courseService.UpdateSectionLessonsAsync(sectionLessons);
|
||||
|
||||
return Json(new { Result = true });
|
||||
}
|
||||
|
||||
return Json(new { Result = false });
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> SortSections(int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(courseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
var sections = await _courseService.GetSectionsByCourseIdAsync(courseExisting.Id);
|
||||
|
||||
var inputModels = from s in sections
|
||||
select new DisplayOrderRecord
|
||||
{
|
||||
Id = s.Id,
|
||||
DisplayOrder = s.DisplayOrder,
|
||||
DisplayText = s.Title
|
||||
};
|
||||
|
||||
var model = await _courseModelFactory.PrepareSortableEntityModelAsync(new SortableEntity(), inputModels, SortRecordType.Section, courseExisting.Id);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Sortable.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> SortSections(SortableEntity sortableEntity)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(sortableEntity.ParentId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
|
||||
var sections = await _courseService.GetSectionsByCourseIdAsync(sortableEntity.ParentId);
|
||||
|
||||
if (sections != null && sections.Count > 0)
|
||||
{
|
||||
|
||||
for (int i = 0; i < sortableEntity.NewSortOrderValues.Count; i++)
|
||||
{
|
||||
sortableEntity.NewSortOrderValues[i] = Regex.Match(sortableEntity.NewSortOrderValues[i], @"\d+").Value;
|
||||
}
|
||||
|
||||
foreach (var sl in sections)
|
||||
{
|
||||
sl.DisplayOrder = Array.FindIndex(sortableEntity.NewSortOrderValues.ToArray()
|
||||
, x => x == sl.Id.ToString()) + 1;
|
||||
|
||||
await _courseService.InsertOrUpdateSectionAsync(sl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return Json(new { Result = true });
|
||||
}
|
||||
|
||||
return Json(new { Result = false });
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> DeleteSection(int sectionId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
await _courseService.DeleteSectionAsync(sectionId);
|
||||
|
||||
return Json(new { Result = true });
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> CreateLesson(int sectionId, int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (courseExisting.Id != courseId)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var model = await _courseModelFactory.PrepareLessonModelAsync(new LessonModel(), section, courseExisting, null);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Lesson_CreateOrEdit.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> CreateLesson(LessonModel lessonModel)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
if (lessonModel.Id > 0)
|
||||
return AccessDeniedView();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(lessonModel.SectionId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var videoId = 0;
|
||||
|
||||
if (lessonModel.LessonType == LessonType.Video)
|
||||
{
|
||||
var video = new Video();
|
||||
video.Duration = lessonModel.Duration;
|
||||
video.InstructorGuid = customer.CustomerGuid;
|
||||
video.InstructorId = customer.Id;
|
||||
video.VideoTypeId = (int)lessonModel.VideoType;
|
||||
video.VideoIdFromProvider = lessonModel.VideoIdFromProvider;
|
||||
|
||||
await _courseService.InsertOrUpdateVideoAsync(video);
|
||||
videoId = video.Id;
|
||||
}
|
||||
|
||||
|
||||
var lesson = lessonModel.ToEntity<Lesson>();
|
||||
|
||||
|
||||
|
||||
if (lessonModel.LessonType == LessonType.Text)
|
||||
{
|
||||
lesson.VideoId = null;
|
||||
}
|
||||
|
||||
lesson.InstructorId = customer.Id;
|
||||
lesson.InstructorGuid = customer.CustomerGuid;
|
||||
|
||||
lesson.DocumentId = null;
|
||||
lesson.PictureId = null;
|
||||
|
||||
lesson.LessonTypeId = (int)lessonModel.LessonType;
|
||||
|
||||
if (videoId > 0)
|
||||
lesson.VideoId = videoId;
|
||||
|
||||
await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
|
||||
var sectionLesson = new SectionLesson();
|
||||
sectionLesson.SectionId = lessonModel.SectionId;
|
||||
sectionLesson.LessonId = lesson.Id;
|
||||
sectionLesson.DisplayOrder = lessonModel.DisplayOrder;
|
||||
sectionLesson.IsFreeLesson = lessonModel.IsFreeLesson;
|
||||
sectionLesson.CourseId = lessonModel.CourseId;
|
||||
|
||||
await _courseService.InsertOrUpdateSectionLessonAsync(sectionLesson);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return BadRequest(ModelState);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> EditLesson(int lessonId, int sectionId, int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var lesson = await _courseService.GetLessonByIdAsync(lessonId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
if (lesson.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var lessonSections = await _courseService.GetLessonSectionByLessonIdAsync(lessonId);
|
||||
|
||||
if (!lessonSections.Select(p => p.SectionId).Contains(sectionId))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (courseExisting.Id != courseId)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
|
||||
var model = await _courseModelFactory.PrepareLessonModelAsync(new LessonModel(), section, courseExisting, lesson);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Course/_CreateOrUpdate.Lesson_CreateOrEdit.cshtml", model);
|
||||
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> EditLesson(LessonModel lessonModel)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (lessonModel.Id == 0)
|
||||
return AccessDeniedView();
|
||||
|
||||
|
||||
var lesson = await _courseService.GetLessonByIdAsync(lessonModel.Id);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (lesson.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(lessonModel.SectionId);
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
|
||||
if (courseExisting.Id != lessonModel.CourseId)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return await AccessDeniedDataTablesJson();
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var videoId = 0;
|
||||
|
||||
var videoIdToDelete = 0;
|
||||
|
||||
if (lessonModel.LessonType == LessonType.Video)
|
||||
{
|
||||
var video = await _courseService.GetVideoByLessonIdAsync(lessonModel.Id);
|
||||
|
||||
if (video == null)
|
||||
video = new Video();
|
||||
|
||||
video.Duration = lessonModel.Duration;
|
||||
video.InstructorGuid = customer.CustomerGuid;
|
||||
video.InstructorId = customer.Id;
|
||||
video.VideoTypeId = (int)lessonModel.VideoType;
|
||||
video.VideoIdFromProvider = lessonModel.VideoIdFromProvider;
|
||||
|
||||
await _courseService.InsertOrUpdateVideoAsync(video);
|
||||
videoId = video.Id;
|
||||
}
|
||||
else if (lessonModel.LessonType == LessonType.Text && lesson.LessonType == LessonType.Video)
|
||||
{
|
||||
var video = await _courseService.GetVideoByLessonIdAsync(lessonModel.Id);
|
||||
videoIdToDelete = video.Id;
|
||||
}
|
||||
|
||||
lesson = lessonModel.ToEntity<Lesson>();
|
||||
|
||||
if (lessonModel.LessonType == LessonType.Text)
|
||||
{
|
||||
lesson.VideoId = null;
|
||||
}
|
||||
|
||||
lesson.InstructorId = customer.Id;
|
||||
lesson.InstructorGuid = customer.CustomerGuid;
|
||||
|
||||
lesson.DocumentId = null;
|
||||
lesson.PictureId = null;
|
||||
|
||||
lesson.LessonTypeId = (int)lessonModel.LessonType;
|
||||
|
||||
if (videoId > 0)
|
||||
lesson.VideoId = videoId;
|
||||
|
||||
await _courseService.InsertOrUpdateLessonAsync(lesson);
|
||||
|
||||
if (videoIdToDelete > 0)
|
||||
await _courseService.DeleteVideoAsync(videoIdToDelete);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return BadRequest(ModelState);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> DeleteLesson(int lessonId, int sectionId, int courseId)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageProducts))
|
||||
return AccessDeniedView();
|
||||
|
||||
var lesson = await _courseService.GetLessonByIdAsync(lessonId);
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (lesson.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
var section = await _courseService.GetSectionByIdAsync(sectionId);
|
||||
var courseExisting = await _courseService.GetCourseById(section.CourseId);
|
||||
|
||||
if (courseExisting.Id != courseId)
|
||||
return AccessDeniedView();
|
||||
|
||||
if (courseExisting.InstructorGuid != customer.CustomerGuid)
|
||||
return AccessDeniedView();
|
||||
|
||||
await _courseService.DeleteSectionLessonAsync(sectionId, lessonId);
|
||||
|
||||
await _customerActivityService.InsertActivityAsync(customer, "DeleteLesson",
|
||||
await _localizationService.GetResourceAsync("SimpleLMS.Lesson") + ": " + lesson.Id + ". " + lesson.Name +
|
||||
await _localizationService.GetResourceAsync("SimpleLMS.Lesson") + ": " + section.Id + ". " + section.Title);
|
||||
|
||||
//_notificationService.SuccessNotification(await _localizationService.GetResourceAsync("SimpleLMS.Lesson") + ' '
|
||||
// + await _localizationService.GetResourceAsync("SimpleLMS.Deleted"));
|
||||
|
||||
return Json(new { Result = true });
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task NormalizeSections(List<int> lstSectionsToDelete)
|
||||
{
|
||||
foreach (var secId in lstSectionsToDelete)
|
||||
{
|
||||
//var section = await _courseService.GetSectionByIdAsync(secId);
|
||||
//var lessons = await _courseService.GetLessonsBySectionIdAsync(secId);
|
||||
|
||||
//foreach (var lesson in lessons)
|
||||
//{
|
||||
// await _courseService.DeleteLessonAttachmentsAsync(lesson, secId);
|
||||
// await _courseService.DeleteLessonVideosAsync(lesson, secId);
|
||||
//}
|
||||
|
||||
await _courseService.DeleteSectionLessonsBySecIdAsync(secId);
|
||||
await _courseService.DeleteSectionAsync(secId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Nop.Core;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Services.Configuration;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Services.Security;
|
||||
using Nop.Web.Areas.Admin.Controllers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Controllers
|
||||
{
|
||||
public partial class SettingsController : BaseAdminController
|
||||
{
|
||||
private readonly ISettingService _settingService;
|
||||
private readonly IStoreContext _storeContext;
|
||||
private readonly IPermissionService _permissionService;
|
||||
public SettingsController(ISettingService settingService,IStoreContext storeContext,ILocalizationService localizationService,IPermissionService permissionService)
|
||||
{
|
||||
_settingService = settingService;
|
||||
_storeContext = storeContext;
|
||||
_permissionService = permissionService;
|
||||
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Configure()
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageWidgets))
|
||||
return AccessDeniedView();
|
||||
|
||||
//load settings for a chosen store scope
|
||||
var storeScope = await _storeContext.GetActiveStoreScopeConfigurationAsync();
|
||||
var simpleLMSSettings = await _settingService.LoadSettingAsync<SimpleLMSSettings>(storeScope);
|
||||
var model = new ConfigurationModel
|
||||
{
|
||||
//YouTubeApiKey = simpleLMSSettings.YouTubeApiKey,
|
||||
//VimeoAppId=simpleLMSSettings.VimeoAppId,
|
||||
VimeoClient=simpleLMSSettings.VimeoClient,
|
||||
VimeoAccess=simpleLMSSettings.VimeoAccess,
|
||||
VimeoSecret=simpleLMSSettings.VimeoSecret,
|
||||
//VdoCipherKey=simpleLMSSettings.VdoCipherKey
|
||||
};
|
||||
return View("~/Plugins/Misc.SimpleLMS/Areas/Admin/Views/Settings/Configure.cshtml", model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
/// <returns>A task that represents the asynchronous operation</returns>
|
||||
public async Task<IActionResult> Configure(ConfigurationModel model)
|
||||
{
|
||||
if (!await _permissionService.AuthorizeAsync(StandardPermissionProvider.ManageWidgets))
|
||||
return AccessDeniedView();
|
||||
|
||||
//load settings for a chosen store scope
|
||||
var storeScope = await _storeContext.GetActiveStoreScopeConfigurationAsync();
|
||||
var simpleLMSSettings = await _settingService.LoadSettingAsync<SimpleLMSSettings>(storeScope);
|
||||
|
||||
//get previous picture identifiers
|
||||
|
||||
|
||||
//simpleLMSSettings.YouTubeApiKey = model.YouTubeApiKey;
|
||||
|
||||
//simpleLMSSettings.VimeoAppId = model.VimeoAppId;
|
||||
|
||||
simpleLMSSettings.VimeoClient = model.VimeoClient;
|
||||
|
||||
simpleLMSSettings.VimeoAccess = model.VimeoAccess;
|
||||
|
||||
simpleLMSSettings.VimeoSecret = model.VimeoSecret;
|
||||
//simpleLMSSettings.VdoCipherKey = model.VdoCipherKey;
|
||||
/* We do not clear cache after each setting update.
|
||||
* This behavior can increase performance because cached settings will not be cleared
|
||||
* and loaded from database after each update */
|
||||
//await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.YouTubeApiKey, storeScope, false);
|
||||
//await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.VimeoAppId, storeScope, false);
|
||||
await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.VimeoClient, storeScope, false);
|
||||
await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.VimeoAccess, storeScope, false);
|
||||
await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.VimeoSecret, storeScope, false);
|
||||
//await _settingService.SaveSettingAsync(simpleLMSSettings, x => x.VdoCipherKey, storeScope, false);
|
||||
//now clear settings cache
|
||||
await _settingService.ClearCacheAsync();
|
||||
|
||||
|
||||
return await Configure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Nop.Core;
|
||||
using Nop.Services.Catalog;
|
||||
using Nop.Services.Customers;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
|
||||
using Nop.Web.Framework.Models.Extensions;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Services;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Factories
|
||||
{
|
||||
public partial class AdminCourseModelFactory
|
||||
{
|
||||
|
||||
private readonly CourseService _courseService;
|
||||
private readonly ICustomerService _customerService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IProductService _productService;
|
||||
private readonly IWorkContext _workContext;
|
||||
|
||||
public AdminCourseModelFactory(
|
||||
IProductService productService,
|
||||
ILocalizationService localizationService,
|
||||
IWorkContext workContext,
|
||||
ICustomerService customerService,
|
||||
CourseService courseService)
|
||||
{
|
||||
_productService = productService;
|
||||
_workContext = workContext;
|
||||
_localizationService = localizationService;
|
||||
_customerService = customerService;
|
||||
_courseService = courseService;
|
||||
}
|
||||
|
||||
public async Task<CourseListModel> PrepareCourseListModelAsync(CourseSearchModel searchModel)
|
||||
{
|
||||
if (searchModel == null)
|
||||
throw new ArgumentNullException(nameof(searchModel));
|
||||
|
||||
|
||||
//get courses
|
||||
var courses = await _courseService.SearchCoursesAsync(pageIndex: searchModel.Page - 1,
|
||||
pageSize: searchModel.PageSize,
|
||||
keyword: searchModel.SearchCourseName,
|
||||
instructorGUID: searchModel.InstructorGUID);
|
||||
|
||||
//prepare list model
|
||||
var model = await new CourseListModel().PrepareToGridAsync(searchModel, courses, () =>
|
||||
{
|
||||
return courses.SelectAwait(async course =>
|
||||
{
|
||||
//fill in model values from the entity
|
||||
var courseModel = course.ToModel<CourseModel>();
|
||||
|
||||
|
||||
//fill in additional values (not existing in the entity)
|
||||
courseModel.Category = string.Empty;
|
||||
|
||||
var product = await _productService.GetProductByIdAsync(course.ProductId);
|
||||
courseModel.ParentProductName = product.Name;
|
||||
courseModel.Price = product.Price;
|
||||
courseModel.Status = product.Published ? "Published" : "Unpublished";
|
||||
|
||||
var customer = await _customerService.GetCustomerByIdAsync(course.InstructorId);
|
||||
|
||||
courseModel.Instructor = customer.Username;
|
||||
|
||||
var courseStat = await _courseService.GetCourseStatsByCourseIdAsync(course.Id);
|
||||
|
||||
courseModel.LessonsTotal = courseStat.Lessons;
|
||||
courseModel.SectionsTotal = courseStat.Sections;
|
||||
courseModel.EnrolledStudents = courseStat.EnrolledStudents;
|
||||
|
||||
|
||||
|
||||
return courseModel;
|
||||
});
|
||||
});
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<CourseModel> PrepareCourseModelAsync(CourseModel courseModel, Course course)
|
||||
{
|
||||
if (courseModel == null)
|
||||
throw new ArgumentNullException(nameof(courseModel));
|
||||
|
||||
if (course != null)
|
||||
{
|
||||
//fill in model values from the entity
|
||||
if (course != null)
|
||||
{
|
||||
courseModel = course.ToModel<CourseModel>();
|
||||
}
|
||||
|
||||
var parentProduct = await _productService.GetProductByIdAsync(course.ProductId);
|
||||
|
||||
if (parentProduct != null)
|
||||
{
|
||||
courseModel.ParentProductName = parentProduct.Name;
|
||||
courseModel.ProductId = parentProduct.Id;
|
||||
}
|
||||
|
||||
courseModel.Sections = (await _courseService.GetSectionsByCourseIdAsync(courseModel.Id)).OrderBy(p => p.DisplayOrder).Select(p =>
|
||||
new SectionModel
|
||||
{
|
||||
CourseName = courseModel.Name,
|
||||
DisplayOrder = p.DisplayOrder,
|
||||
Id = p.Id,
|
||||
IsFree = p.IsFree,
|
||||
Title = p.Title,
|
||||
CourseId = course.Id,
|
||||
Lessons = _courseService.GetLessonsBySectionIdAsync(p.Id)
|
||||
.GetAwaiter().GetResult().Select(l => l.ToModel<LessonModel>()).ToList()
|
||||
}).ToList();
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < courseModel.Sections.Count; i++)
|
||||
{
|
||||
var sectionLessons = await _courseService.GetSectionLessonsBySectionIdAsync(courseModel.Sections[i].Id);
|
||||
|
||||
for (int j = 0; j < courseModel.Sections[i].Lessons.Count; j++)
|
||||
{
|
||||
courseModel.Sections[i].Lessons[j].SectionId = courseModel.Sections[i].Id;
|
||||
courseModel.Sections[i].Lessons[j].CourseId = courseModel.Id;
|
||||
courseModel.Sections[i].Lessons[j].DisplayOrder
|
||||
= sectionLessons.Where(p => p.LessonId == courseModel.Sections[i].Lessons[j].Id).SingleOrDefault().DisplayOrder;
|
||||
}
|
||||
|
||||
courseModel.Sections[i].Lessons = courseModel.Sections[i].Lessons.OrderBy(p => p.DisplayOrder).ToList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
courseModel.AvailableProducts = await _courseService.GetProductsByCurrentUserAsync();
|
||||
courseModel.AvailableProducts.Insert(0, new SelectListItem { Text = await _localizationService.GetResourceAsync("SimpleLMS.Select"), Value = "" });
|
||||
|
||||
return courseModel;
|
||||
}
|
||||
|
||||
protected IList<LessonModel> GetLessonsBySectionIdForAdmin(int id)
|
||||
{
|
||||
var task = _courseService.GetLessonsBySectionIdAsync(id);
|
||||
task.RunSynchronously();
|
||||
var result = task.Result.Select(p => p.ToModel<LessonModel>());
|
||||
return result.ToList();
|
||||
}
|
||||
|
||||
|
||||
public async Task<CourseSearchModel> PrepareCourseSearchModelAsync(CourseSearchModel searchModel)
|
||||
{
|
||||
if (searchModel == null)
|
||||
throw new ArgumentNullException(nameof(searchModel));
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
searchModel.InstructorGUID = customer.CustomerGuid.ToString();
|
||||
|
||||
searchModel.SetGridPageSize();
|
||||
|
||||
return searchModel;
|
||||
}
|
||||
|
||||
public async Task<SectionModel> PrepareSectionModelAsync(SectionModel sectionModel, Course course, Section section, bool loadLessons = false)
|
||||
{
|
||||
if (sectionModel == null)
|
||||
throw new ArgumentNullException(nameof(sectionModel));
|
||||
|
||||
if (course == null)
|
||||
throw new ArgumentNullException(nameof(course));
|
||||
|
||||
if (section != null)
|
||||
{
|
||||
sectionModel = section.ToModel<SectionModel>();
|
||||
sectionModel.CourseId = section.CourseId;
|
||||
|
||||
//if (loadLessons)
|
||||
//{
|
||||
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionModel.CourseId = course.Id;
|
||||
|
||||
//load display order
|
||||
var sections = await _courseService.GetSectionsByCourseIdAsync(course.Id);
|
||||
if (sections != null && sections.Count > 0)
|
||||
{
|
||||
sectionModel.DisplayOrder = sections.Max(p => p.DisplayOrder) + 1;
|
||||
}
|
||||
if (sectionModel.DisplayOrder == 0)
|
||||
{
|
||||
sectionModel.DisplayOrder = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sectionModel;
|
||||
}
|
||||
|
||||
public async Task<LessonModel> PrepareLessonModelAsync(LessonModel lessonModel, Section section, Course course, Lesson lesson)
|
||||
{
|
||||
if (lessonModel == null)
|
||||
throw new ArgumentNullException(nameof(lessonModel));
|
||||
|
||||
if (course == null)
|
||||
throw new ArgumentNullException(nameof(course));
|
||||
|
||||
if (section == null)
|
||||
throw new ArgumentNullException(nameof(section));
|
||||
|
||||
if (lesson != null)
|
||||
{
|
||||
lessonModel = lesson.ToModel<LessonModel>();
|
||||
|
||||
if (lessonModel.LessonType == LessonType.Video)
|
||||
{
|
||||
var video = await _courseService.GetVideoByLessonIdAsync(lessonModel.Id);
|
||||
lessonModel.VideoIdFromProvider = video.VideoIdFromProvider;
|
||||
lessonModel.VideoType = video.VideoType;
|
||||
lessonModel.Duration = video.Duration;
|
||||
}
|
||||
}
|
||||
|
||||
var sls = await _courseService.GetSectionLessonsBySectionIdAsync(section.Id);
|
||||
if (sls != null && sls.Count > 0)
|
||||
{
|
||||
if (lesson != null)
|
||||
{
|
||||
lessonModel.DisplayOrder = sls.Where(p => p.LessonId == lesson.Id).SingleOrDefault().DisplayOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
lessonModel.DisplayOrder = sls.Max(p => p.DisplayOrder) + 1;
|
||||
if (lessonModel.DisplayOrder == 0)
|
||||
{
|
||||
lessonModel.DisplayOrder = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lessonModel.DisplayOrder == 0)
|
||||
{
|
||||
lessonModel.DisplayOrder = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
lessonModel.SectionId = section.Id;
|
||||
lessonModel.CourseId = course.Id;
|
||||
|
||||
|
||||
lessonModel.AvailableLessonTypes.Add(new SelectListItem { Value = ((int)LessonType.Video).ToString(), Text = LessonType.Video.ToString() });
|
||||
lessonModel.AvailableLessonTypes.Add(new SelectListItem { Value = ((int)LessonType.Text).ToString(), Text = LessonType.Text.ToString() });
|
||||
//lessonModel.AvailableLessonTypes.Add(new SelectListItem { Value = ((int)LessonType.Document).ToString(), Text = LessonType.Document.ToString() });
|
||||
|
||||
|
||||
lessonModel.AvailableVideoTypes.Add(new SelectListItem { Value = ((int)VideoType.Youtube).ToString(), Text = VideoType.Youtube.ToString() });
|
||||
lessonModel.AvailableVideoTypes.Add(new SelectListItem { Value = ((int)VideoType.Vimeo).ToString(), Text = VideoType.Vimeo.ToString() });
|
||||
//lessonModel.AvailableVideoTypes.Add(new SelectListItem { Value = ((int)VideoType.VdoCipher).ToString(), Text = VideoType.VdoCipher.ToString() });
|
||||
//lessonModel.AvailableVideoTypes.Add(new SelectListItem { Value = ((int)VideoType.Hosted).ToString(), Text = VideoType.Hosted.ToString() });
|
||||
//lessonModel.AvailableVideoTypes.Add(new SelectListItem { Value = ((int)VideoType.AWS).ToString(), Text = VideoType.AWS.ToString() });
|
||||
|
||||
lessonModel.AvailableAttachmentTypes.Add(new SelectListItem { Value = ((int)AttachmentType.Pdf).ToString(), Text = AttachmentType.Pdf.ToString() });
|
||||
//lessonModel.AvailableAttachmentTypes.Add(new SelectListItem { Value = ((int)AttachmentType.Others).ToString(), Text = AttachmentType.Others.ToString() });
|
||||
|
||||
return lessonModel;
|
||||
}
|
||||
|
||||
public async Task<SortableEntity> PrepareSortableEntityModelAsync(SortableEntity sortableEntity, IEnumerable<IDisplayOrderRecord> models, SortRecordType sortRecordType, int parentId)
|
||||
{
|
||||
if (sortableEntity == null)
|
||||
throw new ArgumentNullException(nameof(sortableEntity));
|
||||
|
||||
sortableEntity.ParentId = parentId;
|
||||
sortableEntity.SortRecords = await (from p in models
|
||||
orderby p.DisplayOrder
|
||||
select new SortRecord
|
||||
{
|
||||
Id = p.Id,
|
||||
ExistingSortOrder = p.DisplayOrder,
|
||||
NewSortOrder = p.DisplayOrder,
|
||||
DisplayText = p.DisplayText
|
||||
}).ToListAsync();
|
||||
|
||||
sortableEntity.SortRecordType = sortRecordType;
|
||||
|
||||
return sortableEntity;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record AttachmentModel : BaseNopEntityModel
|
||||
{
|
||||
public AttachmentModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.AttachmentType")]
|
||||
public AttachmentType AttachmentType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VirtualPath")]
|
||||
public string VirtualPath { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public record ConfigurationModel : BaseNopModel
|
||||
{
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.YouTubeApiKey.Text")]
|
||||
public string YouTubeApiKey { get; set; }
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.VimeoAppId.Text")]
|
||||
public string VimeoAppId { get; set; }
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.VimeoClient.Text")]
|
||||
public string VimeoClient { get; set; }
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.VimeoSecret.Text")]
|
||||
public string VimeoSecret { get; set; }
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.VimeoAccess.Text")]
|
||||
public string VimeoAccess { get; set; }
|
||||
[NopResourceDisplayName("Plugins.SimpleLMS.Configuration.VdoCipherKey.Text")]
|
||||
public string VdoCipherKey { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Web.Framework.Models;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record CourseListModel : BasePagedListModel<CourseModel>
|
||||
{
|
||||
public CourseListModel()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
using FluentValidation.Validators;
|
||||
using FluentValidation;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record CourseModel : BaseNopEntityModel
|
||||
{
|
||||
public CourseModel()
|
||||
{
|
||||
Sections = new List<SectionModel>();
|
||||
AvailableProducts = new List<SelectListItem>();
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.ProductName")]
|
||||
public string ParentProductName { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.ProductName")]
|
||||
public int ProductId { get; set; }
|
||||
public IList<SelectListItem> AvailableProducts { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Instructor")]
|
||||
public string Instructor { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Instructor")]
|
||||
public string Category { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Sections")]
|
||||
public int SectionsTotal { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Lessons")]
|
||||
public int LessonsTotal { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.EnrolledStudents")]
|
||||
public int EnrolledStudents { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Status")]
|
||||
public string Status { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Price")]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.CreatedOn")]
|
||||
public DateTime CreatedOnUtc { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.UpdatedOn")]
|
||||
public DateTime UpdatedOnUtc { get; set; }
|
||||
|
||||
public IList<SectionModel> Sections { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record CourseSearchModel : BaseSearchModel
|
||||
{
|
||||
public CourseSearchModel()
|
||||
{
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.SearchCourseName")]
|
||||
public string SearchCourseName { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.InstructorGUID")]
|
||||
public string InstructorGUID { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record LessonModel : BaseNopEntityModel
|
||||
{
|
||||
public LessonModel()
|
||||
{
|
||||
//Video = new VideoModel();
|
||||
Attachments = new List<AttachmentModel>();
|
||||
AvailableLessonTypes = new List<SelectListItem>();
|
||||
AvailableVideoTypes = new List<SelectListItem>();
|
||||
AvailableAttachmentTypes = new List<SelectListItem>();
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.LessonType")]
|
||||
public LessonType LessonType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.LessonContents")]
|
||||
public string LessonContents { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.DisplayOrder")]
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Instructor")]
|
||||
public int InstructorName { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.IsFree")]
|
||||
public bool IsFreeLesson { get; set; }
|
||||
|
||||
public VideoModel Video { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.SectionName")]
|
||||
public int SectionId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.CourseName")]
|
||||
public int CourseId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoType")]
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoIdFromProvider")]
|
||||
public string VideoIdFromProvider { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Duration")]
|
||||
public int Duration { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoUrl")]
|
||||
public string VideoUrl { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoEmbedCode")]
|
||||
public string VideoEmbedCode { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.AttachmentType")]
|
||||
public AttachmentType AttachmentType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Attachments")]
|
||||
public IList<AttachmentModel> Attachments { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.LessonType")]
|
||||
public IList<SelectListItem> AvailableLessonTypes { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoType")]
|
||||
public IList<SelectListItem> AvailableVideoTypes { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.AttachmentType")]
|
||||
public IList<SelectListItem> AvailableAttachmentTypes { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record SectionModel : BaseNopEntityModel
|
||||
{
|
||||
public SectionModel()
|
||||
{
|
||||
Lessons = new List<LessonModel>();
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.DisplayOrder")]
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.CourseName")]
|
||||
public string CourseName { get; set; }
|
||||
|
||||
public int CourseId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.IsFree")]
|
||||
public bool IsFree { get; set; }
|
||||
|
||||
public IList<LessonModel> Lessons { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using Nop.Web.Framework.Models;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record SortRecord : BaseNopEntityModel
|
||||
{
|
||||
public SortRecord()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public int ExistingSortOrder { get; set; }
|
||||
public int NewSortOrder { get; set; }
|
||||
public string DisplayText { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record SortableEntity
|
||||
{
|
||||
public int ParentId { get; set; }
|
||||
|
||||
public SortRecordType SortRecordType { get; set; }
|
||||
|
||||
public IList<SortRecord> SortRecords { get; set; }
|
||||
|
||||
public List<string> NewSortOrderValues { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models
|
||||
{
|
||||
public partial record VideoModel : BaseNopEntityModel
|
||||
{
|
||||
public VideoModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoType")]
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoIdFromProvider")]
|
||||
public string VideoIdFromProvider { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Duration")]
|
||||
public int Duration { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoUrl")]
|
||||
public string VideoUrl { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoEmbedCode")]
|
||||
public string VideoEmbedCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Nop.Data;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Validators;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators
|
||||
{
|
||||
public partial class AttachmentValidator : BaseNopValidator<AttachmentModel>
|
||||
{
|
||||
public AttachmentValidator(ILocalizationService localizationService, INopDataProvider dataProvider)
|
||||
{
|
||||
RuleFor(x => x.AttachmentType).NotNull();
|
||||
RuleFor(x => x.Name).NotNull();
|
||||
RuleFor(x => x.VirtualPath).NotNull();
|
||||
|
||||
SetDatabaseValidationRules<Attachment>(dataProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Nop.Data;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Validators;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators
|
||||
{
|
||||
public partial class CourseValidator : BaseNopValidator<CourseModel>
|
||||
{
|
||||
public CourseValidator(ILocalizationService localizationService, INopDataProvider dataProvider)
|
||||
{
|
||||
RuleFor(x => x.Name).NotNull();
|
||||
RuleFor(x => x.ProductId).NotNull().GreaterThan(0);
|
||||
SetDatabaseValidationRules<Course>(dataProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Nop.Data;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Validators;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators
|
||||
{
|
||||
public partial class LessonValidator : BaseNopValidator<LessonModel>
|
||||
{
|
||||
public LessonValidator(ILocalizationService localizationService, INopDataProvider dataProvider)
|
||||
{
|
||||
RuleFor(x => x.DisplayOrder).NotNull().GreaterThan(0);
|
||||
RuleFor(x => x.Name).NotEmpty();
|
||||
RuleFor(x => x.LessonType).NotEmpty();
|
||||
|
||||
RuleFor(x => x.AttachmentType).NotEmpty().When(x => x.LessonType == LessonType.Document);
|
||||
RuleFor(x => x.Attachments).Must(coll => coll.Any()).When(x => x.LessonType == LessonType.Document);
|
||||
|
||||
RuleFor(x => x.CourseId).NotNull().GreaterThan(0);
|
||||
|
||||
RuleFor(x => x.Duration).NotNull().When(x => x.LessonType == LessonType.Video)
|
||||
.GreaterThan(0).When(x => x.LessonType == LessonType.Video);
|
||||
|
||||
RuleFor(x => x.IsFreeLesson).NotNull();
|
||||
RuleFor(x => x.LessonContents).Length(1, 4000).When(x => x.LessonType == LessonType.Text);
|
||||
RuleFor(x => x.SectionId).NotNull();
|
||||
RuleFor(x => x.VideoIdFromProvider).NotEmpty().When(x => x.LessonType == LessonType.Video);
|
||||
|
||||
RuleFor(x => x.VideoType).NotEmpty().When(x => x.LessonType == LessonType.Video);
|
||||
|
||||
SetDatabaseValidationRules<Lesson>(dataProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Nop.Data;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Validators;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators
|
||||
{
|
||||
public partial class SectionValidator : BaseNopValidator<SectionModel>
|
||||
{
|
||||
public SectionValidator(ILocalizationService localizationService, INopDataProvider dataProvider)
|
||||
{
|
||||
RuleFor(x => x.Title).NotNull();
|
||||
RuleFor(x => x.DisplayOrder).NotNull();
|
||||
RuleFor(x => x.CourseId).NotNull();
|
||||
|
||||
SetDatabaseValidationRules<Section>(dataProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Nop.Data;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Validators;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators
|
||||
{
|
||||
public partial class VideoValidator : BaseNopValidator<VideoModel>
|
||||
{
|
||||
public VideoValidator(ILocalizationService localizationService, INopDataProvider dataProvider)
|
||||
{
|
||||
RuleFor(x => x.Duration).NotNull();
|
||||
RuleFor(x => x.VideoType).NotNull();
|
||||
|
||||
|
||||
RuleFor(m => m.VideoUrl).NotEmpty().When(m => string.IsNullOrEmpty(m.VideoIdFromProvider) && string.IsNullOrEmpty(m.VideoEmbedCode));
|
||||
RuleFor(m => m.VideoIdFromProvider).NotEmpty().When(m => string.IsNullOrEmpty(m.VideoUrl) && string.IsNullOrEmpty(m.VideoEmbedCode));
|
||||
RuleFor(m => m.VideoEmbedCode).NotEmpty().When(m => string.IsNullOrEmpty(m.VideoIdFromProvider) && string.IsNullOrEmpty(m.VideoUrl));
|
||||
|
||||
SetDatabaseValidationRules<Video>(dataProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Nop.Web.Framework.Components;
|
||||
using System;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Components
|
||||
{
|
||||
[ViewComponent(Name = "Custom")]
|
||||
public class CustomViewComponent : NopViewComponent
|
||||
{
|
||||
public CustomViewComponent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IViewComponentResult Invoke(int productId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 673 B |
|
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 989 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 208 B After Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,151 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Nop.Core;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Services;
|
||||
using Nop.Services.Catalog;
|
||||
using Nop.Services.Configuration;
|
||||
using Nop.Services.Customers;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Services.Logging;
|
||||
using Nop.Services.Security;
|
||||
using Nop.Web.Framework.Controllers;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Controllers
|
||||
{
|
||||
public partial class CustomerController : BaseController
|
||||
{
|
||||
private readonly CourseService _courseService;
|
||||
private readonly ISettingService _settingService;
|
||||
private readonly IWorkContext _workContext;
|
||||
private readonly IStoreContext _storeContext;
|
||||
private readonly IPermissionService _permissionService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly ICustomerService _customerService;
|
||||
private readonly CourseModelFactory _courseModelFactory;
|
||||
|
||||
|
||||
public CustomerController(IAclService aclService, IProductService productService, ISettingService settingService
|
||||
, IWorkContext workContext, IStoreContext storeContext
|
||||
, IPermissionService permissionService, ILanguageService languageService
|
||||
, ILocalizationService localizationService, ICustomerActivityService customerActivityService, ICustomerService customerService
|
||||
, CourseModelFactory courseModelFactory
|
||||
, CourseService courseService) : base()
|
||||
{
|
||||
_settingService = settingService;
|
||||
_workContext = workContext;
|
||||
_storeContext = storeContext;
|
||||
_permissionService = permissionService;
|
||||
_localizationService = localizationService;
|
||||
_customerService = customerService;
|
||||
_courseModelFactory = courseModelFactory;
|
||||
_courseService = courseService;
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> Courses()
|
||||
{
|
||||
if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
|
||||
return Challenge();
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
//prepare model
|
||||
var model = await _courseModelFactory.PrepareCourseSearchModelAsync(new CourseSearchModel());
|
||||
|
||||
return View("~/Plugins/Misc.SimpleLMS/Views/Customer/List.cshtml", model);
|
||||
}
|
||||
|
||||
|
||||
//public virtual async Task<I>
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public virtual async Task<IActionResult> CourseOverviewList([FromBody]CourseSearchModel searchModel)
|
||||
{
|
||||
if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
|
||||
return Challenge();
|
||||
|
||||
|
||||
//prepare model
|
||||
var model = await _courseModelFactory.PrepareCourseOverviewListModelAsync(searchModel);
|
||||
|
||||
return PartialView("~/Plugins/Misc.SimpleLMS/Views/Customer/_MyCourseList.cshtml", model);
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> CoursesDetails(int courseId)
|
||||
{
|
||||
if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
|
||||
return Challenge();
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (_courseService.IsUserCourse(courseId, customer.Id))
|
||||
{
|
||||
var courseExisting = await _courseService.GetCourseByProductIdAsync(courseId);
|
||||
var lessonProgresses = await _courseService.GetCourseProgressByUserId(courseId, customer.Id);
|
||||
var model = await _courseModelFactory.PrepareCourseDetailModelAsync(new CourseDetail(), courseExisting, lessonProgresses);
|
||||
return View("~/Plugins/Misc.SimpleLMS/Views/Customer/CoursesDetails.cshtml", model);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public virtual async Task<IActionResult> LessonContent(int lessonId, int courseId)
|
||||
{
|
||||
if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
|
||||
return Challenge();
|
||||
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (_courseService.IsUserCourse(courseId, customer.Id))
|
||||
{
|
||||
var lessonExisting = await _courseService.GetLessonByCourseIdAndLessonIdAsync(courseId, lessonId);
|
||||
var model = await _courseModelFactory.PrepareLessonModelAsync(new LessonDetail(), lessonExisting);
|
||||
|
||||
var storeScope = await _storeContext.GetActiveStoreScopeConfigurationAsync();
|
||||
var simpleLMSSettings = await _settingService.LoadSettingAsync<SimpleLMSSettings>(storeScope);
|
||||
ViewData["simpleLMSSettings"] = simpleLMSSettings;
|
||||
|
||||
|
||||
return View("~/Plugins/Misc.SimpleLMS/Views/Customer/_LessonContent.cshtml", model);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IActionResult> UpdateLessonStatus(LessonStatusModel lessonStatus)
|
||||
{
|
||||
if (!await _customerService.IsRegisteredAsync(await _workContext.GetCurrentCustomerAsync()))
|
||||
return Challenge();
|
||||
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
if (_courseService.IsUserCourse(lessonStatus.CourseId, customer.Id)
|
||||
&& _courseService.ValidateCourseSectionLessonCombination(lessonStatus.LessonId, lessonStatus.SectionId, lessonStatus.CourseId))
|
||||
{
|
||||
|
||||
await _courseService.InsertOrUpdateLessonProgressByCourseLessonAndUser(lessonStatus.CourseId, customer.Id, lessonStatus.LessonId, lessonStatus.IsCompleted, lessonStatus.CurrentlyAt);
|
||||
|
||||
|
||||
|
||||
return Json(new { success = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
success = false,
|
||||
responseText = await _localizationService.GetResourceAsync("SimpleLMS.InvalidData")
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class Attachment : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int AtttachmentTypeId { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string VirtualPath { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
|
||||
public int InstructorId { get; set; }
|
||||
|
||||
public Guid InstructorGuid { get; set; }
|
||||
|
||||
public AttachmentType AttachmentType
|
||||
{
|
||||
get => (AttachmentType)AtttachmentTypeId;
|
||||
set => AtttachmentTypeId = (int)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public enum AttachmentType
|
||||
{
|
||||
WordDoc = 10,
|
||||
Pdf = 20,
|
||||
Ppt = 30,
|
||||
Image = 100,
|
||||
Others = 110
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Common;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Security;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents Course
|
||||
/// </summary>
|
||||
public partial class Course : BaseEntity, ILocalizedEntity, IStoreMappingSupported, ISoftDeletedEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets associated product id
|
||||
/// </summary>
|
||||
public int ProductId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets course name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets LimitedToStores
|
||||
/// </summary>
|
||||
public bool LimitedToStores { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Deleted
|
||||
/// </summary>
|
||||
public bool Deleted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instructor Id
|
||||
/// </summary>
|
||||
public int InstructorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instructor Guid
|
||||
/// </summary>
|
||||
public Guid InstructorGuid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time of product creation
|
||||
/// </summary>
|
||||
public DateTime CreatedOnUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the date and time of product update
|
||||
/// </summary>
|
||||
public DateTime UpdatedOnUtc { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using Nop.Core;
|
||||
using Nop.Core.Domain.Common;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class CourseProgress : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int CourseId { get; set; }
|
||||
|
||||
public int StudentId { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Core;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public class CourseStat : BaseEntity
|
||||
{
|
||||
public int EnrolledStudents { get; set; }
|
||||
public int Sections { get; set; }
|
||||
public int Lessons { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using Nop.Core;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class CustomTable : BaseEntity
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial interface IDisplayOrderRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int DisplayOrder { get; set; }
|
||||
public string DisplayText { get; set; }
|
||||
}
|
||||
|
||||
public partial class DisplayOrderRecord : IDisplayOrderRecord
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int DisplayOrder { get; set; }
|
||||
public string DisplayText { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Common;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class Lesson : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int LessonTypeId { get; set; }
|
||||
|
||||
public string LessonContents { get; set; }
|
||||
|
||||
public int? VideoId { get; set; }
|
||||
|
||||
public int? DocumentId { get; set; }
|
||||
|
||||
public int? PictureId { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
|
||||
public int InstructorId { get; set; }
|
||||
|
||||
public Guid InstructorGuid { get; set; }
|
||||
|
||||
//public int ExamId { get; set; }
|
||||
|
||||
public bool IsFreeLesson { get; set; }
|
||||
|
||||
public LessonType LessonType
|
||||
{
|
||||
get => (LessonType)LessonTypeId;
|
||||
set => LessonTypeId = (int)value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class LessonAttachment : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int LessonId { get; set; }
|
||||
|
||||
public int AttachmentId { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using Nop.Core;
|
||||
using Nop.Core.Domain.Common;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class LessonProgress : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int CourseProgressId { get; set; }
|
||||
|
||||
public int LessonId { get; set; }
|
||||
|
||||
public bool IsCompleted { get; set; }
|
||||
|
||||
public int CurrentlyAt { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public enum LessonType
|
||||
{
|
||||
Text = 10,
|
||||
Image = 20,
|
||||
Document = 30,
|
||||
Video = 40,
|
||||
Questionire = 50,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using Nop.Core;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class Section : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int CourseId { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
public bool IsFree { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using Nop.Core;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public class SectionLesson : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int CourseId { get; set; }
|
||||
|
||||
public int SectionId { get; set; }
|
||||
|
||||
public int LessonId { get; set; }
|
||||
|
||||
public bool IsFreeLesson { get; set; }
|
||||
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public enum SortRecordType
|
||||
{
|
||||
Section = 1,
|
||||
Lesson =2
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using Nop.Core;
|
||||
using Nop.Core.Domain.Localization;
|
||||
using Nop.Core.Domain.Stores;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public partial class Video : BaseEntity, ILocalizedEntity, IStoreMappingSupported
|
||||
{
|
||||
public int VideoTypeId { get; set; }
|
||||
|
||||
public string VideoIdFromProvider { get; set; }
|
||||
|
||||
public string VideoUrl { get; set; }
|
||||
|
||||
public int Duration { get; set; }
|
||||
|
||||
public string VideoEmbedCode { get; set; }
|
||||
|
||||
public bool LimitedToStores { get; set; }
|
||||
|
||||
public int InstructorId { get; set; }
|
||||
|
||||
public Guid InstructorGuid { get; set; }
|
||||
|
||||
public VideoType VideoType
|
||||
{
|
||||
get => (VideoType)VideoTypeId;
|
||||
set => VideoTypeId = (int)value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Domains
|
||||
{
|
||||
public enum VideoType
|
||||
{
|
||||
Hosted = 10,
|
||||
Youtube = 20,
|
||||
VdoCipher = 30,
|
||||
Vimeo = 40,
|
||||
AWS = 50
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Services.Events;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Web.Framework.Events;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Models.Customer;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Events
|
||||
{
|
||||
public class EventConsumer : IConsumer<ModelPreparedEvent<BaseNopModel>>
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
public EventConsumer(ILocalizationService localizationService)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
}
|
||||
|
||||
public async Task HandleEventAsync(ModelPreparedEvent<BaseNopModel> eventMessage)
|
||||
{
|
||||
if (eventMessage.Model is not CustomerNavigationModel navigationModel)
|
||||
return;
|
||||
|
||||
navigationModel.CustomerNavigationItems.Insert(0, new CustomerNavigationItemModel
|
||||
{
|
||||
RouteName = SimpleLMSDefaults.CustomerMyCoursers,
|
||||
ItemClass = "my-courses",
|
||||
Tab = SimpleLMSDefaults.CustomerMyCoursesMenuTab,
|
||||
Title = await _localizationService.GetResourceAsync("SimpleLMS.MyCourses")
|
||||
|
||||
}); ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Nop.Core;
|
||||
using Nop.Services.Catalog;
|
||||
using Nop.Services.Customers;
|
||||
using Nop.Services.Localization;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Services;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Models;
|
||||
using Nop.Web.Framework.Models.Extensions;
|
||||
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
|
||||
using Nop.Services.Media;
|
||||
using Nop.Core.Domain.Customers;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS
|
||||
{
|
||||
public partial class CourseModelFactory
|
||||
{
|
||||
private readonly CourseService _courseService;
|
||||
private readonly ICustomerService _customerService;
|
||||
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IProductService _productService;
|
||||
private readonly IWorkContext _workContext;
|
||||
|
||||
private readonly IPictureService _pictureService;
|
||||
|
||||
|
||||
public CourseModelFactory(
|
||||
CourseService courseService,
|
||||
ICustomerService customerService,
|
||||
ILocalizationService localizationService,
|
||||
IProductService productService,
|
||||
IWorkContext workContext,
|
||||
IPictureService pictureService)
|
||||
{
|
||||
|
||||
_courseService = courseService;
|
||||
_customerService = customerService;
|
||||
_localizationService = localizationService;
|
||||
_productService = productService;
|
||||
_workContext = workContext;
|
||||
_pictureService = pictureService;
|
||||
}
|
||||
|
||||
public async Task<CourseSearchModel> PrepareCourseSearchModelAsync(CourseSearchModel searchModel)
|
||||
{
|
||||
if (searchModel == null)
|
||||
throw new ArgumentNullException(nameof(searchModel));
|
||||
|
||||
searchModel.CourseOverviewList = await PrepareCourseOverviewListModelAsync(searchModel);
|
||||
|
||||
searchModel.SetGridPageSize();
|
||||
|
||||
return searchModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<CourseOverviewListModel> PrepareCourseOverviewListModelAsync(CourseSearchModel searchModel)
|
||||
{
|
||||
if (searchModel == null)
|
||||
throw new ArgumentNullException(nameof(searchModel));
|
||||
|
||||
var customer = await _workContext.GetCurrentCustomerAsync();
|
||||
|
||||
|
||||
var courses = await _courseService.SearchCoursesAsync(pageIndex: searchModel.PageNumber - 1,
|
||||
pageSize: searchModel.PageSize > 0 ? searchModel.PageSize : 10,
|
||||
keyword: searchModel.SearchCourseName,
|
||||
userId: customer.Id);
|
||||
|
||||
|
||||
var model = new CourseOverviewListModel();
|
||||
|
||||
|
||||
model.Courses = (await PrepareCourseOverviewModelsAsyns(courses, customer)).ToList();
|
||||
model.LoadPagedList(courses);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private async Task<IList<CourseOverviewModel>> PrepareCourseOverviewModelsAsyns(IPagedList<Course> courses, Customer customer)
|
||||
{
|
||||
if (courses == null)
|
||||
throw new ArgumentNullException(nameof(courses));
|
||||
|
||||
|
||||
var models = new List<CourseOverviewModel>();
|
||||
foreach (var course in courses)
|
||||
{
|
||||
|
||||
var model = course.ToModel<CourseOverviewModel>();
|
||||
|
||||
var product = await _productService.GetProductByIdAsync(course.ProductId);
|
||||
model.ParentProductName = product.Name;
|
||||
|
||||
model.CourseProgress = await _courseService.GetCourseProgressPercentByUserId(course.Id, customer.Id);
|
||||
var pictures = await _pictureService.GetPicturesByProductIdAsync(product.Id);
|
||||
|
||||
|
||||
if (pictures != null && pictures.Count() > 0)
|
||||
model.ProductMainImage = (await _pictureService.GetPictureUrlAsync(pictures[0])).Url;
|
||||
|
||||
|
||||
models.Add(model);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
|
||||
public async Task<CourseDetail> PrepareCourseDetailModelAsync(CourseDetail courseDetail, Course course, IList<LessonProgress> lessonProgresses)
|
||||
{
|
||||
|
||||
if (courseDetail == null)
|
||||
throw new ArgumentNullException(nameof(courseDetail));
|
||||
|
||||
if (course != null)
|
||||
{
|
||||
//fill in model values from the entity
|
||||
if (course != null)
|
||||
{
|
||||
courseDetail = course.ToModel<CourseDetail>();
|
||||
}
|
||||
|
||||
var parentProduct = await _productService.GetProductByIdAsync(course.ProductId);
|
||||
|
||||
if (parentProduct != null)
|
||||
{
|
||||
courseDetail.ParentProductName = parentProduct.Name;
|
||||
courseDetail.ProductId = parentProduct.Id;
|
||||
}
|
||||
|
||||
courseDetail.Sections = (await _courseService.GetSectionsByCourseIdAsync(courseDetail.Id)).OrderBy(p => p.DisplayOrder).Select(p =>
|
||||
new SectionDetail
|
||||
{
|
||||
CourseName = courseDetail.Name,
|
||||
DisplayOrder = p.DisplayOrder,
|
||||
Id = p.Id,
|
||||
IsFree = p.IsFree,
|
||||
Title = p.Title,
|
||||
CourseId = course.Id,
|
||||
Lessons = _courseService.GetLessonsBySectionIdAsync(p.Id)
|
||||
.GetAwaiter().GetResult().Select(l => l.ToModel<LessonDetail>()).ToList()
|
||||
}).ToList();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < courseDetail.Sections.Count; i++)
|
||||
{
|
||||
var sectionLessons = await _courseService.GetSectionLessonsBySectionIdAsync(courseDetail.Sections[i].Id);
|
||||
|
||||
|
||||
for (int j = 0; j < courseDetail.Sections[i].Lessons.Count; j++)
|
||||
{
|
||||
courseDetail.Sections[i].Lessons[j].SectionId = courseDetail.Sections[i].Id;
|
||||
courseDetail.Sections[i].Lessons[j].CourseId = courseDetail.Id;
|
||||
courseDetail.Sections[i].Lessons[j].DisplayOrder
|
||||
= sectionLessons.Where(p => p.LessonId == courseDetail.Sections[i].Lessons[j].Id).SingleOrDefault().DisplayOrder;
|
||||
courseDetail.Sections[i].Lessons[j].Duration = courseDetail.Sections[i].Lessons[j].LessonType == LessonType.Video ?
|
||||
_courseService.GetVideoByLessonIdAsync(courseDetail.Sections[i].Lessons[j].Id).GetAwaiter().GetResult().Duration : 0;
|
||||
|
||||
var lessonProgress = lessonProgresses.Where(p => p.LessonId == courseDetail.Sections[i].Lessons[j].Id).SingleOrDefault();
|
||||
|
||||
courseDetail.Sections[i].Lessons[j].IsCompleted = (lessonProgress != null ? lessonProgress.IsCompleted : false);
|
||||
|
||||
if (courseDetail.Sections[i].Lessons[j].Video != null && lessonProgress.CurrentlyAt > 0)
|
||||
{
|
||||
courseDetail.Sections[i].Lessons[j].Video.TimeCode =
|
||||
(courseDetail.Sections[i].Lessons[j].Video.VideoType == VideoType.Vimeo ?
|
||||
lessonProgress.CurrentlyAt / 60 + "m" + (lessonProgress.CurrentlyAt % 60) + "s" : lessonProgress.CurrentlyAt.ToString());
|
||||
}
|
||||
|
||||
if (courseDetail.CurrentLesson == 0 && !courseDetail.Sections[i].Lessons[j].IsCompleted)
|
||||
{
|
||||
courseDetail.CurrentLesson = courseDetail.Sections[i].Lessons[j].Id;
|
||||
courseDetail.CurrentSection = courseDetail.Sections[i].Id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
courseDetail.Sections[i].Lessons = courseDetail.Sections[i].Lessons.OrderBy(p => p.DisplayOrder).ToList();
|
||||
}
|
||||
|
||||
if (courseDetail.CurrentLesson == 0)
|
||||
{
|
||||
var currSection = (from p in courseDetail.Sections
|
||||
where p.Lessons.Count > 0
|
||||
select p).FirstOrDefault();
|
||||
if (currSection != null)
|
||||
{
|
||||
courseDetail.CurrentLesson = currSection.Lessons.FirstOrDefault().Id;
|
||||
courseDetail.CurrentSection = currSection.Id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return courseDetail;
|
||||
}
|
||||
|
||||
public async Task<LessonDetail> PrepareLessonModelAsync(LessonDetail lessonDetail, Lesson lesson)
|
||||
{
|
||||
if (lessonDetail == null)
|
||||
throw new ArgumentNullException(nameof(lessonDetail));
|
||||
|
||||
|
||||
if (lesson != null)
|
||||
{
|
||||
lessonDetail = lesson.ToModel<LessonDetail>();
|
||||
if (lesson.LessonType == LessonType.Video)
|
||||
{
|
||||
lessonDetail.Video = (await _courseService.GetVideoByLessonIdAsync(lessonDetail.Id)).ToModel<VideoDetail>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return lessonDetail;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using FluentValidation;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Nop.Core.Infrastructure;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Factories;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Validators;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Services;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Infrastructure
|
||||
{
|
||||
public class NopStartup : INopStartup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.Configure<RazorViewEngineOptions>(options =>
|
||||
{
|
||||
options.ViewLocationExpanders.Add(new ViewLocationExpander());
|
||||
});
|
||||
|
||||
services.AddTransient<IValidator<CourseModel>, CourseValidator>();
|
||||
services.AddTransient<IValidator<AttachmentModel>, AttachmentValidator>();
|
||||
services.AddTransient<IValidator<LessonModel>, LessonValidator>();
|
||||
services.AddTransient<IValidator<SectionModel>, SectionValidator>();
|
||||
services.AddTransient<IValidator<VideoModel>, VideoValidator>();
|
||||
|
||||
|
||||
services.AddScoped<CourseService>();
|
||||
services.AddScoped<CourseModelFactory>();
|
||||
services.AddScoped<AdminCourseModelFactory>();
|
||||
|
||||
//services.AddScoped<CustomModelFactory, ICustomerModelFactory>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder application)
|
||||
{
|
||||
}
|
||||
|
||||
public int Order => 10000;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Nop.Web.Framework.Mvc.Routing;
|
||||
using Nop.Web.Infrastructure;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Infrastructure
|
||||
{
|
||||
public partial class RouteProvider : BaseRouteProvider, IRouteProvider
|
||||
{
|
||||
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
|
||||
{
|
||||
var lang = GetLanguageRoutePattern();
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.AdminCourseListRoute,
|
||||
pattern: $"{lang}/Admin/Course/List",
|
||||
defaults: new { controller = "CourseController", action = "Index", area = "Admin" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.AdminCourseListJsonRoute,
|
||||
pattern: $"{lang}/Admin/Course/CourseList",
|
||||
defaults: new { controller = "CourseController", action = "CourseList", area = "Admin" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.AdminCourseCreateSectionRoute,
|
||||
pattern: $"{lang}/Admin/Course/CreateSection",
|
||||
defaults: new { controller = "CourseController", action = "CreateSection", area = "Admin" });
|
||||
|
||||
|
||||
//customer account links
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.CustomerMyCoursers,
|
||||
pattern: $"{lang}/customer/mycourses",
|
||||
defaults: new { controller = "Customer", action = "Courses" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.CustomerMyCoursers,
|
||||
pattern: $"{lang}/customer/searchmycourses",
|
||||
defaults: new { controller = "Customer", action = "CourseOverviewList" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.CustomerCoursesDetails,
|
||||
pattern: $"{lang}/coursesdetail/{{productid:min(0)}}",
|
||||
defaults: new { controller = "Customer", action = "CoursesDetails" });
|
||||
|
||||
endpointRouteBuilder.MapControllerRoute(name: SimpleLMSDefaults.CustomerLessonVideo,
|
||||
pattern: $"{lang}/videocontent/{{lessionId:min(0)}}",
|
||||
defaults: new { controller = "Customer", action = "VideoContent" });
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int Priority => 999;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Nop.Core.Infrastructure.Mapper;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Models;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Infrastructure
|
||||
{
|
||||
public class SimpleLMSMapperConfiguration : Profile, IOrderedMapperProfile
|
||||
{
|
||||
public SimpleLMSMapperConfiguration()
|
||||
{
|
||||
CreateMaps();
|
||||
}
|
||||
|
||||
private void CreateMaps()
|
||||
{
|
||||
CreateMap<Course, CourseModel>();
|
||||
CreateMap<Attachment, AttachmentModel>();
|
||||
CreateMap<Lesson, LessonModel>();
|
||||
CreateMap<Section, SectionModel>();
|
||||
CreateMap<Video, VideoModel>();
|
||||
|
||||
CreateMap<CourseModel, Course>();
|
||||
CreateMap<AttachmentModel, Attachment>();
|
||||
CreateMap<LessonModel, Lesson>();
|
||||
CreateMap<SectionModel, Section>();
|
||||
CreateMap<VideoModel, Video>();
|
||||
|
||||
CreateMap<CourseOverviewModel, Course>();
|
||||
CreateMap<Course, CourseOverviewModel>();
|
||||
|
||||
CreateMap<Course, CourseDetail>();
|
||||
CreateMap<CourseDetail, Course>();
|
||||
|
||||
CreateMap<SectionDetail, Section>();
|
||||
CreateMap<Section, SectionDetail>();
|
||||
|
||||
|
||||
CreateMap<LessonDetail, Lesson>();
|
||||
CreateMap<Lesson, LessonDetail>();
|
||||
|
||||
CreateMap<VideoDetail, Video>();
|
||||
CreateMap<Video, VideoDetail>();
|
||||
|
||||
}
|
||||
|
||||
public int Order => 99;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Core.Domain.Catalog;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Core.Domain.Customers;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Data.Mapping.Builders
|
||||
{
|
||||
public class AtttachmentBuilder : NopEntityBuilder<Attachment>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(Attachment.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(Attachment.AtttachmentTypeId))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(Attachment.Name))
|
||||
.AsString(500).NotNullable()
|
||||
.WithColumn(nameof(Attachment.VirtualPath))
|
||||
.AsString().NotNullable()
|
||||
.WithColumn(nameof(Attachment.InstructorId))
|
||||
.AsInt32().NotNullable().ForeignKey<Customer>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Attachment.InstructorGuid))
|
||||
.AsGuid().NotNullable()
|
||||
.WithColumn(nameof(Attachment.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Core.Domain.Catalog;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Core.Domain.Customers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Data.Mapping.Builders
|
||||
{
|
||||
public class CourseBuilder : NopEntityBuilder<Course>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(Course.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(Course.ProductId))
|
||||
.AsInt32().NotNullable().ForeignKey<Product>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Course.Name))
|
||||
.AsString(500).NotNullable()
|
||||
.WithColumn(nameof(Course.LimitedToStores))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(Course.Deleted))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(Course.InstructorId))
|
||||
.AsInt32().NotNullable().ForeignKey<Customer>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Course.InstructorGuid))
|
||||
.AsGuid().NotNullable()
|
||||
.WithColumn(nameof(Course.CreatedOnUtc))
|
||||
.AsDateTime().NotNullable()
|
||||
.WithColumn(nameof(Course.UpdatedOnUtc))
|
||||
.AsDateTime().NotNullable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Core.Domain.Customers;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Data.Mapping.Builders
|
||||
{
|
||||
public class CourseProgressBuilder : NopEntityBuilder<CourseProgress>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(CourseProgress.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(CourseProgress.CourseId))
|
||||
.AsInt32().NotNullable().ForeignKey<Course>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(CourseProgress.StudentId))
|
||||
.AsInt32().NotNullable().ForeignKey<Customer>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(CourseProgress.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Mapping.Builders
|
||||
{
|
||||
public class LessonAttachmentBuilder : NopEntityBuilder<LessonAttachment>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(LessonAttachment.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(LessonAttachment.LessonId))
|
||||
.AsInt32().Nullable().ForeignKey<Lesson>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(LessonAttachment.AttachmentId))
|
||||
.AsInt32().Nullable().ForeignKey<Attachment>(onDelete: System.Data.Rule.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Core.Domain.Customers;
|
||||
using Nop.Core.Domain.Media;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Data.Mapping.Builders
|
||||
{
|
||||
public class LessonBuilder : NopEntityBuilder<Lesson>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(Lesson.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(Lesson.Name))
|
||||
.AsString(500).NotNullable()
|
||||
.WithColumn(nameof(Lesson.LessonTypeId))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(Lesson.LessonContents))
|
||||
.AsString(4000).Nullable()
|
||||
.WithColumn(nameof(Lesson.VideoId))
|
||||
.AsInt32().Nullable().ForeignKey<Video>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Lesson.PictureId))
|
||||
.AsInt32().Nullable().ForeignKey<Picture>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Lesson.DocumentId))
|
||||
.AsInt32().Nullable().ForeignKey<Attachment>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Lesson.LimitedToStores))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(Lesson.IsFreeLesson))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(Lesson.InstructorId))
|
||||
.AsInt32().NotNullable().ForeignKey<Customer>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Lesson.InstructorGuid))
|
||||
.AsGuid().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Core.Domain.Customers;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Data.Mapping.Builders
|
||||
{
|
||||
public class LessonProgressBuilder : NopEntityBuilder<LessonProgress>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(LessonProgress.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(LessonProgress.CourseProgressId))
|
||||
.AsInt32().NotNullable().ForeignKey<CourseProgress>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(LessonProgress.LessonId))
|
||||
.AsInt32().NotNullable().ForeignKey<Lesson>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(LessonProgress.IsCompleted))
|
||||
.AsBoolean().Nullable()
|
||||
.WithColumn(nameof(LessonProgress.CurrentlyAt))
|
||||
.AsInt32().Nullable()
|
||||
.WithColumn(nameof(LessonProgress.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Mapping.Builders
|
||||
{
|
||||
public class PluginBuilder : NopEntityBuilder<CustomTable>
|
||||
{
|
||||
#region Methods
|
||||
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using Nop.Data.Extensions;
|
||||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
|
||||
public class SectionBuilder : NopEntityBuilder<Section>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(Section.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(Section.CourseId))
|
||||
.AsInt32().NotNullable().ForeignKey<Course>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Section.Title))
|
||||
.AsString(500).NotNullable()
|
||||
.WithColumn(nameof(Section.DisplayOrder))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(Section.IsFree))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(Section.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Nop.Data.Extensions;
|
||||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
|
||||
public class SectionLessonBuilder : NopEntityBuilder<SectionLesson>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(SectionLesson.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(SectionLesson.CourseId))
|
||||
.AsInt32().NotNullable().ForeignKey<Course>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(SectionLesson.SectionId))
|
||||
.AsInt32().NotNullable().ForeignKey<Section>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(SectionLesson.LessonId))
|
||||
.AsInt32().NotNullable().ForeignKey<Lesson>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(SectionLesson.DisplayOrder))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(SectionLesson.IsFreeLesson))
|
||||
.AsBoolean().NotNullable()
|
||||
.WithColumn(nameof(SectionLesson.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using Nop.Data.Extensions;
|
||||
using FluentMigrator.Builders.Create.Table;
|
||||
using Nop.Data.Mapping.Builders;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Core.Domain.Customers;
|
||||
|
||||
public class VideoBuilder : NopEntityBuilder<Video>
|
||||
{
|
||||
public override void MapEntity(CreateTableExpressionBuilder table)
|
||||
{
|
||||
table.WithColumn(nameof(Video.Id))
|
||||
.AsInt32().PrimaryKey().Identity()
|
||||
.WithColumn(nameof(Video.VideoTypeId))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(Video.VideoIdFromProvider))
|
||||
.AsString(4000).NotNullable()
|
||||
.WithColumn(nameof(Video.Duration))
|
||||
.AsInt32().NotNullable()
|
||||
.WithColumn(nameof(Video.VideoUrl))
|
||||
.AsString(4000).Nullable()
|
||||
.WithColumn(nameof(Video.VideoEmbedCode))
|
||||
.AsString(4000).Nullable()
|
||||
.WithColumn(nameof(Video.InstructorGuid))
|
||||
.AsGuid().NotNullable()
|
||||
.WithColumn(nameof(Video.InstructorId))
|
||||
.AsInt32().NotNullable().ForeignKey<Customer>(onDelete: System.Data.Rule.None)
|
||||
.WithColumn(nameof(Video.LimitedToStores))
|
||||
.AsBoolean().NotNullable();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using Nop.Data.Mapping;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Mapping
|
||||
{
|
||||
public partial class NameCompatibility : INameCompatibility
|
||||
{
|
||||
public Dictionary<Type, string> TableNames => new Dictionary<Type, string>()
|
||||
{
|
||||
{typeof(Course),"SimpleLMS_Course" },
|
||||
{typeof(Video),"SimpleLMS_Video" },
|
||||
{typeof(Attachment),"SimpleLMS_Attachment" },
|
||||
{typeof(SectionLesson),"SimpleLMS_SectionLesson" },
|
||||
{typeof(Section),"SimpleLMS_Section" },
|
||||
{typeof(LessonProgress),"SimpleLMS_LessonProgress" },
|
||||
{typeof(Lesson),"SimpleLMS_Lesson" },
|
||||
{typeof(CourseProgress),"SimpleLMS_CourseProgress" }
|
||||
//{typeof(LessonAttachment),"SimpleLMS_LessonAttachment" }
|
||||
};
|
||||
|
||||
public Dictionary<(Type, string), string> ColumnName => new Dictionary<(Type, string), string>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
using FluentMigrator;
|
||||
using Nop.Data.Extensions;
|
||||
using Nop.Data.Mapping;
|
||||
using Nop.Data.Migrations;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Migrations
|
||||
{
|
||||
[NopMigration("2022/06/11 16:21:00:0000000","4.5",UpdateMigrationType.Data ,MigrationProcessType.Installation)]
|
||||
public class SchemaMigration : Migration
|
||||
{
|
||||
public SchemaMigration()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collect the UP migration expressions
|
||||
/// </summary>
|
||||
public override void Up()
|
||||
{
|
||||
|
||||
if(!Schema.Table(NameCompatibilityManager.GetTableName(typeof(Course))).Exists())
|
||||
{
|
||||
Create.TableFor<Course>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(CourseProgress))).Exists())
|
||||
{
|
||||
Create.TableFor<CourseProgress>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(Attachment))).Exists())
|
||||
{
|
||||
Create.TableFor<Attachment>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(Video))).Exists())
|
||||
{
|
||||
Create.TableFor<Video>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(Lesson))).Exists())
|
||||
{
|
||||
Create.TableFor<Lesson>();
|
||||
}
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(LessonAttachment))).Exists())
|
||||
{
|
||||
Create.TableFor<LessonAttachment>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(LessonProgress))).Exists())
|
||||
{
|
||||
Create.TableFor<LessonProgress>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(Section))).Exists())
|
||||
{
|
||||
Create.TableFor<Section>();
|
||||
}
|
||||
|
||||
if (!Schema.Table(NameCompatibilityManager.GetTableName(typeof(SectionLesson))).Exists())
|
||||
{
|
||||
Create.TableFor<SectionLesson>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public record CourseDetail : BaseNopEntityModel
|
||||
{
|
||||
public CourseDetail()
|
||||
{
|
||||
Sections = new List<SectionDetail>();
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.ProductName")]
|
||||
public string ParentProductName { get; set; }
|
||||
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.ProductName")]
|
||||
public int ProductId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Sections")]
|
||||
public int SectionsTotal { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Lessons")]
|
||||
public int LessonsTotal { get; set; }
|
||||
|
||||
public IList<SectionDetail> Sections { get; set; }
|
||||
|
||||
public int TotalLessons { get { return Sections.SelectMany(p => p.Lessons).ToList().Count; } }
|
||||
|
||||
public int CompletedLessons { get { return Sections.SelectMany(p => p.Lessons.Where(q => q.IsCompleted)).Count(); } }
|
||||
|
||||
public int Progress { get { return (TotalLessons > 0 ? CompletedLessons * 100 / TotalLessons : 0); } }
|
||||
|
||||
public int CurrentSection { get; set; }
|
||||
public int CurrentLesson { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.UI.Paging;
|
||||
using Nop.Web.Models.Common;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public partial record CourseOverviewListModel : BasePageableModel
|
||||
{
|
||||
public CourseOverviewListModel()
|
||||
{
|
||||
Courses = new List<CourseOverviewModel>();
|
||||
}
|
||||
|
||||
public IList<CourseOverviewModel> Courses { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using Nop.Plugin.Misc.SimpleLMS.Areas.Admin.Models;
|
||||
using Nop.Web.Areas.Admin.Models.Catalog;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public partial record CourseOverviewModel : BaseNopEntityModel
|
||||
{
|
||||
|
||||
public CourseOverviewModel()
|
||||
{
|
||||
CourseProgress = 0;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string ParentProductName { get; set; }
|
||||
public string ProductMainImage { get; set; }
|
||||
public int CourseProgress { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public partial record CourseSearchModel : BaseSearchModel
|
||||
{
|
||||
public CourseSearchModel()
|
||||
{
|
||||
CourseOverviewList = new CourseOverviewListModel();
|
||||
PageNumber = 1;
|
||||
Length = 6;
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.SearchCourseName")]
|
||||
public string SearchCourseName { get; set; }
|
||||
|
||||
public CourseOverviewListModel CourseOverviewList { get; set; }
|
||||
|
||||
public int PageNumber { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public record LessonDetail : BaseNopEntityModel
|
||||
{
|
||||
public LessonDetail()
|
||||
{
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.LessonType")]
|
||||
public LessonType LessonType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.LessonContents")]
|
||||
public string LessonContents { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.DisplayOrder")]
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Instructor")]
|
||||
public int InstructorName { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.SectionName")]
|
||||
public int SectionId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.IsFree")]
|
||||
public bool IsFreeLesson { get; set; }
|
||||
|
||||
public VideoDetail Video { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoType")]
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoIdFromProvider")]
|
||||
public string VideoIdFromProvider { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Duration")]
|
||||
public int Duration { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoUrl")]
|
||||
public string VideoUrl { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoEmbedCode")]
|
||||
public string VideoEmbedCode { get; set; }
|
||||
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.CourseName")]
|
||||
public int CourseId { get; internal set; }
|
||||
|
||||
public bool IsCompleted { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using Nop.Web.Framework.Models;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public record LessonStatusModel : BaseNopEntityModel
|
||||
{
|
||||
public LessonStatusModel()
|
||||
{
|
||||
}
|
||||
|
||||
public int CourseId { get; set; }
|
||||
public int SectionId { get; set; }
|
||||
public int LessonId { get; set; }
|
||||
public bool IsCompleted { get; set; }
|
||||
public int CurrentlyAt { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public record SectionDetail : BaseNopEntityModel
|
||||
{
|
||||
public SectionDetail()
|
||||
{
|
||||
Lessons = new List<LessonDetail>();
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Name")]
|
||||
public string Title { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.DisplayOrder")]
|
||||
public int DisplayOrder { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.CourseName")]
|
||||
public string CourseName { get; set; }
|
||||
|
||||
public int CourseId { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.IsFree")]
|
||||
public bool IsFree { get; set; }
|
||||
|
||||
public IList<LessonDetail> Lessons { get; set; }
|
||||
|
||||
public int TotalLessons { get { return Lessons.Count; } }
|
||||
|
||||
public int CompletedLessons { get { return Lessons.Where(p => p.IsCompleted).Count(); } }
|
||||
|
||||
public int Duration { get
|
||||
{
|
||||
return
|
||||
Lessons.Select(p=>p.Duration).Sum();
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using Nop.Plugin.Misc.SimpleLMS.Domains;
|
||||
using Nop.Web.Framework.Models;
|
||||
using Nop.Web.Framework.Mvc.ModelBinding;
|
||||
|
||||
namespace Nop.Plugin.Misc.SimpleLMS.Models
|
||||
{
|
||||
public record VideoDetail : BaseNopEntityModel
|
||||
{
|
||||
public VideoDetail()
|
||||
{
|
||||
}
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoType")]
|
||||
public VideoType VideoType { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoIdFromProvider")]
|
||||
public string VideoIdFromProvider { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.Duration")]
|
||||
public int Duration { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoUrl")]
|
||||
public string VideoUrl { get; set; }
|
||||
|
||||
[NopResourceDisplayName("SimpleLMS.VideoEmbedCode")]
|
||||
public string VideoEmbedCode { get; set; }
|
||||
|
||||
|
||||
public string TimeCode { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||