This commit is contained in:
l.gabrysiak 2024-08-21 15:10:04 +02:00
parent 2250f540f5
commit 1550c640d1
154 changed files with 21245 additions and 9333 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
src/.DS_Store vendored

Binary file not shown.

BIN
src/Plugins/.DS_Store vendored

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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()
{
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -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")
});
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
namespace Nop.Plugin.Misc.SimpleLMS.Domains
{
public enum AttachmentType
{
WordDoc = 10,
Pdf = 20,
Ppt = 30,
Image = 100,
Others = 110
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,9 @@
using Nop.Core;
namespace Nop.Plugin.Misc.SimpleLMS.Domains
{
public partial class CustomTable : BaseEntity
{
}
}

View File

@ -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; }
}
}

View File

@ -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;
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -0,0 +1,11 @@
namespace Nop.Plugin.Misc.SimpleLMS.Domains
{
public enum LessonType
{
Text = 10,
Image = 20,
Document = 30,
Video = 40,
Questionire = 50,
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}

View File

@ -0,0 +1,12 @@

namespace Nop.Plugin.Misc.SimpleLMS.Domains
{
public enum VideoType
{
Hosted = 10,
Youtube = 20,
VdoCipher = 30,
Vimeo = 40,
AWS = 50
}
}

View File

@ -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")
}); ;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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();
;
}
}
}

View File

@ -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();
;
}
}
}

View File

@ -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
}
}

View File

@ -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();
;
}
}

View File

@ -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();
;
}
}

View File

@ -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();
;
}
}

View File

@ -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>();
}
}

View File

@ -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>();
}
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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();
} }
}
}

View File

@ -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; }
}
}

Some files were not shown because too many files have changed in this diff Show More