public AssessmentEligibilityStatus GetEligibilityStatus(string username, int courseId) { bool hasActiveSubscription = _subscriptions.All().FirstOrDefault(x => x.User.Username == username && x.CourseId == courseId)?.Status == SubscriptionStatus.Active; List <int> unvisitedLectures; if (hasActiveSubscription && _lecturesService.HasVisitedAllLectures(username, courseId, out unvisitedLectures)) { AssessmentSubmission latestSubmission = _assessmentSubmissions.All() .Where(x => x.AssessmentRequest.User.Username == username && x.CourseId == courseId).OrderByDescending(x => x.CreatedOn).FirstOrDefault(); if (latestSubmission != null) { if (latestSubmission.IsSuccessful) { return(AssessmentEligibilityStatus.AlreadyCompleted); } if (NextAvailableAssessmentAttempt(latestSubmission.CreatedOn) > DateTime.UtcNow) { return(AssessmentEligibilityStatus.Lockout); } } return(AssessmentEligibilityStatus.Eligible); } return(AssessmentEligibilityStatus.NotEligible); }
public void CreateAssessmentSubmission(AssessmentSubmission submission, out Certificate certificate) { if (submission == null) { throw new ArgumentNullException(nameof(submission)); } certificate = null; //TODO validation AssessmentRequest request = submission.AssessmentRequest ?? _assessmentRequests.GetById(submission.AssessmentRequestId); request.IsCompleted = true; _assessmentRequests.Update(request); _assessmentRequests.SaveChanges(); submission.UserId = request.UserId; _assessmentSubmissions.Add(submission); _assessmentSubmissions.SaveChanges(); Course submissionCourse = _courses.GetById(submission.CourseId); if (submission.IsSuccessful) { certificate = _certificatesService.GenerateCertificate(request.User.Username, submissionCourse.Id, submission); string certificateUrl = _routeProvider.GetCertificateRoute(certificate); string certificatePictureUrl = _routeProvider.GetCertificatePictureRoute(certificate); _messageService.SendExamSuccessfulMessage(request.User, submissionCourse, certificateUrl, certificatePictureUrl); } else { string assessmentUrl = _routeProvider.GetAssessmentRoute(submissionCourse.Id); _taskRunner.Schedule <IMessageService>(x => x.SendExamAvailableMessage(request.User, submissionCourse, assessmentUrl), NextAvailableAssessmentAttempt(submission.CreatedOn));//TODO add config setting } }
public DateTime?GetNextAssessmentAttemptDate(string username, int courseId) { AssessmentSubmission latestSubmission = _assessmentSubmissions.All() .Where(x => x.User.Username == username && x.CourseId == courseId) .OrderByDescending(x => x.CreatedOn) .FirstOrDefault(); if (latestSubmission == null) { return(null); } return(NextAvailableAssessmentAttempt(latestSubmission.CreatedOn)); }
public Certificate GenerateCertificate(string username, int courseId, AssessmentSubmission assessmentSubmission) { User user = _users.GetByUsername(username); Course course = _courses.GetById(courseId); Certificate certificate = new Certificate { UserId = user.Id, AssesmentSubmissionId = assessmentSubmission.Id, CourseId = course.Id, Code = _random.GenerateRandomCode(10) }; CertificateGenerationInfo certificateGenerationInfo = _generationInfoProvider.GetByCourseId(courseId); string certificateRelativePath = string.Format(CertificateFilePathFormat, certificate.Code); string filePath = Path.Combine(certificateGenerationInfo.BaseFilePath, certificateRelativePath); certificate.FilePath = certificateRelativePath; _certificates.Add(certificate); _certificates.SaveChanges(); Bitmap bitmap = (Bitmap)Image.FromFile(Path.GetFullPath(certificateGenerationInfo.TemplateFilePath));//load the image file QRCodeEncoder encoder = new QRCodeEncoder(); Bitmap certificateUrlQrCode = encoder.Encode(string.Format(CertificateUrlFormat, certificate.Code)); using (Graphics certificateTemplate = Graphics.FromImage(bitmap)) { using (Font arialFont = new Font("Arial", 16, FontStyle.Bold)) { using (Font arialFontLarge = new Font("Arial", 20, FontStyle.Bold)) { PlaceholderInfo studentData = certificateGenerationInfo.StudentName; PlaceholderInfo courseData = certificateGenerationInfo.CourseName; PlaceholderInfo datePlaceholder = certificateGenerationInfo.IssueDate; PlaceholderInfo qrPlaceholder = certificateGenerationInfo.QrCode; PlaceholderInfo certificateNumberPlaceholder = certificateGenerationInfo.CertificateNumber; PlaceholderInfo moduleNamesPlaceholder = certificateGenerationInfo.ModuleNames; PlaceholderInfo numberOfHoursPlaceholder = certificateGenerationInfo.NumberOfHours; certificateTemplate.DrawString($"{user.FirstName} {user.MiddleName} {user.LastName}", arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(studentData.Color)), new Rectangle(studentData.TopLeftX, studentData.TopLeftY, studentData.Width, studentData.Height)); certificateTemplate.DrawString(course.Title, arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(courseData.Color)), new Rectangle(courseData.TopLeftX, courseData.TopLeftY, courseData.Width, courseData.Height)); certificateTemplate.DrawString(DateTime.Today.ToString("dd.MM.yyy") + "г.", arialFont, new SolidBrush(ColorTranslator.FromHtml(datePlaceholder.Color)), new Rectangle(datePlaceholder.TopLeftX, datePlaceholder.TopLeftY, datePlaceholder.Width, datePlaceholder.Height)); certificateTemplate.DrawImage(certificateUrlQrCode, new Rectangle(qrPlaceholder.TopLeftX, qrPlaceholder.TopLeftY, qrPlaceholder.Width, qrPlaceholder.Height)); certificateTemplate.DrawString($"Рег. № {certificate.Id}", arialFontLarge, new SolidBrush(ColorTranslator.FromHtml(certificateNumberPlaceholder.Color)), new Rectangle(certificateNumberPlaceholder.TopLeftX, certificateNumberPlaceholder.TopLeftY, certificateNumberPlaceholder.Width, certificateNumberPlaceholder.Height)); certificateTemplate.DrawString(course.ModuleNames, arialFont, new SolidBrush(ColorTranslator.FromHtml(moduleNamesPlaceholder.Color)), new Rectangle(moduleNamesPlaceholder.TopLeftX, moduleNamesPlaceholder.TopLeftY, moduleNamesPlaceholder.Width, moduleNamesPlaceholder.Height)); certificateTemplate.DrawString($"{course.NumberOfHours} учебни часа", arialFont, new SolidBrush(ColorTranslator.FromHtml(numberOfHoursPlaceholder.Color)), new Rectangle(numberOfHoursPlaceholder.TopLeftX, numberOfHoursPlaceholder.TopLeftY, numberOfHoursPlaceholder.Width, numberOfHoursPlaceholder.Height)); string directoryPath = Path.GetDirectoryName(filePath); Debug.Assert(!string.IsNullOrEmpty(directoryPath)); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } bitmap.Save(filePath); } } } return(certificate); }
public ActionResult Assessment(AssessmentViewModel assessment) { int courseId = _coursesContentService.GetCourseId(Umbraco.AssignedContentItem); string username = User.Identity.Name; if (!_feedbackService.UserHasSentFeedback(username, courseId)) { return(RedirectToRoute("Feedback", new { courseNiceUrl = Umbraco.AssignedContentItem.UrlName })); } if (_assessments.GetEligibilityStatus(username, courseId) != AssessmentEligibilityStatus.Eligible) { return(Redirect(Umbraco.AssignedContentItem.Url)); } if (assessment.AssessmentRequestId == default(int)) { throw new ArgumentException("Assessment Id is missing from Assessment Submission. Cannot evaluate assessment"); } var assessmentRequest = _assessments.GetAssessmentRequest(assessment.AssessmentRequestId); IEnumerable <IPublishedContent> questions = Umbraco.TypedContent(assessmentRequest.QuestionIds.Split(',').ToList()); IPublishedContent assessmentContnet = Umbraco.TypedContent(assessmentRequest.AssessmentExternalId); var requiredCorrectAnswers = assessmentContnet.GetPropertyValue <int>( nameof(Models.Umbraco.DocumentTypes.Assessment.RequiredCorrectAnswers)); if (requiredCorrectAnswers == default(int)) { throw new ArgumentException($"Number of required correct answers is not set for assessment with ID: {assessmentRequest.AssessmentExternalId}"); } AssessmentViewModel assessmentViewModel = new AssessmentViewModel(); List <QuestionViewModel> questionViewModel = new List <QuestionViewModel>(); _mapper.AddCustomMapping(typeof(IEnumerable <QuestionAnswer>).FullName, UmbracoMapperMappings.MapQuestionAnswer) .MapCollection(questions, questionViewModel) .Map(assessmentContnet, assessmentViewModel); assessmentViewModel.Questions = questionViewModel; int correctAnswers = 0; foreach (QuestionViewModel questionInDb in assessmentViewModel.Questions) { QuestionViewModel questionAnswered = assessment.Questions.Single(x => x.Id == questionInDb.Id); questionAnswered.QuestionText = questionInDb.QuestionText; bool isCorrectlyAnswered = true; foreach (QuestionAnswer answerInDb in questionInDb.Answers) { QuestionAnswer answer = questionAnswered.Answers.Single(x => x.Index == answerInDb.Index); answer.Text = answerInDb.Text; if (answer.IsCorrect != answerInDb.IsCorrect) { isCorrectlyAnswered = false; break; } } if (isCorrectlyAnswered) { correctAnswers++; } } var submission = new AssessmentSubmission { CourseId = courseId, AssessmentRequest = assessmentRequest, Submission = JsonConvert.SerializeObject(assessment.Questions) }; if (correctAnswers >= requiredCorrectAnswers) { submission.IsSuccessful = true; } Certificate certificate; _assessments.CreateAssessmentSubmission(submission, out certificate); if (submission.IsSuccessful) { TempData["SuccessfulSubmission"] = true; TempData["CorrectAnswers"] = correctAnswers; TempData["RequiredAnswers"] = requiredCorrectAnswers; return(RedirectToRoute("Certificate", new { certificateCode = certificate.Code })); } return(View("AssessmentFailure", new AssessmentFailureViewModel { CorrectAnswers = correctAnswers, RequiredAnswers = requiredCorrectAnswers, NumberOfQuestions = questions.Count(), CourseTitle = Umbraco.AssignedContentItem.Name, CourseUrl = Umbraco.AssignedContentItem.Url, // ReSharper disable once PossibleInvalidOperationException - This should never be null as we've just done a submission NextAttempt = _assessments.GetNextAssessmentAttemptDate(username, courseId).Value })); }