generated from karsten.jeppesen/KAJE-Template
Quizzer-8: Migrating to .NET 10
This commit is contained in:
455
Quizzer-8/Quizzer/Pages/Index.cshtml.cs
Normal file
455
Quizzer-8/Quizzer/Pages/Index.cshtml.cs
Normal file
@@ -0,0 +1,455 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Newtonsoft.Json;
|
||||
using Quizzer.Extensions;
|
||||
using Quizzer.Models;
|
||||
using Quizzer.OpenIDConnect;
|
||||
using Quizzer.Persistens;
|
||||
using System.Collections;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
|
||||
namespace Quizzer.Pages
|
||||
{
|
||||
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
|
||||
// Generat landing page
|
||||
// Teachers get navigation options
|
||||
// Students are presented with selection of available tests
|
||||
|
||||
[BindProperty]
|
||||
public string PageQuizzID { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public List<JournalHtml> PageTests { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public OpenIDUCNData ucnData { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string UserID { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string StudentState { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public MCQuestion PageMCQuestion { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public List<MCQuestion> PageMCQuestionReview { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public List<List<bool>> PageMCResponseReview { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public List<int> PageMCRandomized { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public string myFullName { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public List<ChartConnector> PageChartConnectors { get; set; }
|
||||
|
||||
private readonly ILogger<IndexModel> _logger;
|
||||
|
||||
public IndexModel(ILogger<IndexModel> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private bool isDebug;
|
||||
private string KCUserID { get; set; }
|
||||
|
||||
private DbOps dbManager = new();
|
||||
|
||||
private OpenIDConnectUtils OpenIDUtils = new();
|
||||
|
||||
private void DumpEnvironment()
|
||||
{
|
||||
Console.WriteLine("HEADER DUMP START");
|
||||
foreach (var e in HttpContext.Request.Headers)
|
||||
{
|
||||
Console.WriteLine(e.Key + ":" + e.Value);
|
||||
}
|
||||
Console.WriteLine("HEADER DUMP END");
|
||||
Console.WriteLine("ENVIRONMENT DUMP START");
|
||||
foreach (DictionaryEntry e in System.Environment.GetEnvironmentVariables())
|
||||
{
|
||||
Console.WriteLine(e.Key + ":" + e.Value);
|
||||
}
|
||||
Console.WriteLine("ENVIRONMENT DUMP END");
|
||||
}
|
||||
|
||||
public void Common()
|
||||
{
|
||||
isDebug = MyConfiguration.Get()["DEBUG"] == "Y";
|
||||
string? ucnDataJson = OpenIDUtils.GetJwtClaim(HttpContext, "ucn");
|
||||
|
||||
KCUserID = OpenIDUtils.GetJwtClaim(HttpContext, "sub");
|
||||
ucnData = JsonConvert.DeserializeObject<OpenIDUCNData>(ucnDataJson);
|
||||
UserID = OpenIDUtils.GetJwtClaim(HttpContext, "email").HashSHA256();
|
||||
myFullName = OpenIDUtils.GetJwtClaim(HttpContext, "name");
|
||||
}
|
||||
|
||||
private void Msg(string msg)
|
||||
{
|
||||
Boolean debug = true;
|
||||
if (debug)
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void Journal(string Msg)
|
||||
{
|
||||
Console.WriteLine("JOURNAL:" + Msg);
|
||||
}
|
||||
|
||||
|
||||
// =============================================================
|
||||
// From SSO session:
|
||||
// OIDC_CLAIM_email = "KAJE@ucn.dk"
|
||||
// OIDC_CLAIM_family_name = "Jeppesen"
|
||||
// OIDC_CLAIM_given_name = "Karsten"
|
||||
// OIDC_CLAIM_name = "Karsten Jeppesen"
|
||||
|
||||
List<Question> PopulateQList(string theCategory)
|
||||
{
|
||||
// Get the questions in the category
|
||||
List<Question> list = dbManager.GetQuestions(theCategory);
|
||||
// Now get the subordinate categories
|
||||
List<Cat> catList = dbManager.GetChildCategories(theCategory);
|
||||
foreach (Cat cat in catList)
|
||||
{
|
||||
list.AddRange(PopulateQList(cat.CId));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void PrepareForUser(string theRole, string theClass)
|
||||
{
|
||||
|
||||
foreach (Quizz theQuizz in dbManager.GetQuizzesClass(theClass))
|
||||
{
|
||||
// Make sure that for a quizz is generated for this individual
|
||||
Journal2 theJournal = dbManager.GetJournal2(UserID, theQuizz.QuizzId);
|
||||
if (theJournal == null)
|
||||
{
|
||||
// Make up a new journal
|
||||
Journal2 newJournal = new()
|
||||
{
|
||||
PID = UserID,
|
||||
QuizzID = theQuizz.QuizzId,
|
||||
Category = theQuizz.Category,
|
||||
Anonymous = theQuizz.Anonymous,
|
||||
IsOpen = 1,
|
||||
Score = 0,
|
||||
ScoreAcc = 0,
|
||||
};
|
||||
//List<Item>items = JsonConvert.DeserializeObject<List<Item>>(theJournal.JournalJson);
|
||||
newJournal.Items = new();
|
||||
List<Question> myQuestions = PopulateQList(theQuizz.Category);
|
||||
//List<Question> myQuestions = dbManager.GetQuestions(theQuizz.Category);
|
||||
int theSize = (myQuestions.Count < theQuizz.QSize) ? myQuestions.Count : theQuizz.QSize;
|
||||
Random rnd = new Random();
|
||||
while (theSize < myQuestions.Count)
|
||||
{
|
||||
myQuestions.RemoveAt(rnd.Next(myQuestions.Count));
|
||||
}
|
||||
// we should now have a random selection of theSize questions
|
||||
// Lets mix the deck
|
||||
for (int indx = 0; indx < myQuestions.Count; indx++)
|
||||
{
|
||||
int target = rnd.Next(myQuestions.Count);
|
||||
myQuestions.Add(myQuestions[target]);
|
||||
myQuestions.RemoveAt(target);
|
||||
}
|
||||
foreach (Question question in myQuestions)
|
||||
{
|
||||
newJournal.ScoreAcc++;
|
||||
newJournal.Items.Add(new Journal2Item
|
||||
{
|
||||
QuestionID = question.QuestionID,
|
||||
IsOpen = 1,
|
||||
Score = 0,
|
||||
MaxScore = 1,
|
||||
});
|
||||
}
|
||||
dbManager.PostJournal2(newJournal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTestSelection()
|
||||
{
|
||||
List<JournalHtml> myTests = new();
|
||||
List<Journal2> myJournals = dbManager.GetJournal2(UserID);
|
||||
foreach (Journal2 myJournal in myJournals)
|
||||
{
|
||||
Quizz theQuizz = dbManager.GetQuizz(myJournal.QuizzID);
|
||||
if (theQuizz == null) continue;
|
||||
JournalHtml myHtml = new()
|
||||
{
|
||||
Journal = myJournal,
|
||||
Text = theQuizz.Descr,
|
||||
};
|
||||
myTests.Add(myHtml);
|
||||
}
|
||||
PageTests = myTests;
|
||||
}
|
||||
|
||||
private bool PresentQuestion()
|
||||
{
|
||||
Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
|
||||
if (myJournal == null)
|
||||
{
|
||||
Response.Cookies.Delete("PageQuizzID");
|
||||
return false;
|
||||
}
|
||||
//List<Item> myItems = JsonConvert.DeserializeObject<List<Item>>(myJournal.JournalJson);
|
||||
Random rnd = new Random();
|
||||
foreach (var item in myJournal.Items)
|
||||
{
|
||||
if (item.IsOpen == 1)
|
||||
{
|
||||
// Get the question
|
||||
MCQuestion myMCQuestion = dbManager.GetMCQuestion(item.QuestionID);
|
||||
List<int> myRndSeq = new List<int>();
|
||||
for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
|
||||
{
|
||||
myRndSeq.Add(indx);
|
||||
myMCQuestion.AList[indx].Aok = false;
|
||||
}
|
||||
PageMCRandomized = new List<int>();
|
||||
while (myRndSeq.Count > 0)
|
||||
{
|
||||
int indx = rnd.Next(myRndSeq.Count);
|
||||
PageMCRandomized.Add(myRndSeq[indx]);
|
||||
myRndSeq.RemoveAt(indx);
|
||||
}
|
||||
PageMCQuestion = myMCQuestion;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
FinalizeTest();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void FinalizeTest()
|
||||
{
|
||||
Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
|
||||
myJournal.IsOpen = 0;
|
||||
dbManager.UpdateJournal2(myJournal);
|
||||
Response.Cookies.Delete("PageQuizzID");
|
||||
}
|
||||
|
||||
private void RegisterAnswer()
|
||||
{
|
||||
Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
|
||||
foreach (var item in myJournal.Items)
|
||||
{
|
||||
if (item.IsOpen == 1)
|
||||
{
|
||||
// Get the question
|
||||
MCQuestion myMCQuestion = dbManager.GetMCQuestion(item.QuestionID);
|
||||
if (myMCQuestion != null)
|
||||
{
|
||||
int theScore = item.MaxScore;
|
||||
int answers = 0;
|
||||
item.ReplyMC = new();
|
||||
for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
|
||||
{
|
||||
item.ReplyMC.Add(PageMCQuestion.AList[indx].Aok);
|
||||
if (myMCQuestion.AList[indx].Aok != PageMCQuestion.AList[indx].Aok) theScore = 0;
|
||||
if (PageMCQuestion.AList[indx].Aok) answers++;
|
||||
}
|
||||
if (answers != 1) return; // Must have one answer and one only
|
||||
item.Score = theScore;
|
||||
myJournal.Score += theScore;
|
||||
item.IsOpen = 0;
|
||||
dbManager.UpdateJournal2(myJournal);
|
||||
// Now register statistics
|
||||
List<int> counter = new List<int>();
|
||||
for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
|
||||
{
|
||||
if (PageMCQuestion.AList[indx].Aok) { counter.Add(1); } else { counter.Add(0); }
|
||||
}
|
||||
dbManager.UpdateStats(PageQuizzID, item.QuestionID, counter);
|
||||
PageMCQuestion.AList.Clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private void PrepareReview()
|
||||
{
|
||||
PageMCQuestionReview = new();
|
||||
PageMCResponseReview = new();
|
||||
List<StatisticsStudentByCategory> StatStudent = new();
|
||||
Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
|
||||
if (myJournal == null)
|
||||
{
|
||||
Response.Cookies.Delete("PageQuizzID");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int index = 0; index < myJournal.Items.Count; index++)
|
||||
{
|
||||
string background;
|
||||
MCQuestion question = dbManager.GetMCQuestion(myJournal.Items[index].QuestionID);
|
||||
PageMCQuestionReview.Add(question);
|
||||
PageMCResponseReview.Add(myJournal.Items[index].ReplyMC);
|
||||
// create statistics
|
||||
StatisticsStudentByCategory theStat = StatStudent.Find(x => x.CategoryID == question.Category);
|
||||
if (theStat == null)
|
||||
{ // need a new one
|
||||
Cat cat = dbManager.GetCat(question.Category);
|
||||
StatStudent.Add(new StatisticsStudentByCategory { CategoryID = cat.CId, CategoryName = cat.Txt });
|
||||
theStat = StatStudent[StatStudent.Count - 1];
|
||||
}
|
||||
theStat.Update(myJournal.Items[index].Score, myJournal.Items[index].MaxScore);
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/7f96525d-7253-4f08-87f8-88ae526834f9/razor-pages-with-chartjs?forum=aspdotnetcore
|
||||
PageChartConnectors = new List<ChartConnector>();
|
||||
//background = "getRandomColor()";
|
||||
var random = new Random();
|
||||
foreach (StatisticsStudentByCategory item in StatStudent)
|
||||
{
|
||||
background = String.Format("#{0:X6}", random.Next(0x1000000)); // = "#A197B9"
|
||||
PageChartConnectors.Add(new ChartConnector
|
||||
{
|
||||
ChartLabel = item.CategoryName,
|
||||
ChartData = item.percentage.ToString(),
|
||||
ChartBackground = background,
|
||||
ChartBorder = "#FFBBBB"
|
||||
});
|
||||
}
|
||||
//PageChartConnectors.Add(new ChartConnector
|
||||
//{
|
||||
// ChartLabel = "100%",
|
||||
// ChartData = "100",
|
||||
// ChartBackground = "#000000",
|
||||
// ChartBorder = "#FFBBBB"
|
||||
//});
|
||||
//PageChartConnectors.Add(new ChartConnector { ChartLabel = "Jan", ChartData = "31", ChartBackground = "#FF0000", ChartBorder = "#000000" });
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckPageQuizzID()
|
||||
{
|
||||
if (PageQuizzID == null)
|
||||
{
|
||||
//PrepareForUser(ucnData.theRole, ucnData.theClass.FirstOrDefault());
|
||||
foreach (var item in ucnData.theClass)
|
||||
{
|
||||
PrepareForUser(ucnData.theRole, item);
|
||||
}
|
||||
BuildTestSelection();
|
||||
if (ucnData.theRole == "student" || ucnData.theRole == "developer") StudentState = "QuizzSelect";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QuizzRunning())
|
||||
{
|
||||
//PageQuizzID = null;
|
||||
if (ucnData.theRole == "student" || ucnData.theRole == "developer") StudentState = "QuizzSelect";
|
||||
PrepareForUser(ucnData.theRole, ucnData.theClass.FirstOrDefault());
|
||||
BuildTestSelection();
|
||||
// Review selected test?
|
||||
PrepareReview();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckTheClass()
|
||||
{
|
||||
if (ucnData.theClass.Count > 0)
|
||||
{
|
||||
foreach (var item in ucnData.theClass)
|
||||
{
|
||||
if (item.Contains("-CSD-"))
|
||||
{
|
||||
if (dbManager.GetTheClasses().Find(x => x.Name == item) == null) dbManager.CreateTheClass(new TheClass { Name = item });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IActionResult OnGet(string category, string count)
|
||||
{
|
||||
try
|
||||
{
|
||||
// if the entity can not be categorized then send him to classselect
|
||||
Common();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Redirect("https://ClassSelect.a.ucnit.eu");
|
||||
}
|
||||
if ((ucnData.theClass.Count == 0) || (ucnData.theClass[0] == "PleaseSelectAClass"))
|
||||
{
|
||||
// No class found
|
||||
return Redirect("https://ClassSelect.a.ucnit.eu");
|
||||
}
|
||||
PageQuizzID = HttpContext.Request.Cookies["PageQuizzID"];
|
||||
CheckPageQuizzID();
|
||||
// Next line should be replaced by call to KeyCloakGetUsersGroups
|
||||
// CheckTheClass();
|
||||
return Page();
|
||||
}
|
||||
|
||||
private bool QuizzRunning()
|
||||
{
|
||||
StudentState = "QuizzRunning";
|
||||
return PresentQuestion();
|
||||
}
|
||||
|
||||
public IActionResult OnPost(string action, string value, string quizzInProgress, string target)
|
||||
{
|
||||
Common();
|
||||
switch (action)
|
||||
{
|
||||
case "startTest":
|
||||
// NEW: Coverage: register who takes the test
|
||||
Quizz theQuizz = dbManager.GetQuizz(value);
|
||||
if (! theQuizz.Anonymous)
|
||||
{ // Only register coverage if the test is not anonymous
|
||||
dbManager.SetCoverage(OpenIDUtils.GetJwtClaim(HttpContext, "email"), OpenIDUtils.GetJwtClaim(HttpContext, "name"), ucnData.theClass.FirstOrDefault());
|
||||
}
|
||||
if (isDebug) Console.WriteLine(OpenIDUtils.GetJwtClaim(HttpContext, "name") + ": REMOTE ADDR: " + HttpContext.Request.Headers["X-Forwarded-For"]);
|
||||
Console.WriteLine(OpenIDUtils.GetJwtClaim(HttpContext, "name") + ": REMOTE ADDR: " + HttpContext.Request.Headers["X-Forwarded-For"]);
|
||||
PageQuizzID = value;
|
||||
QuizzRunning();
|
||||
break;
|
||||
case "reviewTest":
|
||||
PageQuizzID = value;
|
||||
break;
|
||||
case "QuizzRunning":
|
||||
QuizzRunning();
|
||||
break;
|
||||
case "registerAnswer":
|
||||
PageQuizzID = quizzInProgress;
|
||||
RegisterAnswer();
|
||||
break;
|
||||
case "deleteMyTest": //Student should not be able to delete journal as this resets the journal
|
||||
dbManager.DeleteJournal2(UserID, target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (PageQuizzID != null)
|
||||
{
|
||||
Response.Cookies.Append("PageQuizzID", PageQuizzID, new Microsoft.AspNetCore.Http.CookieOptions
|
||||
{
|
||||
Secure = true,
|
||||
HttpOnly = true,
|
||||
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None,
|
||||
});
|
||||
}
|
||||
return Redirect("/");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user