mirror of
https://github.com/acanas/swad-core.git
synced 2024-06-05 16:25:29 +02:00
Version 20.95.1: Jul 15, 2021 Queries moved to module swad_exam_database.
This commit is contained in:
parent
0866392160
commit
c44e6be88a
|
@ -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.
|
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 CSS_FILE "swad20.45.css"
|
||||||
#define JS_FILE "swad20.69.1.js"
|
#define JS_FILE "swad20.69.1.js"
|
||||||
/*
|
/*
|
||||||
TODO: Rename CENTRE to CENTER in help wiki.
|
TODO: Rename CENTRE to CENTER in help wiki.
|
||||||
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
|
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.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.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)
|
Version 20.94.9: Jun 29, 2021 Query moved from module swad_menu to module swad_setting. (313848 lines)
|
||||||
|
|
|
@ -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'
|
// StrSize does not include the ending byte '\0'
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
//#include "swad_error.h"
|
//#include "swad_error.h"
|
||||||
#include "swad_exam_database.h"
|
#include "swad_exam_database.h"
|
||||||
#include "swad_exam_log.h"
|
#include "swad_exam_log.h"
|
||||||
|
#include "swad_exam_print.h"
|
||||||
#include "swad_global.h"
|
#include "swad_global.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -59,11 +60,359 @@ extern struct Globals Gbl;
|
||||||
/***************************** Private prototypes ****************************/
|
/***************************** 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 ********/
|
/******** 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
|
/***** Check if the current session id
|
||||||
is the same as the last one stored in database *****/
|
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 ********/
|
/******** 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
|
/***** Get if the current user agent
|
||||||
is the same as the last stored in database *****/
|
is the same as the last stored in database *****/
|
||||||
|
@ -103,7 +452,7 @@ bool ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserA
|
||||||
/******************************** Log access *********************************/
|
/******************************** 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.
|
/* Log access in exam log.
|
||||||
Redundant data (also present in log table) are stored for speed */
|
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 *************************/
|
/*************************** 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",
|
DB_QueryINSERT ("can not log session",
|
||||||
"INSERT INTO exa_log_sessions "
|
"INSERT INTO exa_log_sessions "
|
||||||
|
@ -142,7 +491,7 @@ void ExaLog_DB_LogSession (long LogCod,long PrnCod)
|
||||||
/************************* Log user agent in database ************************/
|
/************************* 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",
|
DB_QueryINSERT ("can not log user agent",
|
||||||
"INSERT INTO exa_log_user_agents "
|
"INSERT INTO exa_log_user_agents "
|
||||||
|
@ -153,3 +502,28 @@ void ExaLog_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB)
|
||||||
PrnCod,
|
PrnCod,
|
||||||
UserAgentDB);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include "swad_exam_log.h"
|
#include "swad_exam_log.h"
|
||||||
// #include "swad_exam_print.h"
|
#include "swad_exam_print.h"
|
||||||
|
#include "swad_test_type.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/************************* Public types and constants ************************/
|
/************************* Public types and constants ************************/
|
||||||
|
@ -38,11 +39,39 @@
|
||||||
/***************************** Public prototypes *****************************/
|
/***************************** Public prototypes *****************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
bool ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (long PrnCod);
|
unsigned Exa_DB_GetExamSets (MYSQL_RES **mysql_res,long ExaCod);
|
||||||
bool ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (long PrnCod,const char *UserAgentDB);
|
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);
|
long Exa_DB_CreatePrint (const struct ExaPrn_Print *Print);
|
||||||
void ExaLog_DB_LogSession (long LogCod,long PrnCod);
|
void Exa_DB_UpdatePrint (const struct ExaPrn_Print *Print);
|
||||||
void ExaLog_DB_LogUserAgent (long LogCod,long PrnCod,const char *UserAgentDB);
|
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
|
#endif
|
||||||
|
|
|
@ -151,7 +151,7 @@ void ExaLog_LogAccess (long LogCod)
|
||||||
/***** Insert access into database *****/
|
/***** Insert access into database *****/
|
||||||
/* Log access in exam log.
|
/* Log access in exam log.
|
||||||
Redundant data (also present in log table) are stored for speed */
|
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 *****/
|
/***** Log session and user agent *****/
|
||||||
ExaLog_LogSession (LogCod,PrnCod);
|
ExaLog_LogSession (LogCod,PrnCod);
|
||||||
|
@ -168,8 +168,8 @@ static void ExaLog_LogSession (long LogCod,long PrnCod)
|
||||||
{
|
{
|
||||||
/***** Insert session id into database
|
/***** Insert session id into database
|
||||||
only if it's not the same as the last one stored *****/
|
only if it's not the same as the last one stored *****/
|
||||||
if (!ExaLog_DB_CheckIfSessionIsTheSameAsTheLast (PrnCod))
|
if (!Exa_DB_CheckIfSessionIsTheSameAsTheLast (PrnCod))
|
||||||
ExaLog_DB_LogSession (LogCod,PrnCod);
|
Exa_DB_LogSession (LogCod,PrnCod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -209,8 +209,8 @@ static void ExaLog_LogUsrAgent (long LogCod,long PrnCod)
|
||||||
|
|
||||||
/***** Insert user agent into database
|
/***** Insert user agent into database
|
||||||
only if it's not the same as the last one stored *****/
|
only if it's not the same as the last one stored *****/
|
||||||
if (!ExaLog_DB_CheckIfUserAgentIsTheSameAsTheLast (PrnCod,UserAgentDB))
|
if (!Exa_DB_CheckIfUserAgentIsTheSameAsTheLast (PrnCod,UserAgentDB))
|
||||||
ExaLog_DB_LogUserAgent (LogCod,PrnCod,UserAgentDB);
|
Exa_DB_LogUserAgent (LogCod,PrnCod,UserAgentDB);
|
||||||
|
|
||||||
/***** Free user agent *****/
|
/***** Free user agent *****/
|
||||||
free (UserAgentDB);
|
free (UserAgentDB);
|
||||||
|
@ -251,25 +251,7 @@ void ExaLog_ShowExamLog (const struct ExaPrn_Print *Print)
|
||||||
const char *Class;
|
const char *Class;
|
||||||
|
|
||||||
/***** Get print log from database *****/
|
/***** Get print log from database *****/
|
||||||
NumClicks = (unsigned)
|
if ((NumClicks = Exa_DB_GetExamLog (&mysql_res,Print->PrnCod)))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
/***** Initialize last session id and last user agent ******/
|
/***** Initialize last session id and last user agent ******/
|
||||||
SessionId[0] = '\0';
|
SessionId[0] = '\0';
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "swad_database.h"
|
#include "swad_database.h"
|
||||||
#include "swad_error.h"
|
#include "swad_error.h"
|
||||||
#include "swad_exam.h"
|
#include "swad_exam.h"
|
||||||
|
#include "swad_exam_database.h"
|
||||||
#include "swad_exam_log.h"
|
#include "swad_exam_log.h"
|
||||||
#include "swad_exam_print.h"
|
#include "swad_exam_print.h"
|
||||||
#include "swad_exam_result.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 void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,long ExaCod);
|
||||||
static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print,
|
static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print,
|
||||||
struct ExaSet_Set *Set,
|
struct ExaSet_Set *Set,
|
||||||
unsigned *NumQstInPrint);
|
unsigned *NumQstsInPrint);
|
||||||
static void ExaPrn_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
static void ExaPrn_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
||||||
bool Shuffle);
|
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,
|
static void ExaPrn_ShowExamPrintToFillIt (struct Exa_Exams *Exams,
|
||||||
const struct Exa_Exam *Exam,
|
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_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 *******************************/
|
/**************************** Reset exam print *******************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -216,7 +208,7 @@ void ExaPrn_ShowExamPrint (void)
|
||||||
if (Print.NumQsts.All)
|
if (Print.NumQsts.All)
|
||||||
{
|
{
|
||||||
/***** Create new exam print in database *****/
|
/***** Create new exam print in database *****/
|
||||||
ExaPrn_CreatePrintInDB (&Print);
|
ExaPrn_CreatePrint (&Print);
|
||||||
|
|
||||||
/***** Set log print code and action *****/
|
/***** Set log print code and action *****/
|
||||||
ExaLog_SetPrnCod (Print.PrnCod);
|
ExaLog_SetPrnCod (Print.PrnCod);
|
||||||
|
@ -256,20 +248,7 @@ void ExaPrn_GetDataOfPrintByPrnCod (struct ExaPrn_Print *Print)
|
||||||
unsigned NumPrints;
|
unsigned NumPrints;
|
||||||
|
|
||||||
/***** Make database query *****/
|
/***** Make database query *****/
|
||||||
NumPrints = (unsigned)
|
NumPrints = Exa_DB_GetDataOfPrintByPrnCod (&mysql_res,Print->PrnCod);
|
||||||
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);
|
|
||||||
|
|
||||||
/***** Get data of print *****/
|
/***** Get data of print *****/
|
||||||
ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints);
|
ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints);
|
||||||
|
@ -285,22 +264,9 @@ void ExaPrn_GetDataOfPrintBySesCodAndUsrCod (struct ExaPrn_Print *Print)
|
||||||
unsigned NumPrints;
|
unsigned NumPrints;
|
||||||
|
|
||||||
/***** Make database query *****/
|
/***** Make database query *****/
|
||||||
NumPrints = (unsigned)
|
NumPrints = Exa_DB_GetDataOfPrintBySesCodAndUsrCod (&mysql_res,
|
||||||
DB_QuerySELECT (&mysql_res,"can not get data of an exam print",
|
Print->SesCod,
|
||||||
"SELECT PrnCod," // row[0]
|
Print->UsrCod);
|
||||||
"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);
|
|
||||||
|
|
||||||
/***** Get data of print *****/
|
/***** Get data of print *****/
|
||||||
ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints);
|
ExaPrn_GetDataOfPrint (Print,&mysql_res,NumPrints);
|
||||||
|
@ -369,22 +335,11 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,lon
|
||||||
unsigned NumSet;
|
unsigned NumSet;
|
||||||
struct ExaSet_Set Set;
|
struct ExaSet_Set Set;
|
||||||
unsigned NumQstsFromSet;
|
unsigned NumQstsFromSet;
|
||||||
unsigned NumQstInPrint = 0;
|
unsigned NumQstsInPrint = 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);
|
|
||||||
|
|
||||||
/***** Get questions from all sets *****/
|
/***** Get questions from all sets *****/
|
||||||
Print->NumQsts.All = 0;
|
Print->NumQsts.All = 0;
|
||||||
if (NumSets)
|
if ((NumSets = Exa_DB_GetExamSets (&mysql_res,ExaCod)))
|
||||||
/***** For each set in exam... *****/
|
/***** For each set in exam... *****/
|
||||||
for (NumSet = 0;
|
for (NumSet = 0;
|
||||||
NumSet < NumSets;
|
NumSet < NumSets;
|
||||||
|
@ -400,22 +355,21 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct ExaPrn_Print *Print,lon
|
||||||
row[1] NumQstsToPrint
|
row[1] NumQstsToPrint
|
||||||
row[2] Title
|
row[2] Title
|
||||||
*/
|
*/
|
||||||
/* Get set code (row[0]) */
|
/* Get set code (row[0])
|
||||||
Set.SetCod = Str_ConvertStrCodToLongCod (row[0]);
|
and set index (row[1]) */
|
||||||
|
Set.SetCod = Str_ConvertStrCodToLongCod (row[0]);
|
||||||
/* Get set index (row[1]) */
|
|
||||||
Set.NumQstsToPrint = Str_ConvertStrToUnsigned (row[1]);
|
Set.NumQstsToPrint = Str_ConvertStrToUnsigned (row[1]);
|
||||||
|
|
||||||
/* Get the title of the set (row[2]) */
|
/* Get the title of the set (row[2]) */
|
||||||
Str_Copy (Set.Title,row[2],sizeof (Set.Title) - 1);
|
Str_Copy (Set.Title,row[2],sizeof (Set.Title) - 1);
|
||||||
|
|
||||||
/***** Questions in this set *****/
|
/***** Questions in this set *****/
|
||||||
NumQstsFromSet = ExaPrn_GetSomeQstsFromSetToPrint (Print,&Set,&NumQstInPrint);
|
NumQstsFromSet = ExaPrn_GetSomeQstsFromSetToPrint (Print,&Set,&NumQstsInPrint);
|
||||||
Print->NumQsts.All += NumQstsFromSet;
|
Print->NumQsts.All += NumQstsFromSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Check *****/
|
/***** Check *****/
|
||||||
if (Print->NumQsts.All != NumQstInPrint)
|
if (Print->NumQsts.All != NumQstsInPrint)
|
||||||
Err_ShowErrorAndExit ("Wrong number of questions.");
|
Err_ShowErrorAndExit ("Wrong number of questions.");
|
||||||
|
|
||||||
/***** Free structure that stores the query result *****/
|
/***** 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,
|
static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print,
|
||||||
struct ExaSet_Set *Set,
|
struct ExaSet_Set *Set,
|
||||||
unsigned *NumQstInPrint)
|
unsigned *NumQstsInPrint)
|
||||||
{
|
{
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
@ -438,22 +392,14 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print,
|
||||||
bool Shuffle;
|
bool Shuffle;
|
||||||
|
|
||||||
/***** Get questions from database *****/
|
/***** Get questions from database *****/
|
||||||
NumQstsInSet = (unsigned)
|
NumQstsInSet = Exa_DB_GetSomeQstsFromSetToPrint (&mysql_res,
|
||||||
DB_QuerySELECT (&mysql_res,"can not get questions from set",
|
Set->SetCod,
|
||||||
"SELECT QstCod," // row[0]
|
Set->NumQstsToPrint);
|
||||||
"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);
|
|
||||||
|
|
||||||
/***** Questions in this set *****/
|
/***** Questions in this set *****/
|
||||||
for (NumQstInSet = 0;
|
for (NumQstInSet = 0;
|
||||||
NumQstInSet < NumQstsInSet;
|
NumQstInSet < NumQstsInSet;
|
||||||
NumQstInSet++, (*NumQstInPrint)++)
|
NumQstInSet++, (*NumQstsInPrint)++)
|
||||||
{
|
{
|
||||||
Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd;
|
Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd;
|
||||||
|
|
||||||
|
@ -466,10 +412,10 @@ static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Get question code (row[0]) */
|
/* 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 */
|
/* Set set of questions */
|
||||||
Print->PrintedQuestions[*NumQstInPrint].SetCod = Set->SetCod;
|
Print->PrintedQuestions[*NumQstsInPrint].SetCod = Set->SetCod;
|
||||||
|
|
||||||
/* Get answer type (row[1]) */
|
/* Get answer type (row[1]) */
|
||||||
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (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_FLOAT:
|
||||||
case Tst_ANS_TRUE_FALSE:
|
case Tst_ANS_TRUE_FALSE:
|
||||||
case Tst_ANS_TEXT:
|
case Tst_ANS_TEXT:
|
||||||
Print->PrintedQuestions[*NumQstInPrint].StrIndexes[0] = '\0';
|
Print->PrintedQuestions[*NumQstsInPrint].StrIndexes[0] = '\0';
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_UNIQUE_CHOICE:
|
case Tst_ANS_UNIQUE_CHOICE:
|
||||||
case Tst_ANS_MULTIPLE_CHOICE:
|
case Tst_ANS_MULTIPLE_CHOICE:
|
||||||
/* If answer type is unique or multiple option,
|
/* If answer type is unique or multiple option,
|
||||||
generate indexes of answers depending on shuffle */
|
generate indexes of answers depending on shuffle */
|
||||||
ExaPrn_GenerateChoiceIndexes (&Print->PrintedQuestions[*NumQstInPrint],Shuffle);
|
ExaPrn_GenerateChoiceIndexes (&Print->PrintedQuestions[*NumQstsInPrint],Shuffle);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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.
|
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 ==>
|
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. */
|
==> 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 */
|
/* Reset score of this question in print */
|
||||||
Print->PrintedQuestions[*NumQstInPrint].Score = 0.0;
|
Print->PrintedQuestions[*NumQstsInPrint].Score = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NumQstsInSet;
|
return NumQstsInSet;
|
||||||
|
@ -578,29 +524,19 @@ static void ExaPrn_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *Printed
|
||||||
/***************** Create new blank exam print in database *******************/
|
/***************** 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;
|
unsigned QstInd;
|
||||||
|
|
||||||
/***** Insert new exam print into table *****/
|
/***** Insert new exam print into database *****/
|
||||||
Print->PrnCod =
|
Print->PrnCod = Exa_DB_CreatePrint (Print);
|
||||||
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);
|
|
||||||
|
|
||||||
/***** Store all questions (with blank answers)
|
/***** Store all questions (with blank answers)
|
||||||
of this exam print just generated in database *****/
|
of this exam print just generated in database *****/
|
||||||
for (QstInd = 0;
|
for (QstInd = 0;
|
||||||
QstInd < Print->NumQsts.All;
|
QstInd < Print->NumQsts.All;
|
||||||
QstInd++)
|
QstInd++)
|
||||||
ExaPrn_StoreOneQstOfPrintInDB (Print,QstInd);
|
Exa_DB_StoreOneQstOfPrint (Print,QstInd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -614,31 +550,18 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print)
|
||||||
unsigned QstInd;
|
unsigned QstInd;
|
||||||
|
|
||||||
/***** Get questions of an exam print from database *****/
|
/***** Get questions of an exam print from database *****/
|
||||||
Print->NumQsts.All = (unsigned)
|
if ((Print->NumQsts.All = Exa_DB_GetPrintQuestions (&mysql_res,Print->PrnCod))
|
||||||
DB_QuerySELECT (&mysql_res,"can not get questions of an exam print",
|
<= ExaPrn_MAX_QUESTIONS_PER_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)
|
|
||||||
for (QstInd = 0;
|
for (QstInd = 0;
|
||||||
QstInd < Print->NumQsts.All;
|
QstInd < Print->NumQsts.All;
|
||||||
QstInd++)
|
QstInd++)
|
||||||
{
|
{
|
||||||
row = mysql_fetch_row (mysql_res);
|
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)
|
if ((Print->PrintedQuestions[QstInd].QstCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
|
||||||
Err_WrongQuestionExit ();
|
Err_WrongQuestionExit ();
|
||||||
|
|
||||||
/* Get set code (row[1]) */
|
|
||||||
if ((Print->PrintedQuestions[QstInd].SetCod = Str_ConvertStrCodToLongCod (row[1])) <= 0)
|
if ((Print->PrintedQuestions[QstInd].SetCod = Str_ConvertStrCodToLongCod (row[1])) <= 0)
|
||||||
Err_WrongSetExit ();
|
Err_WrongSetExit ();
|
||||||
|
|
||||||
|
@ -648,11 +571,10 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print)
|
||||||
Err_ShowErrorAndExit ("Wrong question score.");
|
Err_ShowErrorAndExit ("Wrong question score.");
|
||||||
Str_SetDecimalPointToLocal (); // Return to local system
|
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],
|
Str_Copy (Print->PrintedQuestions[QstInd].StrIndexes,row[3],
|
||||||
sizeof (Print->PrintedQuestions[QstInd].StrIndexes) - 1);
|
sizeof (Print->PrintedQuestions[QstInd].StrIndexes) - 1);
|
||||||
|
|
||||||
/* Get answers selected by user for this question (row[4]) */
|
|
||||||
Str_Copy (Print->PrintedQuestions[QstInd].StrAnswers,row[4],
|
Str_Copy (Print->PrintedQuestions[QstInd].StrAnswers,row[4],
|
||||||
sizeof (Print->PrintedQuestions[QstInd].StrAnswers) - 1);
|
sizeof (Print->PrintedQuestions[QstInd].StrAnswers) - 1);
|
||||||
}
|
}
|
||||||
|
@ -914,9 +836,9 @@ static void ExaPrn_WriteTF_AnsToFill (const struct ExaPrn_Print *Print,
|
||||||
HTM_TxtF ("<select id=\"%s\" name=\"Ans\"",Id);
|
HTM_TxtF ("<select id=\"%s\" name=\"Ans\"",Id);
|
||||||
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,-1);
|
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,-1);
|
||||||
HTM_Txt (" />");
|
HTM_Txt (" />");
|
||||||
HTM_OPTION (HTM_Type_STRING,"" ,Print->PrintedQuestions[QstInd].StrAnswers[0] == '\0',false," ");
|
HTM_OPTION (HTM_Type_STRING,"" ,Print->PrintedQuestions[QstInd].StrAnswers[0] == '\0',false," ");
|
||||||
HTM_OPTION (HTM_Type_STRING,"T",Print->PrintedQuestions[QstInd].StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]);
|
HTM_OPTION (HTM_Type_STRING,"T",Print->PrintedQuestions[QstInd].StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]);
|
||||||
HTM_OPTION (HTM_Type_STRING,"F",Print->PrintedQuestions[QstInd].StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]);
|
HTM_OPTION (HTM_Type_STRING,"F",Print->PrintedQuestions[QstInd].StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]);
|
||||||
HTM_Txt ("</select>");
|
HTM_Txt ("</select>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -953,37 +875,37 @@ static void ExaPrn_WriteChoAnsToFill (const struct ExaPrn_Print *Print,
|
||||||
or 3 1 0 2... (example) if shuffle *****/
|
or 3 1 0 2... (example) if shuffle *****/
|
||||||
HTM_TR_Begin (NULL);
|
HTM_TR_Begin (NULL);
|
||||||
|
|
||||||
/***** Write selectors and letter of this option *****/
|
/***** Write selectors and letter of this option *****/
|
||||||
/* Initially user has not answered the question ==> initially all the answers will be blank.
|
/* 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 ==>
|
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. */
|
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
|
||||||
HTM_TD_Begin ("class=\"LT\"");
|
HTM_TD_Begin ("class=\"LT\"");
|
||||||
snprintf (Id,sizeof (Id),"Ans%010u",QstInd);
|
snprintf (Id,sizeof (Id),"Ans%010u",QstInd);
|
||||||
HTM_TxtF ("<input type=\"%s\" id=\"%s_%u\" name=\"Ans\" value=\"%u\"%s",
|
HTM_TxtF ("<input type=\"%s\" id=\"%s_%u\" name=\"Ans\" value=\"%u\"%s",
|
||||||
Question->Answer.Type == Tst_ANS_UNIQUE_CHOICE ? "radio" :
|
Question->Answer.Type == Tst_ANS_UNIQUE_CHOICE ? "radio" :
|
||||||
"checkbox",
|
"checkbox",
|
||||||
Id,NumOpt,Indexes[NumOpt],
|
Id,NumOpt,Indexes[NumOpt],
|
||||||
UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" :
|
UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" :
|
||||||
"");
|
"");
|
||||||
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,(int) NumOpt);
|
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,(int) NumOpt);
|
||||||
HTM_Txt (" />");
|
HTM_Txt (" />");
|
||||||
HTM_TD_End ();
|
HTM_TD_End ();
|
||||||
|
|
||||||
HTM_TD_Begin ("class=\"LT\"");
|
HTM_TD_Begin ("class=\"LT\"");
|
||||||
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt);
|
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt);
|
||||||
HTM_TxtF ("%c) ",'a' + (char) NumOpt);
|
HTM_TxtF ("%c) ",'a' + (char) NumOpt);
|
||||||
HTM_LABEL_End ();
|
HTM_LABEL_End ();
|
||||||
HTM_TD_End ();
|
HTM_TD_End ();
|
||||||
|
|
||||||
/***** Write the option text *****/
|
/***** Write the option text *****/
|
||||||
HTM_TD_Begin ("class=\"LT\"");
|
HTM_TD_Begin ("class=\"LT\"");
|
||||||
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt);
|
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"TEST_TXT\"",QstInd,NumOpt);
|
||||||
HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text);
|
HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text);
|
||||||
HTM_LABEL_End ();
|
HTM_LABEL_End ();
|
||||||
Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media,
|
Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media,
|
||||||
"TEST_MED_SHOW_CONT",
|
"TEST_MED_SHOW_CONT",
|
||||||
"TEST_MED_SHOW");
|
"TEST_MED_SHOW");
|
||||||
HTM_TD_End ();
|
HTM_TD_End ();
|
||||||
|
|
||||||
HTM_TR_End ();
|
HTM_TR_End ();
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +931,6 @@ static void ExaPrn_WriteTxtAnsToFill (const struct ExaPrn_Print *Print,
|
||||||
Id,Tst_MAX_CHARS_ANSWERS_ONE_QST,
|
Id,Tst_MAX_CHARS_ANSWERS_ONE_QST,
|
||||||
Print->PrintedQuestions[QstInd].StrAnswers);
|
Print->PrintedQuestions[QstInd].StrAnswers);
|
||||||
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,-1);
|
ExaPrn_WriteJSToUpdateExamPrint (Print,QstInd,Id,-1);
|
||||||
|
|
||||||
HTM_Txt (" />");
|
HTM_Txt (" />");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,8 +1095,8 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri
|
||||||
==> uncheck it by deleting answer *****/
|
==> uncheck it by deleting answer *****/
|
||||||
if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE)
|
if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE)
|
||||||
{
|
{
|
||||||
ExaPrn_GetAnswerFromDB (Print,Print->PrintedQuestions[QstInd].QstCod,
|
Exa_DB_GetAnswersFromQstInPrint (Print->PrnCod,Print->PrintedQuestions[QstInd].QstCod,
|
||||||
CurrentStrAnswersInDB);
|
CurrentStrAnswersInDB);
|
||||||
if (!strcmp (Print->PrintedQuestions[QstInd].StrAnswers,CurrentStrAnswersInDB))
|
if (!strcmp (Print->PrintedQuestions[QstInd].StrAnswers,CurrentStrAnswersInDB))
|
||||||
{
|
{
|
||||||
/* The answer just clicked by user
|
/* The answer just clicked by user
|
||||||
|
@ -1186,8 +1107,8 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Store test exam question in database *****/
|
/***** Store test exam question in database *****/
|
||||||
ExaPrn_StoreOneQstOfPrintInDB (Print,
|
Exa_DB_StoreOneQstOfPrint (Print,
|
||||||
QstInd); // 0, 1, 2, 3...
|
QstInd); // 0, 1, 2, 3...
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1271,12 +1192,7 @@ static void ExaPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question)
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
|
||||||
/***** Query database *****/
|
/***** Query database *****/
|
||||||
Question->Answer.NumOptions = (unsigned)
|
Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get answers of a question",
|
|
||||||
"SELECT Answer" // row[0]
|
|
||||||
" FROM exa_set_answers"
|
|
||||||
" WHERE QstCod=%ld",
|
|
||||||
Question->QstCod);
|
|
||||||
|
|
||||||
/***** Check if number of rows is correct *****/
|
/***** Check if number of rows is correct *****/
|
||||||
Tst_CheckIfNumberOfAnswersIsOne (Question);
|
Tst_CheckIfNumberOfAnswersIsOne (Question);
|
||||||
|
@ -1298,12 +1214,7 @@ static void ExaPrn_GetCorrectFltAnswerFromDB (struct Tst_Question *Question)
|
||||||
double Tmp;
|
double Tmp;
|
||||||
|
|
||||||
/***** Query database *****/
|
/***** Query database *****/
|
||||||
Question->Answer.NumOptions = (unsigned)
|
Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get answers of a question",
|
|
||||||
"SELECT Answer" // row[0]
|
|
||||||
" FROM exa_set_answers"
|
|
||||||
" WHERE QstCod=%ld",
|
|
||||||
Question->QstCod);
|
|
||||||
|
|
||||||
/***** Check if number of rows is correct *****/
|
/***** Check if number of rows is correct *****/
|
||||||
if (Question->Answer.NumOptions != 2)
|
if (Question->Answer.NumOptions != 2)
|
||||||
|
@ -1336,12 +1247,7 @@ static void ExaPrn_GetCorrectTF_AnswerFromDB (struct Tst_Question *Question)
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
|
||||||
/***** Query database *****/
|
/***** Query database *****/
|
||||||
Question->Answer.NumOptions = (unsigned)
|
Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get answers of a question",
|
|
||||||
"SELECT Answer" // row[0]
|
|
||||||
" FROM exa_set_answers"
|
|
||||||
" WHERE QstCod=%ld",
|
|
||||||
Question->QstCod);
|
|
||||||
|
|
||||||
/***** Check if number of rows is correct *****/
|
/***** Check if number of rows is correct *****/
|
||||||
Tst_CheckIfNumberOfAnswersIsOne (Question);
|
Tst_CheckIfNumberOfAnswersIsOne (Question);
|
||||||
|
@ -1361,13 +1267,7 @@ static void ExaPrn_GetCorrectChoAnswerFromDB (struct Tst_Question *Question)
|
||||||
unsigned NumOpt;
|
unsigned NumOpt;
|
||||||
|
|
||||||
/***** Query database *****/
|
/***** Query database *****/
|
||||||
Question->Answer.NumOptions = (unsigned)
|
Question->Answer.NumOptions = Exa_DB_GetQstAnswersCorrFromSet (&mysql_res,Question->QstCod);
|
||||||
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);
|
|
||||||
for (NumOpt = 0;
|
for (NumOpt = 0;
|
||||||
NumOpt < Question->Answer.NumOptions;
|
NumOpt < Question->Answer.NumOptions;
|
||||||
NumOpt++)
|
NumOpt++)
|
||||||
|
@ -1390,12 +1290,7 @@ static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question)
|
||||||
unsigned NumOpt;
|
unsigned NumOpt;
|
||||||
|
|
||||||
/***** Query database *****/
|
/***** Query database *****/
|
||||||
Question->Answer.NumOptions = (unsigned)
|
Question->Answer.NumOptions = Exa_DB_GetQstAnswersTextFromSet (&mysql_res,Question->QstCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get answers of a question",
|
|
||||||
"SELECT Answer" // row[0]
|
|
||||||
" FROM exa_set_answers"
|
|
||||||
" WHERE QstCod=%ld",
|
|
||||||
Question->QstCod);
|
|
||||||
|
|
||||||
/***** Get text and correctness of answers for this question from database (one row per answer) *****/
|
/***** Get text and correctness of answers for this question from database (one row per answer) *****/
|
||||||
for (NumOpt = 0;
|
for (NumOpt = 0;
|
||||||
|
@ -1422,115 +1317,6 @@ static void ExaPrn_GetCorrectTxtAnswerFromDB (struct Tst_Question *Question)
|
||||||
DB_FreeMySQLResult (&mysql_res);
|
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 ********************/
|
/********************** 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)
|
void ExaPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod)
|
||||||
{
|
{
|
||||||
/***** Remove exam prints questions for the given user *****/
|
/***** Remove exam prints questions for the given user *****/
|
||||||
DB_QueryDELETE ("can not remove exam prints made by a user",
|
Exa_DB_RemovePrintQuestionsMadeByUsrInAllCrss (UsrCod);
|
||||||
"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 exam prints made by the given user *****/
|
/***** Remove exam prints made by the given user *****/
|
||||||
DB_QueryDELETE ("can not remove exam prints made by a user",
|
Exa_DB_RemovePrintsMadeByUsrInAllCrss (UsrCod);
|
||||||
"DELETE FROM exa_prints"
|
|
||||||
" WHERE UsrCod=%ld",
|
|
||||||
UsrCod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1560,32 +1337,10 @@ void ExaPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod)
|
||||||
void ExaPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
|
void ExaPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
|
||||||
{
|
{
|
||||||
/***** Remove questions of exams prints made by the given user in the given course *****/
|
/***** 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",
|
Exa_DB_RemovePrintsQuestionsMadeByUsrInCrs (UsrCod,CrsCod);
|
||||||
"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 exams prints made by the given user in the given course *****/
|
/***** 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",
|
Exa_DB_RemovePrintsMadeByUsrInCrs (UsrCod,CrsCod);
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1595,26 +1350,8 @@ void ExaPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
|
||||||
void ExaPrn_RemoveCrsPrints (long CrsCod)
|
void ExaPrn_RemoveCrsPrints (long CrsCod)
|
||||||
{
|
{
|
||||||
/***** Remove questions of exams prints made by the given user in the given course *****/
|
/***** Remove questions of exams prints made by the given user in the given course *****/
|
||||||
DB_QueryDELETE ("can not remove exams prints in a course",
|
Exa_DB_RemovePrintQuestionsInCrs (CrsCod);
|
||||||
"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);
|
|
||||||
|
|
||||||
/***** Remove exams prints made by the given user in the given course *****/
|
/***** Remove exams prints made by the given user in the given course *****/
|
||||||
DB_QueryDELETE ("can not remove exams prints in a course",
|
Exa_DB_RemovePrintsInCrs (CrsCod);
|
||||||
"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);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user