From c44e6be88a083fd45b8d8fedfe047880367999d6 Mon Sep 17 00:00:00 2001 From: acanas Date: Thu, 15 Jul 2021 19:34:41 +0200 Subject: [PATCH] Version 20.95.1: Jul 15, 2021 Queries moved to module swad_exam_database. --- swad_changelog.h | 3 +- swad_database.c | 2 +- swad_exam_database.c | 384 +++++++++++++++++++++++++++++++++++++- swad_exam_database.h | 41 +++- swad_exam_log.c | 30 +-- swad_exam_print.c | 431 +++++++++---------------------------------- 6 files changed, 507 insertions(+), 384 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index 93c3aa42..1fbdfe2a 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo. */ -#define Log_PLATFORM_VERSION "SWAD 20.95 (2021-07-08)" +#define Log_PLATFORM_VERSION "SWAD 20.95.1 (2021-07-15)" #define CSS_FILE "swad20.45.css" #define JS_FILE "swad20.69.1.js" /* TODO: Rename CENTRE to CENTER in help wiki. TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams + Version 20.95.1: Jul 15, 2021 Queries moved to module swad_exam_database. (314082 lines) Version 20.95: Jul 08, 2021 New module swad_exam_database for database queries related to exams. (313981 lines) Version 20.94.10: Jun 29, 2021 Code refactoring related to HTML output. (313860 lines) Version 20.94.9: Jun 29, 2021 Query moved from module swad_menu to module swad_setting. (313848 lines) diff --git a/swad_database.c b/swad_database.c index 00e72ed6..190b33c3 100644 --- a/swad_database.c +++ b/swad_database.c @@ -3944,7 +3944,7 @@ Rol_Role_t DB_QuerySELECTRole (const char *MsgError, } /*****************************************************************************/ -/**** Make a SELECT query for a unique row with one double from database *****/ +/**** Make a SELECT query for a unique row with one string from database *****/ /*****************************************************************************/ // StrSize does not include the ending byte '\0' diff --git a/swad_exam_database.c b/swad_exam_database.c index 03adddd8..89451881 100644 --- a/swad_exam_database.c +++ b/swad_exam_database.c @@ -35,6 +35,7 @@ //#include "swad_error.h" #include "swad_exam_database.h" #include "swad_exam_log.h" +#include "swad_exam_print.h" #include "swad_global.h" /*****************************************************************************/ @@ -59,11 +60,359 @@ extern struct Globals Gbl; /***************************** Private prototypes ****************************/ /*****************************************************************************/ +/*****************************************************************************/ +/***************** Get sets of questions in a given exam *********************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetExamSets (MYSQL_RES **mysql_res,long ExaCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get sets of questions", + "SELECT SetCod," // row[0] + "NumQstsToPrint," // row[1] + "Title" // row[2] + " FROM exa_sets" + " WHERE ExaCod=%ld" + " ORDER BY SetInd", + ExaCod); + } + +/*****************************************************************************/ +/******************* Get some random questions from a set ********************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetSomeQstsFromSetToPrint (MYSQL_RES **mysql_res, + long SetCod,unsigned NumQstsToPrint) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get questions from set", + "SELECT QstCod," // row[0] + "AnsType," // row[1] + "Shuffle" // row[2] + " FROM exa_set_questions" + " WHERE SetCod=%ld" + " ORDER BY RAND()" // Don't use RAND(NOW()) because the same ordering will be repeated across sets + " LIMIT %u", + SetCod, + NumQstsToPrint); + } + +/*****************************************************************************/ +/************** Get answers text for a question in an exam set ***************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetQstAnswersTextFromSet (MYSQL_RES **mysql_res,long QstCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get text of answers of a question", + "SELECT Answer" // row[0] + " FROM exa_set_answers" + " WHERE QstCod=%ld", + QstCod); + } + +/*****************************************************************************/ +/********** Get answers correctness for a question in an exam set ************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetQstAnswersCorrFromSet (MYSQL_RES **mysql_res,long QstCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get correctness of answers of a question", + "SELECT Correct" // row[0] + " FROM exa_set_answers" + " WHERE QstCod=%ld" + " ORDER BY AnsInd", + QstCod); + } + +/*****************************************************************************/ +/***************** Create new blank exam print in database *******************/ +/*****************************************************************************/ + +long Exa_DB_CreatePrint (const struct ExaPrn_Print *Print) + { + return + DB_QueryINSERTandReturnCode ("can not create new exam print", + "INSERT INTO exa_prints" + " (SesCod,UsrCod,StartTime,EndTime," + "NumQsts,NumQstsNotBlank,Sent,Score)" + " VALUES" + " (%ld,%ld,NOW(),NOW()," + "%u,0,'N',0)", + Print->SesCod, + Print->UsrCod, + Print->NumQsts.All); + } + +/*****************************************************************************/ +/********************** Update exam print in database ************************/ +/*****************************************************************************/ + +void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print) + { + /***** Update exam print in database *****/ + Str_SetDecimalPointToUS (); // To print the floating point as a dot + DB_QueryUPDATE ("can not update exam print", + "UPDATE exa_prints" + " SET EndTime=NOW()," + "NumQstsNotBlank=%u," + "Sent='%c'," + "Score='%.15lg'" + " WHERE PrnCod=%ld" + " AND SesCod=%ld" + " AND UsrCod=%ld", // Extra checks + Print->NumQsts.NotBlank, + Print->Sent ? 'Y' : + 'N', + Print->Score, + Print->PrnCod, + Print->SesCod, + Gbl.Usrs.Me.UsrDat.UsrCod); + Str_SetDecimalPointToLocal (); // Return to local system + } + +/*****************************************************************************/ +/**************** Get data of an exam print using print code *****************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetDataOfPrintByPrnCod (MYSQL_RES **mysql_res,long PrnCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get data of an exam print", + "SELECT PrnCod," // row[0] + "SesCod," // row[1] + "UsrCod," // row[2] + "UNIX_TIMESTAMP(StartTime)," // row[3] + "UNIX_TIMESTAMP(EndTime)," // row[4] + "NumQsts," // row[5] + "NumQstsNotBlank," // row[6] + "Sent," // row[7] + "Score" // row[8] + " FROM exa_prints" + " WHERE PrnCod=%ld", + PrnCod); + } + +/*****************************************************************************/ +/******** Get data of an exam print using session code and user code *********/ +/*****************************************************************************/ + +unsigned Exa_DB_GetDataOfPrintBySesCodAndUsrCod (MYSQL_RES **mysql_res, + long SesCod,long UsrCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get data of an exam print", + "SELECT PrnCod," // row[0] + "SesCod," // row[1] + "UsrCod," // row[2] + "UNIX_TIMESTAMP(StartTime)," // row[3] + "UNIX_TIMESTAMP(EndTime)," // row[4] + "NumQsts," // row[5] + "NumQstsNotBlank," // row[6] + "Sent," // row[7] + "Score" // row[8] + " FROM exa_prints" + " WHERE SesCod=%ld" + " AND UsrCod=%ld", + SesCod, + UsrCod); + } + +/*****************************************************************************/ +/******************* Remove exam prints for a given user *********************/ +/*****************************************************************************/ + +void Exa_DB_RemovePrintsMadeByUsrInAllCrss (long UsrCod) + { + DB_QueryDELETE ("can not remove exam prints made by a user", + "DELETE FROM exa_prints" + " WHERE UsrCod=%ld", + UsrCod); + } + +/*****************************************************************************/ +/*************** Remove exam prints made by a user in a course ***************/ +/*****************************************************************************/ + +void Exa_DB_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod) + { + DB_QueryDELETE ("can not remove exams prints made by a user in a course", + "DELETE FROM exa_prints" + " USING exa_exams," + "exa_sessions," + "exa_prints" + " WHERE exa_exams.CrsCod=%ld" + " AND exa_exams.ExaCod=exa_sessions.ExaCod" + " AND exa_sessions.SesCod=exa_prints.SesCod" + " AND exa_prints.UsrCod=%ld", + CrsCod, + UsrCod); + } + +/*****************************************************************************/ +/******* Remove exams prints made by the given user in the given course ******/ +/*****************************************************************************/ + +void Exa_DB_RemovePrintsInCrs (long CrsCod) + { + DB_QueryDELETE ("can not remove exams prints in a course", + "DELETE FROM exa_prints" + " USING exa_exams," + "exa_sessions," + "exa_prints" + " WHERE exa_exams.CrsCod=%ld" + " AND exa_exams.ExaCod=exa_sessions.ExaCod" + " AND exa_sessions.SesCod=exa_prints.SesCod", + CrsCod); + } + +/*****************************************************************************/ +/************* Store user's answers of an test exam into database ************/ +/*****************************************************************************/ + +void Exa_DB_StoreOneQstOfPrint (const struct ExaPrn_Print *Print, + unsigned QstInd) + { + Str_SetDecimalPointToUS (); // To print the floating point as a dot + DB_QueryREPLACE ("can not update a question in an exam print", + "REPLACE INTO exa_print_questions" + " (PrnCod,QstCod,QstInd,SetCod,Score,Indexes,Answers)" + " VALUES" + " (%ld,%ld,%u,%ld,'%.15lg','%s','%s')", + Print->PrnCod, + Print->PrintedQuestions[QstInd].QstCod, + QstInd, // 0, 1, 2, 3... + Print->PrintedQuestions[QstInd].SetCod, + Print->PrintedQuestions[QstInd].Score, + Print->PrintedQuestions[QstInd].StrIndexes, + Print->PrintedQuestions[QstInd].StrAnswers); + Str_SetDecimalPointToLocal (); // Return to local system + } + +/*****************************************************************************/ +/************* Get the questions of an exam print from database **************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetPrintQuestions (MYSQL_RES **mysql_res,long PrnCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get questions of an exam print", + "SELECT QstCod," // row[0] + "SetCod," // row[1] + "Score," // row[2] + "Indexes," // row[3] + "Answers" // row[4] + " FROM exa_print_questions" + " WHERE PrnCod=%ld" + " ORDER BY QstInd", + PrnCod); + } + +/*****************************************************************************/ +/************** Get the answers of an exam print from database ***************/ +/*****************************************************************************/ + +void Exa_DB_GetAnswersFromQstInPrint (long PrnCod,long QstCod, + char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]) + { + DB_QuerySELECTString (StrAnswers,Tst_MAX_BYTES_ANSWERS_ONE_QST, + "can not get answer in an exam print", + "SELECT Answers" + " FROM exa_print_questions" + " WHERE PrnCod=%ld" + " AND QstCod=%ld", + PrnCod,QstCod); + } + +/*****************************************************************************/ +/************ Get number of questions not blank in an exam print *************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetNumQstsNotBlankInPrint (long PrnCod) + { + return (unsigned) + DB_QueryCOUNT ("can not get number of questions not blank", + "SELECT COUNT(*)" + " FROM exa_print_questions" + " WHERE PrnCod=%ld" + " AND Answers<>''", + PrnCod); + } + +/*****************************************************************************/ +/************* Compute total score of questions of an exam print *************/ +/*****************************************************************************/ + +double Exa_DB_ComputeTotalScoreOfPrint (long PrnCod) + { + return DB_QuerySELECTDouble ("can not get score of exam print", + "SELECT SUM(Score)" + " FROM exa_print_questions" + " WHERE PrnCod=%ld", + PrnCod); + } + +/*****************************************************************************/ +/*************** Remove exam prints questions for a given user ***************/ +/*****************************************************************************/ + +void Exa_DB_RemovePrintQuestionsMadeByUsrInAllCrss (long UsrCod) + { + DB_QueryDELETE ("can not remove exam prints made by a user", + "DELETE FROM exa_print_questions" + " USING exa_prints," + "exa_print_questions" + " WHERE exa_prints.UsrCod=%ld" + " AND exa_prints.PrnCod=exa_print_questions.PrnCod", + UsrCod); + } + +/*****************************************************************************/ +/* Remove questions of exams prints made by the given user in a given course */ +/*****************************************************************************/ + +void Exa_DB_RemovePrintsQuestionsMadeByUsrInCrs (long UsrCod,long CrsCod) + { + DB_QueryDELETE ("can not remove exams prints made by a user in a course", + "DELETE FROM exa_print_questions" + " USING exa_exams," + "exa_sessions," + "exa_prints," + "exa_print_questions" + " WHERE exa_exams.CrsCod=%ld" + " AND exa_exams.ExaCod=exa_sessions.ExaCod" + " AND exa_sessions.SesCod=exa_prints.SesCod" + " AND exa_prints.UsrCod=%ld" + " AND exa_prints.PrnCod=exa_print_questions.PrnCod", + CrsCod, + UsrCod); + } + +/*****************************************************************************/ +/* Remove questions of exams prints made by the given user in a given course */ +/*****************************************************************************/ + +void Exa_DB_RemovePrintQuestionsInCrs (long CrsCod) + { + DB_QueryDELETE ("can not remove exams prints in a course", + "DELETE FROM exa_print_questions" + " USING exa_exams," + "exa_sessions," + "exa_prints," + "exa_print_questions" + " WHERE exa_exams.CrsCod=%ld" + " AND exa_exams.ExaCod=exa_sessions.ExaCod" + " AND exa_sessions.SesCod=exa_prints.SesCod" + " AND exa_prints.PrnCod=exa_print_questions.PrnCod", + CrsCod); + } + /*****************************************************************************/ /******** Check if the current session id is the same as the last one ********/ /*****************************************************************************/ -bool ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod) +bool Exa_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod) { /***** Check if the current session id is the same as the last one stored in database *****/ @@ -83,7 +432,7 @@ bool ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod) /******** Check if the current user agent is the same as the last one ********/ /*****************************************************************************/ -bool ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserAgentDB) +bool Exa_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserAgentDB) { /***** Get if the current user agent is the same as the last stored in database *****/ @@ -103,7 +452,7 @@ bool ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserA /******************************** Log access *********************************/ /*****************************************************************************/ -void ExaLog_DB_LogAccess (long LogCod,long PrnCod,ExaLog_Action_t Action) +void Exa_DB_LogAccess (long LogCod,long PrnCod,ExaLog_Action_t Action) { /* Log access in exam log. Redundant data (also present in log table) are stored for speed */ @@ -126,7 +475,7 @@ void ExaLog_DB_LogAccess (long LogCod,long PrnCod,ExaLog_Action_t Action) /*************************** Log session in database *************************/ /*****************************************************************************/ -void ExaLog_DB_LogSession (long LogCod,long PrnCod) +void Exa_DB_LogSession (long LogCod,long PrnCod) { DB_QueryINSERT ("can not log session", "INSERT INTO exa_log_sessions " @@ -142,7 +491,7 @@ void ExaLog_DB_LogSession (long LogCod,long PrnCod) /************************* Log user agent in database ************************/ /*****************************************************************************/ -void ExaLog_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB) +void Exa_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB) { DB_QueryINSERT ("can not log user agent", "INSERT INTO exa_log_user_agents " @@ -153,3 +502,28 @@ void ExaLog_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB) PrnCod, UserAgentDB); } + +/*****************************************************************************/ +/********************* Get exam print log from database **********************/ +/*****************************************************************************/ + +unsigned Exa_DB_GetExamLog (MYSQL_RES **mysql_res,long PrnCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get exam print log", + "SELECT exa_log.ActCod," // row[0] + "exa_log.QstInd," // row[1] + "exa_log.CanAnswer," // row[2] + "UNIX_TIMESTAMP(exa_log.ClickTime)," // row[3] + "exa_log.IP," // row[4] + "exa_log_sessions.SessionId," // row[5] + "exa_log_user_agents.UserAgent" // row[6] + " FROM exa_log" + " LEFT JOIN exa_log_sessions" + " ON exa_log.LogCod=exa_log_sessions.LogCod" + " LEFT JOIN exa_log_user_agents" + " ON exa_log.LogCod=exa_log_user_agents.LogCod" + " WHERE exa_log.PrnCod=%ld" + " ORDER BY exa_log.LogCod", + PrnCod); + } diff --git a/swad_exam_database.h b/swad_exam_database.h index ae2b6f6c..947f7b3d 100644 --- a/swad_exam_database.h +++ b/swad_exam_database.h @@ -28,7 +28,8 @@ /*****************************************************************************/ #include "swad_exam_log.h" -// #include "swad_exam_print.h" +#include "swad_exam_print.h" +#include "swad_test_type.h" /*****************************************************************************/ /************************* Public types and constants ************************/ @@ -38,11 +39,39 @@ /***************************** Public prototypes *****************************/ /*****************************************************************************/ -bool ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod); -bool ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserAgentDB); +unsigned Exa_DB_GetExamSets (MYSQL_RES **mysql_res,long ExaCod); +unsigned Exa_DB_GetSomeQstsFromSetToPrint (MYSQL_RES **mysql_res, + long SetCod,unsigned NumQstsToPrint); +unsigned Exa_DB_GetQstAnswersTextFromSet (MYSQL_RES **mysql_res,long QstCod); +unsigned Exa_DB_GetQstAnswersCorrFromSet (MYSQL_RES **mysql_res,long QstCod); -void ExaLog_DB_LogAccess (long LogCod,long PrnCod,ExaLog_Action_t Action); -void ExaLog_DB_LogSession (long LogCod,long PrnCod); -void ExaLog_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB); +long Exa_DB_CreatePrint (const struct ExaPrn_Print *Print); +void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print); +unsigned Exa_DB_GetDataOfPrintByPrnCod (MYSQL_RES **mysql_res,long PrnCod); +unsigned Exa_DB_GetDataOfPrintBySesCodAndUsrCod (MYSQL_RES **mysql_res, + long SesCod,long UsrCod); +void Exa_DB_RemovePrintsMadeByUsrInAllCrss (long UsrCod); +void Exa_DB_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod); +void Exa_DB_RemovePrintsInCrs (long CrsCod); + +void Exa_DB_StoreOneQstOfPrint (const struct ExaPrn_Print *Print, + unsigned QstInd); +unsigned Exa_DB_GetPrintQuestions (MYSQL_RES **mysql_res,long PrnCod); +void Exa_DB_GetAnswersFromQstInPrint (long PrnCod,long QstCod, + char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]); +unsigned Exa_DB_GetNumQstsNotBlankInPrint (long PrnCod); +double Exa_DB_ComputeTotalScoreOfPrint (long PrnCod); +void Exa_DB_RemovePrintQuestionsMadeByUsrInAllCrss (long UsrCod); +void Exa_DB_RemovePrintsQuestionsMadeByUsrInCrs (long UsrCod,long CrsCod); +void Exa_DB_RemovePrintQuestionsInCrs (long CrsCod); + +bool Exa_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod); +bool Exa_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserAgentDB); + +void Exa_DB_LogAccess (long LogCod,long PrnCod,ExaLog_Action_t Action); +void Exa_DB_LogSession (long LogCod,long PrnCod); +void Exa_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB); + +unsigned Exa_DB_GetExamLog (MYSQL_RES **mysql_res,long PrnCod); #endif diff --git a/swad_exam_log.c b/swad_exam_log.c index 8e38cda5..af083cd5 100644 --- a/swad_exam_log.c +++ b/swad_exam_log.c @@ -151,7 +151,7 @@ void ExaLog_LogAccess (long LogCod) /***** Insert access into database *****/ /* Log access in exam log. Redundant data (also present in log table) are stored for speed */ - ExaLog_DB_LogAccess (LogCod,PrnCod,Action); + Exa_DB_LogAccess (LogCod,PrnCod,Action); /***** Log session and user agent *****/ ExaLog_LogSession (LogCod,PrnCod); @@ -168,8 +168,8 @@ static void ExaLog_LogSession (long LogCod,long PrnCod) { /***** Insert session id into database only if it's not the same as the last one stored *****/ - if (!ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (PrnCod)) - ExaLog_DB_LogSession (LogCod,PrnCod); + if (!Exa_DB_CheckIfSessionIsTheSameAsTheLast (PrnCod)) + Exa_DB_LogSession (LogCod,PrnCod); } /*****************************************************************************/ @@ -209,8 +209,8 @@ static void ExaLog_LogUsrAgent (long LogCod,long PrnCod) /***** Insert user agent into database only if it's not the same as the last one stored *****/ - if (!ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (PrnCod,UserAgentDB)) - ExaLog_DB_LogUserAgent (LogCod,PrnCod,UserAgentDB); + if (!Exa_DB_CheckIfUserAgentIsTheSameAsTheLast (PrnCod,UserAgentDB)) + Exa_DB_LogUserAgent (LogCod,PrnCod,UserAgentDB); /***** Free user agent *****/ free (UserAgentDB); @@ -251,25 +251,7 @@ void ExaLog_ShowExamLog (const struct ExaPrn_Print *Print) const char *Class; /***** Get print log from database *****/ - NumClicks = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get exam print log", - "SELECT exa_log.ActCod," // row[0] - "exa_log.QstInd," // row[1] - "exa_log.CanAnswer," // row[2] - "UNIX_TIMESTAMP(exa_log.ClickTime)," // row[3] - "exa_log.IP," // row[4] - "exa_log_sessions.SessionId," // row[5] - "exa_log_user_agents.UserAgent" // row[6] - " FROM exa_log" - " LEFT JOIN exa_log_sessions" - " ON exa_log.LogCod=exa_log_sessions.LogCod" - " LEFT JOIN exa_log_user_agents" - " ON exa_log.LogCod=exa_log_user_agents.LogCod" - " WHERE exa_log.PrnCod=%ld" - " ORDER BY exa_log.LogCod", - Print->PrnCod); - - if (NumClicks) + if ((NumClicks = Exa_DB_GetExamLog (&mysql_res,Print->PrnCod))) { /***** Initialize last session id and last user agent ******/ SessionId[0] = '\0'; diff --git a/swad_exam_print.c b/swad_exam_print.c index a0a65d76..bbabde23 100644 --- a/swad_exam_print.c +++ b/swad_exam_print.c @@ -35,6 +35,7 @@ #include "swad_database.h" #include "swad_error.h" #include "swad_exam.h" +#include "swad_exam_database.h" #include "swad_exam_log.h" #include "swad_exam_print.h" #include "swad_exam_result.h" @@ -75,10 +76,10 @@ static void ExaPrn_GetDataOfPrint (struct ExaPrn_Print *Print, static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,long ExaCod); static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, struct ExaSet_Set *Set, - unsigned *NumQstInPrint); + unsigned *NumQstsInPrint); static void ExaPrn_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *PrintedQuestion, bool Shuffle); -static void ExaPrn_CreatePrintInDB (struct ExaPrn_Print *Print); +static void ExaPrn_CreatePrint (struct ExaPrn_Print *Print); static void ExaPrn_ShowExamPrintToFillIt (struct Exa_Exams *Exams, const struct Exa_Exam *Exam, @@ -141,15 +142,6 @@ static void ExaPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question); static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question); //----------------------------------------------------------------------------- -static void ExaPrn_GetAnswerFromDB (struct ExaPrn_Print *Print,long QstCod, - char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]); -static void ExaPrn_StoreOneQstOfPrintInDB (const struct ExaPrn_Print *Print, - unsigned QstInd); - -static unsigned Exa_DB_GetNumQstsNotBlankInPrint (long PrnCod); -static double Exa_DB_ComputeTotalScoreOfPrint (long PrnCod); -static void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print); - /*****************************************************************************/ /**************************** Reset exam print *******************************/ /*****************************************************************************/ @@ -216,7 +208,7 @@ void ExaPrn_ShowExamPrint (void) if (Print.NumQsts.All) { /***** Create new exam print in database *****/ - ExaPrn_CreatePrintInDB (&Print); + ExaPrn_CreatePrint (&Print); /***** Set log print code and action *****/ ExaLog_SetPrnCod (Print.PrnCod); @@ -256,20 +248,7 @@ void ExaPrn_GetDataOfPrintByPrnCod (struct ExaPrn_Print *Print) unsigned NumPrints; /***** Make database query *****/ - NumPrints = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get data of an exam print", - "SELECT PrnCod," // row[0] - "SesCod," // row[1] - "UsrCod," // row[2] - "UNIX_TIMESTAMP(StartTime)," // row[3] - "UNIX_TIMESTAMP(EndTime)," // row[4] - "NumQsts," // row[5] - "NumQstsNotBlank," // row[6] - "Sent," // row[7] - "Score" // row[8] - " FROM exa_prints" - " WHERE PrnCod=%ld", - Print->PrnCod); + NumPrints = Exa_DB_GetDataOfPrintByPrnCod (&mysql_res,Print->PrnCod); /***** Get data of print *****/ ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints); @@ -285,22 +264,9 @@ void ExaPrn_GetDataOfPrintBySesCodAndUsrCod (struct ExaPrn_Print *Print) unsigned NumPrints; /***** Make database query *****/ - NumPrints = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get data of an exam print", - "SELECT PrnCod," // row[0] - "SesCod," // row[1] - "UsrCod," // row[2] - "UNIX_TIMESTAMP(StartTime)," // row[3] - "UNIX_TIMESTAMP(EndTime)," // row[4] - "NumQsts," // row[5] - "NumQstsNotBlank," // row[6] - "Sent," // row[7] - "Score" // row[8] - " FROM exa_prints" - " WHERE SesCod=%ld" - " AND UsrCod=%ld", - Print->SesCod, - Print->UsrCod); + NumPrints = Exa_DB_GetDataOfPrintBySesCodAndUsrCod (&mysql_res, + Print->SesCod, + Print->UsrCod); /***** Get data of print *****/ ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints); @@ -369,22 +335,11 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,lon unsigned NumSet; struct ExaSet_Set Set; unsigned NumQstsFromSet; - unsigned NumQstInPrint = 0; - - /***** Get data of set of questions from database *****/ - NumSets = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get sets of questions", - "SELECT SetCod," // row[0] - "NumQstsToPrint," // row[1] - "Title" // row[2] - " FROM exa_sets" - " WHERE ExaCod=%ld" - " ORDER BY SetInd", - ExaCod); + unsigned NumQstsInPrint = 0; /***** Get questions from all sets *****/ Print->NumQsts.All = 0; - if (NumSets) + if ((NumSets = Exa_DB_GetExamSets (&mysql_res,ExaCod))) /***** For each set in exam... *****/ for (NumSet = 0; NumSet < NumSets; @@ -400,22 +355,21 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,lon row[1] NumQstsToPrint row[2] Title */ - /* Get set code (row[0]) */ - Set.SetCod = Str_ConvertStrCodToLongCod (row[0]); - - /* Get set index (row[1]) */ + /* Get set code (row[0]) + and set index (row[1]) */ + Set.SetCod = Str_ConvertStrCodToLongCod (row[0]); Set.NumQstsToPrint = Str_ConvertStrToUnsigned (row[1]); /* Get the title of the set (row[2]) */ Str_Copy (Set.Title,row[2],sizeof (Set.Title) - 1); /***** Questions in this set *****/ - NumQstsFromSet = ExaPrn_GetSomeQstsFromSetToPrint (Print,&Set,&NumQstInPrint); + NumQstsFromSet = ExaPrn_GetSomeQstsFromSetToPrint (Print,&Set,&NumQstsInPrint); Print->NumQsts.All += NumQstsFromSet; } /***** Check *****/ - if (Print->NumQsts.All != NumQstInPrint) + if (Print->NumQsts.All != NumQstsInPrint) Err_ShowErrorAndExit ("Wrong number of questions."); /***** Free structure that stores the query result *****/ @@ -423,12 +377,12 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,lon } /*****************************************************************************/ -/************************ Show questions from a set **************************/ +/********************** Get some questions from a set ************************/ /*****************************************************************************/ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, struct ExaSet_Set *Set, - unsigned *NumQstInPrint) + unsigned *NumQstsInPrint) { MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -438,22 +392,14 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, bool Shuffle; /***** Get questions from database *****/ - NumQstsInSet = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get questions from set", - "SELECT QstCod," // row[0] - "AnsType," // row[1] - "Shuffle" // row[2] - " FROM exa_set_questions" - " WHERE SetCod=%ld" - " ORDER BY RAND()" // Don't use RAND(NOW()) because the same ordering will be repeated across sets - " LIMIT %u", - Set->SetCod, - Set->NumQstsToPrint); + NumQstsInSet = Exa_DB_GetSomeQstsFromSetToPrint (&mysql_res, + Set->SetCod, + Set->NumQstsToPrint); /***** Questions in this set *****/ for (NumQstInSet = 0; NumQstInSet < NumQstsInSet; - NumQstInSet++, (*NumQstInPrint)++) + NumQstInSet++, (*NumQstsInPrint)++) { Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; @@ -466,10 +412,10 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, */ /* Get question code (row[0]) */ - Print->PrintedQuestions[*NumQstInPrint].QstCod = Str_ConvertStrCodToLongCod (row[0]); + Print->PrintedQuestions[*NumQstsInPrint].QstCod = Str_ConvertStrCodToLongCod (row[0]); /* Set set of questions */ - Print->PrintedQuestions[*NumQstInPrint].SetCod = Set->SetCod; + Print->PrintedQuestions[*NumQstsInPrint].SetCod = Set->SetCod; /* Get answer type (row[1]) */ AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); @@ -484,13 +430,13 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, case Tst_ANS_FLOAT: case Tst_ANS_TRUE_FALSE: case Tst_ANS_TEXT: - Print->PrintedQuestions[*NumQstInPrint].StrIndexes[0] = '\0'; + Print->PrintedQuestions[*NumQstsInPrint].StrIndexes[0] = '\0'; break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: /* If answer type is unique or multiple option, generate indexes of answers depending on shuffle */ - ExaPrn_GenerateChoiceIndexes (&Print->PrintedQuestions[*NumQstInPrint],Shuffle); + ExaPrn_GenerateChoiceIndexes (&Print->PrintedQuestions[*NumQstsInPrint],Shuffle); break; default: break; @@ -500,10 +446,10 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, Initially user has not answered the question ==> initially all the answers will be blank. If the user does not confirm the submission of their exam ==> ==> the exam may be half filled ==> the answers displayed will be those selected by the user. */ - Print->PrintedQuestions[*NumQstInPrint].StrAnswers[0] = '\0'; + Print->PrintedQuestions[*NumQstsInPrint].StrAnswers[0] = '\0'; /* Reset score of this question in print */ - Print->PrintedQuestions[*NumQstInPrint].Score = 0.0; + Print->PrintedQuestions[*NumQstsInPrint].Score = 0.0; } return NumQstsInSet; @@ -578,29 +524,19 @@ static void ExaPrn_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *Printed /***************** Create new blank exam print in database *******************/ /*****************************************************************************/ -static void ExaPrn_CreatePrintInDB (struct ExaPrn_Print *Print) +static void ExaPrn_CreatePrint (struct ExaPrn_Print *Print) { unsigned QstInd; - /***** Insert new exam print into table *****/ - Print->PrnCod = - DB_QueryINSERTandReturnCode ("can not create new exam print", - "INSERT INTO exa_prints" - " (SesCod,UsrCod,StartTime,EndTime," - "NumQsts,NumQstsNotBlank,Sent,Score)" - " VALUES" - " (%ld,%ld,NOW(),NOW()," - "%u,0,'N',0)", - Print->SesCod, - Print->UsrCod, - Print->NumQsts.All); + /***** Insert new exam print into database *****/ + Print->PrnCod = Exa_DB_CreatePrint (Print); /***** Store all questions (with blank answers) of this exam print just generated in database *****/ for (QstInd = 0; QstInd < Print->NumQsts.All; QstInd++) - ExaPrn_StoreOneQstOfPrintInDB (Print,QstInd); + Exa_DB_StoreOneQstOfPrint (Print,QstInd); } /*****************************************************************************/ @@ -614,31 +550,18 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print) unsigned QstInd; /***** Get questions of an exam print from database *****/ - Print->NumQsts.All = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get questions of an exam print", - "SELECT QstCod," // row[0] - "SetCod," // row[1] - "Score," // row[2] - "Indexes," // row[3] - "Answers" // row[4] - " FROM exa_print_questions" - " WHERE PrnCod=%ld" - " ORDER BY QstInd", - Print->PrnCod); - - /***** Get questions *****/ - if (Print->NumQsts.All <= ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT) + if ((Print->NumQsts.All = Exa_DB_GetPrintQuestions (&mysql_res,Print->PrnCod)) + <= ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT) for (QstInd = 0; QstInd < Print->NumQsts.All; QstInd++) { row = mysql_fetch_row (mysql_res); - /* Get question code (row[0]) */ + /* Get question code (row[0]) + and set code (row[1]) */ if ((Print->PrintedQuestions[QstInd].QstCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) Err_WrongQuestionExit (); - - /* Get set code (row[1]) */ if ((Print->PrintedQuestions[QstInd].SetCod = Str_ConvertStrCodToLongCod (row[1])) <= 0) Err_WrongSetExit (); @@ -648,11 +571,10 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print) Err_ShowErrorAndExit ("Wrong question score."); Str_SetDecimalPointToLocal (); // Return to local system - /* Get indexes for this question (row[3]) */ + /* Get indexes for this question (row[3]) + and answers selected by user for this question (row[4]) */ Str_Copy (Print->PrintedQuestions[QstInd].StrIndexes,row[3], sizeof (Print->PrintedQuestions[QstInd].StrIndexes) - 1); - - /* Get answers selected by user for this question (row[4]) */ Str_Copy (Print->PrintedQuestions[QstInd].StrAnswers,row[4], sizeof (Print->PrintedQuestions[QstInd].StrAnswers) - 1); } @@ -914,9 +836,9 @@ static void ExaPrn_WriteTF_AnsToFill (const struct ExaPrn_Print *Print, HTM_TxtF (""); } @@ -953,37 +875,37 @@ static void ExaPrn_WriteChoAnsToFill (const struct ExaPrn_Print *Print, or 3 1 0 2... (example) if shuffle *****/ HTM_TR_Begin (NULL); - /***** Write selectors and letter of this option *****/ - /* Initially user has not answered the question ==> initially all the answers will be blank. - If the user does not confirm the submission of their exam ==> - ==> the exam may be half filled ==> the answers displayed will be those selected by the user. */ - HTM_TD_Begin ("class=\"LT\""); - snprintf (Id,sizeof (Id),"Ans%010u",QstInd); - HTM_TxtF ("Answer.Type == Tst_ANS_UNIQUE_CHOICE ? "radio" : - "checkbox", - Id,NumOpt,Indexes[NumOpt], - UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" : - ""); - ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,(int) NumOpt); - HTM_Txt (" />"); - HTM_TD_End (); + /***** Write selectors and letter of this option *****/ + /* Initially user has not answered the question ==> initially all the answers will be blank. + If the user does not confirm the submission of their exam ==> + ==> the exam may be half filled ==> the answers displayed will be those selected by the user. */ + HTM_TD_Begin ("class=\"LT\""); + snprintf (Id,sizeof (Id),"Ans%010u",QstInd); + HTM_TxtF ("Answer.Type == Tst_ANS_UNIQUE_CHOICE ? "radio" : + "checkbox", + Id,NumOpt,Indexes[NumOpt], + UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" : + ""); + ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,(int) NumOpt); + HTM_Txt (" />"); + HTM_TD_End (); - HTM_TD_Begin ("class=\"LT\""); - HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt); - HTM_TxtF ("%c) ",'a' + (char) NumOpt); - HTM_LABEL_End (); - HTM_TD_End (); + HTM_TD_Begin ("class=\"LT\""); + HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt); + HTM_TxtF ("%c) ",'a' + (char) NumOpt); + HTM_LABEL_End (); + HTM_TD_End (); - /***** Write the option text *****/ - HTM_TD_Begin ("class=\"LT\""); - HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt); - HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text); - HTM_LABEL_End (); - Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media, - "TEST_MED_SHOW_CONT", - "TEST_MED_SHOW"); - HTM_TD_End (); + /***** Write the option text *****/ + HTM_TD_Begin ("class=\"LT\""); + HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt); + HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text); + HTM_LABEL_End (); + Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media, + "TEST_MED_SHOW_CONT", + "TEST_MED_SHOW"); + HTM_TD_End (); HTM_TR_End (); } @@ -1009,7 +931,6 @@ static void ExaPrn_WriteTxtAnsToFill (const struct ExaPrn_Print *Print, Id,Tst_MAX_CHARS_ANSWERS_ONE_QST, Print->PrintedQuestions[QstInd].StrAnswers); ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,-1); - HTM_Txt (" />"); } @@ -1174,8 +1095,8 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri ==> uncheck it by deleting answer *****/ if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE) { - ExaPrn_GetAnswerFromDB (Print,Print->PrintedQuestions[QstInd].QstCod, - CurrentStrAnswersInDB); + Exa_DB_GetAnswersFromQstInPrint (Print->PrnCod,Print->PrintedQuestions[QstInd].QstCod, + CurrentStrAnswersInDB); if (!strcmp (Print->PrintedQuestions[QstInd].StrAnswers,CurrentStrAnswersInDB)) { /* The answer just clicked by user @@ -1186,8 +1107,8 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri } /***** Store test exam question in database *****/ - ExaPrn_StoreOneQstOfPrintInDB (Print, - QstInd); // 0, 1, 2, 3... + Exa_DB_StoreOneQstOfPrint (Print, + QstInd); // 0, 1, 2, 3... } /*****************************************************************************/ @@ -1271,12 +1192,7 @@ static void ExaPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question) MYSQL_ROW row; /***** Query database *****/ - Question->Answer.NumOptions = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get answers of a question", - "SELECT Answer" // row[0] - " FROM exa_set_answers" - " WHERE QstCod=%ld", - Question->QstCod); + Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod); /***** Check if number of rows is correct *****/ Tst_CheckIfNumberOfAnswersIsOne (Question); @@ -1298,12 +1214,7 @@ static void ExaPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question) double Tmp; /***** Query database *****/ - Question->Answer.NumOptions = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get answers of a question", - "SELECT Answer" // row[0] - " FROM exa_set_answers" - " WHERE QstCod=%ld", - Question->QstCod); + Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod); /***** Check if number of rows is correct *****/ if (Question->Answer.NumOptions != 2) @@ -1336,12 +1247,7 @@ static void ExaPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question) MYSQL_ROW row; /***** Query database *****/ - Question->Answer.NumOptions = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get answers of a question", - "SELECT Answer" // row[0] - " FROM exa_set_answers" - " WHERE QstCod=%ld", - Question->QstCod); + Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod); /***** Check if number of rows is correct *****/ Tst_CheckIfNumberOfAnswersIsOne (Question); @@ -1361,13 +1267,7 @@ static void ExaPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question) unsigned NumOpt; /***** Query database *****/ - Question->Answer.NumOptions = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get answers of a question", - "SELECT Correct" // row[0] - " FROM exa_set_answers" - " WHERE QstCod=%ld" - " ORDER BY AnsInd", - Question->QstCod); + Question->Answer.NumOptions = Exa_DB_GetQstAnswersCorrFromSet (&mysql_res,Question->QstCod); for (NumOpt = 0; NumOpt < Question->Answer.NumOptions; NumOpt++) @@ -1390,12 +1290,7 @@ static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question) unsigned NumOpt; /***** Query database *****/ - Question->Answer.NumOptions = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get answers of a question", - "SELECT Answer" // row[0] - " FROM exa_set_answers" - " WHERE QstCod=%ld", - Question->QstCod); + Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod); /***** Get text and correctness of answers for this question from database (one row per answer) *****/ for (NumOpt = 0; @@ -1422,115 +1317,6 @@ static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question) DB_FreeMySQLResult (&mysql_res); } -/*****************************************************************************/ -/************* Get the questions of an exam print from database **************/ -/*****************************************************************************/ - -static void ExaPrn_GetAnswerFromDB (struct ExaPrn_Print *Print,long QstCod, - char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - - /***** Get questions of an exam print from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get answer in an exam print", - "SELECT Answers" // row[0] - " FROM exa_print_questions" - " WHERE PrnCod=%ld" - " AND QstCod=%ld", - Print->PrnCod,QstCod)) - { - row = mysql_fetch_row (mysql_res); - - /* Get answers selected by user for this question (row[0]) */ - Str_Copy (StrAnswers,row[0],strlen (StrAnswers) - 1); - } - else - StrAnswers[0] = '\0'; - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - } - -/*****************************************************************************/ -/************* Store user's answers of an test exam into database ************/ -/*****************************************************************************/ - -static void ExaPrn_StoreOneQstOfPrintInDB (const struct ExaPrn_Print *Print, - unsigned QstInd) - { - /***** Insert question and user's answers into database *****/ - Str_SetDecimalPointToUS (); // To print the floating point as a dot - DB_QueryREPLACE ("can not update a question in an exam print", - "REPLACE INTO exa_print_questions" - " (PrnCod,QstCod,QstInd,SetCod,Score,Indexes,Answers)" - " VALUES" - " (%ld,%ld,%u,%ld,'%.15lg','%s','%s')", - Print->PrnCod, - Print->PrintedQuestions[QstInd].QstCod, - QstInd, // 0, 1, 2, 3... - Print->PrintedQuestions[QstInd].SetCod, - Print->PrintedQuestions[QstInd].Score, - Print->PrintedQuestions[QstInd].StrIndexes, - Print->PrintedQuestions[QstInd].StrAnswers); - Str_SetDecimalPointToLocal (); // Return to local system - } - -/*****************************************************************************/ -/************ Get number of questions not blank in an exam print *************/ -/*****************************************************************************/ - -static unsigned Exa_DB_GetNumQstsNotBlankInPrint (long PrnCod) - { - return (unsigned) - DB_QueryCOUNT ("can not get number of questions not blank", - "SELECT COUNT(*)" - " FROM exa_print_questions" - " WHERE PrnCod=%ld" - " AND Answers<>''", - PrnCod); - } - -/*****************************************************************************/ -/************* Compute total score of questions of an exam print *************/ -/*****************************************************************************/ - -static double Exa_DB_ComputeTotalScoreOfPrint (long PrnCod) - { - return DB_QuerySELECTDouble ("can not get score of exam print", - "SELECT SUM(Score)" - " FROM exa_print_questions" - " WHERE PrnCod=%ld", - PrnCod); - } - -/*****************************************************************************/ -/********************** Update exam print in database ************************/ -/*****************************************************************************/ - -static void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print) - { - /***** Update exam print in database *****/ - Str_SetDecimalPointToUS (); // To print the floating point as a dot - DB_QueryUPDATE ("can not update exam print", - "UPDATE exa_prints" - " SET EndTime=NOW()," - "NumQstsNotBlank=%u," - "Sent='%c'," - "Score='%.15lg'" - " WHERE PrnCod=%ld" - " AND SesCod=%ld" - " AND UsrCod=%ld", // Extra checks - Print->NumQsts.NotBlank, - Print->Sent ? 'Y' : - 'N', - Print->Score, - Print->PrnCod, - Print->SesCod, - Gbl.Usrs.Me.UsrDat.UsrCod); - Str_SetDecimalPointToLocal (); // Return to local system - } - /*****************************************************************************/ /********************** Remove exam prints made by a user ********************/ /*****************************************************************************/ @@ -1538,19 +1324,10 @@ static void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print) void ExaPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod) { /***** Remove exam prints questions for the given user *****/ - DB_QueryDELETE ("can not remove exam prints made by a user", - "DELETE FROM exa_print_questions" - " USING exa_prints," - "exa_print_questions" - " WHERE exa_prints.UsrCod=%ld" - " AND exa_prints.PrnCod=exa_print_questions.PrnCod", - UsrCod); + Exa_DB_RemovePrintQuestionsMadeByUsrInAllCrss (UsrCod); /***** Remove exam prints made by the given user *****/ - DB_QueryDELETE ("can not remove exam prints made by a user", - "DELETE FROM exa_prints" - " WHERE UsrCod=%ld", - UsrCod); + Exa_DB_RemovePrintsMadeByUsrInAllCrss (UsrCod); } /*****************************************************************************/ @@ -1560,32 +1337,10 @@ void ExaPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod) void ExaPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod) { /***** Remove questions of exams prints made by the given user in the given course *****/ - DB_QueryDELETE ("can not remove exams prints made by a user in a course", - "DELETE FROM exa_print_questions" - " USING exa_exams," - "exa_sessions," - "exa_prints," - "exa_print_questions" - " WHERE exa_exams.CrsCod=%ld" - " AND exa_exams.ExaCod=exa_sessions.ExaCod" - " AND exa_sessions.SesCod=exa_prints.SesCod" - " AND exa_prints.UsrCod=%ld" - " AND exa_prints.PrnCod=exa_print_questions.PrnCod", - CrsCod, - UsrCod); + Exa_DB_RemovePrintsQuestionsMadeByUsrInCrs (UsrCod,CrsCod); /***** Remove exams prints made by the given user in the given course *****/ - DB_QueryDELETE ("can not remove exams prints made by a user in a course", - "DELETE FROM exa_prints" - " USING exa_exams," - "exa_sessions," - "exa_prints" - " WHERE exa_exams.CrsCod=%ld" - " AND exa_exams.ExaCod=exa_sessions.ExaCod" - " AND exa_sessions.SesCod=exa_prints.SesCod" - " AND exa_prints.UsrCod=%ld", - CrsCod, - UsrCod); + Exa_DB_RemovePrintsMadeByUsrInCrs (UsrCod,CrsCod); } /*****************************************************************************/ @@ -1595,26 +1350,8 @@ void ExaPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod) void ExaPrn_RemoveCrsPrints (long CrsCod) { /***** Remove questions of exams prints made by the given user in the given course *****/ - DB_QueryDELETE ("can not remove exams prints in a course", - "DELETE FROM exa_print_questions" - " USING exa_exams," - "exa_sessions," - "exa_prints," - "exa_print_questions" - " WHERE exa_exams.CrsCod=%ld" - " AND exa_exams.ExaCod=exa_sessions.ExaCod" - " AND exa_sessions.SesCod=exa_prints.SesCod" - " AND exa_prints.PrnCod=exa_print_questions.PrnCod", - CrsCod); + Exa_DB_RemovePrintQuestionsInCrs (CrsCod); /***** Remove exams prints made by the given user in the given course *****/ - DB_QueryDELETE ("can not remove exams prints in a course", - "DELETE FROM exa_prints" - " USING exa_exams," - "exa_sessions," - "exa_prints" - " WHERE exa_exams.CrsCod=%ld" - " AND exa_exams.ExaCod=exa_sessions.ExaCod" - " AND exa_sessions.SesCod=exa_prints.SesCod", - CrsCod); + Exa_DB_RemovePrintsInCrs (CrsCod); }