From 3bc30a31fa7f5fd9012d3a2d3cdd2fcc8963af20 Mon Sep 17 00:00:00 2001 From: acanas Date: Sat, 9 May 2020 01:37:00 +0200 Subject: [PATCH] Version19.219 --- sql/swad.sql | 28 +++++- swad_API.c | 2 +- swad_changelog.h | 13 ++- swad_config.h | 2 +- swad_connected.c | 2 +- swad_database.c | 72 ++++++++++++-- swad_exam_event.c | 12 +-- swad_exam_print.c | 184 +++++++++++++++++++++++++++++------ swad_exam_result.c | 4 +- swad_match.c | 12 +-- swad_match_result.c | 4 +- swad_test.c | 49 +++++++--- swad_test.h | 2 + swad_test_print.c | 229 ++++++++++++++++++-------------------------- swad_test_print.h | 24 ++--- swad_test_type.h | 7 ++ swad_user.c | 4 +- 17 files changed, 424 insertions(+), 226 deletions(-) diff --git a/sql/swad.sql b/sql/swad.sql index 1a8b6e10..43231428 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -524,6 +524,32 @@ CREATE TABLE IF NOT EXISTS exa_participants ( TS TIMESTAMP, UNIQUE INDEX(EvtCod,UsrCod)); -- +-- Table exa_print_questions: stores the questions and answers in exam prints made by users +-- +CREATE TABLE IF NOT EXISTS exa_print_questions ( + PrnCod INT NOT NULL, + QstCod INT NOT NULL, + QstInd INT NOT NULL, + Score DOUBLE PRECISION NOT NULL DEFAULT 0, + Indexes TEXT NOT NULL, + Answers TEXT NOT NULL, + UNIQUE INDEX(PrnCod,QstCod)); +-- +-- Table exa_prints: stores the exam prints of every exam event +-- +CREATE TABLE IF NOT EXISTS exa_prints ( + PrnCod INT NOT NULL AUTO_INCREMENT, + EvtCod INT NOT NULL, + UsrCod INT NOT NULL, + StartTime DATETIME NOT NULL, + EndTime DATETIME NOT NULL, + NumQsts INT NOT NULL DEFAULT 0, + NumQstsNotBlank INT NOT NULL DEFAULT 0, + Sent ENUM('N','Y') NOT NULL DEFAULT 'N', + Score DOUBLE PRECISION NOT NULL DEFAULT 0, + UNIQUE INDEX(PrnCod), + UNIQUE INDEX(EvtCod,UsrCod)); +-- -- Table exa_questions: stores the questions in the set of questions for exams -- CREATE TABLE IF NOT EXISTS exa_questions ( @@ -1507,7 +1533,7 @@ CREATE TABLE IF NOT EXISTS tst_config ( Visibility INT NOT NULL DEFAULT 0x1f, UNIQUE INDEX(CrsCod)); -- --- Table tst_exam_questions: stores the questions and answers in test exams made by users +-- Table tst_exam_questions: stores the questions and answers in test prints made by users -- CREATE TABLE IF NOT EXISTS tst_exam_questions ( ExaCod INT NOT NULL, diff --git a/swad_API.c b/swad_API.c index 2faf6a0b..cb03bea3 100644 --- a/swad_API.c +++ b/swad_API.c @@ -4635,7 +4635,7 @@ int swad__getTrivialQuestion (struct soap *soap, " AND tst_tags.TagHidden='Y'" " AND tst_tags.TagCod=tst_question_tags.TagCod)" " HAVING S>='%f' AND S<='%f'" - " ORDER BY RAND(NOW()) LIMIT 1", + " ORDER BY RAND() LIMIT 1", DegreesStr,DegreesStr, lowerScore,upperScore); Str_SetDecimalPointToLocal (); // Return to local system diff --git a/swad_changelog.h b/swad_changelog.h index 9e5d42c8..ba093202 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -548,10 +548,19 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.218.1 (2020-05-07)" +#define Log_PLATFORM_VERSION "SWAD 19.219 (2020-05-07)" #define CSS_FILE "swad19.217.css" #define JS_FILE "swad19.193.1.js" /* + Arreglar bug: cuando se crea un nuevo proyecto no debería salir de nuevo el formulario de creación sino el formulario que incluye la adición de usuarios al proyecto recién creado. + cuando se modifica se hace correctamente, así que se trata de hacer lo mismo cuando se crea que cuando se modifica. + Arreglar bug en rol de usuario. Reported by Francisco Ocaña Lara. + + Version 19.219: May 09, 2020 Create exam print. (302347 lines) + 2 change necessary in database: +CREATE TABLE IF NOT EXISTS exa_prints (PrnCod INT NOT NULL AUTO_INCREMENT,EvtCod INT NOT NULL,UsrCod INT NOT NULL,StartTime DATETIME NOT NULL,EndTime DATETIME NOT NULL,NumQsts INT NOT NULL DEFAULT 0,NumQstsNotBlank INT NOT NULL DEFAULT 0,Sent ENUM('N','Y') NOT NULL DEFAULT 'N',Score DOUBLE PRECISION NOT NULL DEFAULT 0,UNIQUE INDEX(PrnCod),UNIQUE INDEX(EvtCod,UsrCod)); +CREATE TABLE IF NOT EXISTS exa_print_questions (PrnCod INT NOT NULL,QstCod INT NOT NULL,QstInd INT NOT NULL,Score DOUBLE PRECISION NOT NULL DEFAULT 0,Indexes TEXT NOT NULL,Answers TEXT NOT NULL,UNIQUE INDEX(PrnCod,QstCod)); + Version 19.218.1: May 07, 2020 Fixed minor bug in test results and match results. (302171 lines) Version 19.218: May 07, 2020 Fixed bug in creation of new exam announcements, reported by Francisco Gómez Mula. Changes in exam announcementes. (302170 lines) @@ -578,7 +587,7 @@ ALTER TABLE room_MAC ENGINE=MyISAM; Version 19.211: May 05, 2020 Exam events can be hidden/unhidden. (301215 lines) 1 change necessary in database: ALTER TABLE exa_events ADD COLUMN Hidden ENUM('N','Y') NOT NULL DEFAULT 'N' AFTER ExaCod; - +---- Version 19.210.4: May 05, 2020 Fixed bug searching courses. (301103 lines) Version 19.210.3: May 03, 2020 All figures cacheable are cached everytime they are calculated. (301089 lines) Version 19.210.2: May 03, 2020 More figures cached. (301125 lines) diff --git a/swad_config.h b/swad_config.h index b9ef34c6..67a2d62a 100644 --- a/swad_config.h +++ b/swad_config.h @@ -262,7 +262,7 @@ #define Cfg_MIN_NUM_USERS_TO_CONFIRM_SHOW_BIG_LIST 500 // If the number of users in a list is greater than this, ask me for confirmation before showing the list #define Cfg_MIN_PHOTOS_TO_SHOW_AVERAGE 10 // If the number of students with photo in a degree is less than this, don't show average photo of the degree #define Cfg_MAX_RECIPIENTS 250 // A student can not send a message to more than this number of recipients -#define Cfg_MAX_CONNECTED_SHOWN 15 // Show (in right column) only these connected users with more recent activity +#define Cfg_MAX_CONNECTED_SHOWN 10 // Show (in right column) only these connected users with more recent activity /* Courses */ #define Cfg_MIN_NUM_COURSES_TO_CONFIRM_SHOW_BIG_LIST 500 // If the number of courses in a list is greater than this, ask me for confirmation before showing the list diff --git a/swad_connected.c b/swad_connected.c index 1f695648..d070546a 100644 --- a/swad_connected.c +++ b/swad_connected.c @@ -908,7 +908,7 @@ static void Con_ShowConnectedUsrsCurrentLocationOneByOneOnMainZone (Rol_Role_t R { case Rol_GST: NumUsrs = (unsigned) DB_QuerySELECT (&mysql_res,"can not get list of connected users" - " who belong to this location", + " who belong to this location", "SELECT UsrCod,LastCrsCod," "UNIX_TIMESTAMP()-UNIX_TIMESTAMP(LastTime) AS Dif" " FROM connected" diff --git a/swad_database.c b/swad_database.c index 676502c6..ab930485 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1159,6 +1159,60 @@ mysql> DESCRIBE exa_participants; "TS TIMESTAMP," "UNIQUE INDEX(EvtCod,UsrCod))"); +/***** Table exa_print_questions *****/ +/* +mysql> DESCRIBE exa_print_questions; +---------+---------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++---------+---------+------+-----+---------+-------+ +| PrnCod | int(11) | NO | PRI | NULL | | +| QstCod | int(11) | NO | PRI | NULL | | +| QstInd | int(11) | NO | | NULL | | +| Score | double | NO | | 0 | | +| Indexes | text | NO | | NULL | | +| Answers | text | NO | | NULL | | ++---------+---------+------+-----+---------+-------+ +6 rows in set (0.00 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS exa_print_questions (" + "PrnCod INT NOT NULL," + "QstCod INT NOT NULL," + "QstInd INT NOT NULL," + "Score DOUBLE PRECISION NOT NULL DEFAULT 0," + "Indexes TEXT NOT NULL," // Tst_MAX_BYTES_INDEXES_ONE_QST + "Answers TEXT NOT NULL," // Tst_MAX_BYTES_ANSWERS_ONE_QST + "UNIQUE INDEX(PrnCod,QstCod))"); + + /***** Table exa_prints *****/ +/* +mysql> DESCRIBE exa_prints; ++-----------------+---------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-----------------+---------------+------+-----+---------+----------------+ +| PrnCod | int(11) | NO | PRI | NULL | auto_increment | +| EvtCod | int(11) | NO | MUL | NULL | | +| UsrCod | int(11) | NO | | NULL | | +| StartTime | datetime | NO | | NULL | | +| EndTime | datetime | NO | | NULL | | +| NumQsts | int(11) | NO | | 0 | | +| NumQstsNotBlank | int(11) | NO | | 0 | | +| Sent | enum('N','Y') | NO | | N | | +| Score | double | NO | | 0 | | ++-----------------+---------------+------+-----+---------+----------------+ +9 rows in set (0.00 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS exa_prints (" + "PrnCod INT NOT NULL AUTO_INCREMENT," + "EvtCod INT NOT NULL," + "UsrCod INT NOT NULL," + "StartTime DATETIME NOT NULL," + "EndTime DATETIME NOT NULL," + "NumQsts INT NOT NULL DEFAULT 0," + "NumQstsNotBlank INT NOT NULL DEFAULT 0," + "Sent ENUM('N','Y') NOT NULL DEFAULT 'N'," + "Score DOUBLE PRECISION NOT NULL DEFAULT 0," + "UNIQUE INDEX(PrnCod)," + "UNIQUE INDEX(EvtCod,UsrCod))"); + /***** Table exa_questions *****/ /* mysql> DESCRIBE exa_questions; @@ -1768,7 +1822,7 @@ mysql> DESCRIBE mch_indexes; DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_indexes (" "MchCod INT NOT NULL," "QstInd INT NOT NULL," - "Indexes TEXT NOT NULL," // TstPrn_MAX_BYTES_INDEXES_ONE_QST + "Indexes TEXT NOT NULL," // Tst_MAX_BYTES_INDEXES_ONE_QST "UNIQUE INDEX(MchCod,QstInd))"); /***** Table mch_results *****/ @@ -3184,16 +3238,16 @@ mysql> DESCRIBE tst_exam_questions; +---------+---------+------+-----+---------+-------+ 6 rows in set (0.00 sec) */ - DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_exam_questions (" - "ExaCod INT NOT NULL," + DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_exam_questions (" // TODO: rename as tst_print_questions + "ExaCod INT NOT NULL," // TODO: rename as PrnCod "QstCod INT NOT NULL," "QstInd INT NOT NULL," "Score DOUBLE PRECISION NOT NULL DEFAULT 0," - "Indexes TEXT NOT NULL," // TstPrn_MAX_BYTES_INDEXES_ONE_QST - "Answers TEXT NOT NULL," // TstPrn_MAX_BYTES_ANSWERS_ONE_QST + "Indexes TEXT NOT NULL," // Tst_MAX_BYTES_INDEXES_ONE_QST + "Answers TEXT NOT NULL," // Tst_MAX_BYTES_ANSWERS_ONE_QST "UNIQUE INDEX(ExaCod,QstCod))"); - /***** Table tst_exams *****/ + /***** Table tst_exams *****/ // TODO: rename as tst_prints /* mysql> DESCRIBE tst_exams; +-----------------+---------------+------+-----+---------+----------------+ @@ -3212,8 +3266,8 @@ mysql> DESCRIBE tst_exams; +-----------------+---------------+------+-----+---------+----------------+ 10 rows in set (0.00 sec) */ - DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_exams (" - "ExaCod INT NOT NULL AUTO_INCREMENT," + DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_exams (" // TODO: rename as tst_prints + "ExaCod INT NOT NULL AUTO_INCREMENT," // TODO: rename as PrnCod "CrsCod INT NOT NULL," "UsrCod INT NOT NULL," "StartTime DATETIME NOT NULL," @@ -3223,7 +3277,7 @@ mysql> DESCRIBE tst_exams; "Sent ENUM('N','Y') NOT NULL DEFAULT 'N'," "AllowTeachers ENUM('N','Y') NOT NULL DEFAULT 'N'," "Score DOUBLE PRECISION NOT NULL DEFAULT 0," - "UNIQUE INDEX(ExaCod)," + "UNIQUE INDEX(ExaCod)," // TODO: rename as PrnCod "INDEX(CrsCod,UsrCod))"); /***** Table tst_question_tags *****/ diff --git a/swad_exam_event.c b/swad_exam_event.c index b4abe274..c85f2055 100644 --- a/swad_exam_event.c +++ b/swad_exam_event.c @@ -1934,7 +1934,7 @@ static void ExaEvt_ReorderAnswer (long EvtCod,unsigned QstInd, long LongNum; unsigned AnsInd; char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; - char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; ***** Initialize list of answers to empty string ***** StrAnswersOneQst[0] = '\0'; @@ -1967,9 +1967,9 @@ static void ExaEvt_ReorderAnswer (long EvtCod,unsigned QstInd, * Concatenate answer index to list of answers * if (NumAns) Str_Concat (StrAnswersOneQst,",", - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); Str_Concat (StrAnswersOneQst,StrOneAnswer, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); } ***** Free structure that stores the query result ***** @@ -1993,7 +1993,7 @@ void ExaEvt_GetIndexes (long EvtCod,unsigned QstInd, { MYSQL_RES *mysql_res; MYSQL_ROW row; - char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1]; + char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; /***** Get indexes for a question from database *****/ if (!DB_QuerySELECT (&mysql_res,"can not get data of a question", @@ -2006,7 +2006,7 @@ void ExaEvt_GetIndexes (long EvtCod,unsigned QstInd, /* Get indexes (row[0]) */ Str_Copy (StrIndexesOneQst,row[0], - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -4348,7 +4348,7 @@ static void ExaEvt_ComputeScore (struct TstPrn_Print *Print) Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; /***** Compute score for this answer ******/ - TstPrn_ComputeChoiceAnsScore (Print,NumQst,&Question); + TstPrn_ComputeChoiceAnsScore (&Print->PrintedQuestions[NumQst],&Question); /***** Update total score *****/ Print->Score += Print->PrintedQuestions[NumQst].Score; diff --git a/swad_exam_print.c b/swad_exam_print.c index 14b13a60..292c0b9f 100644 --- a/swad_exam_print.c +++ b/swad_exam_print.c @@ -86,8 +86,15 @@ static void ExaPrn_ResetPrintExceptPrnCod (struct ExaPrn_Print *Print); static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, struct ExaPrn_Print *Print); -static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print, - struct ExaSet_Set *Set); +static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, + struct ExaSet_Set *Set, + unsigned *NumQstInPrint); +static void ExaPrn_CreatePrintInDB (const struct ExaEvt_Event *Event, + struct ExaPrn_Print *Print); +static void ExaPrn_ComputeScoresAndStoreQuestionsOfPrint (struct ExaPrn_Print *Print, + bool UpdateQstScore); +static void ExaPrn_StoreOneQstOfPrintInDB (const struct ExaPrn_Print *Print, + unsigned NumQst); /*****************************************************************************/ /**************************** Reset exam print *******************************/ @@ -145,6 +152,22 @@ void ExaPrn_ShowNewExamPrint (void) /***** Get questions from database *****/ ExaPrn_GetQuestionsForNewPrintFromDB (&Exam,&Print); + if (Print.NumQsts) + { + /***** Create new exam print in database *****/ + ExaPrn_CreatePrintInDB (&Event,&Print); + ExaPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print, + false); // Don't update question score + + /***** Show test exam to be answered *****/ + // Tst_ShowTestExamToFillIt (&Print,NumExamsGeneratedByMe,Tst_REQUEST); + } + // else // No questions found + // { + // Ale_ShowAlert (Ale_INFO,Txt_No_questions_found_matching_your_search_criteria); + // Tst_ShowFormRequestTest (&Test); // Show the form again + // } + /***** End table *****/ HTM_TABLE_End (); } @@ -163,6 +186,8 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, unsigned NumSets; unsigned NumSet; struct ExaSet_Set Set; + unsigned NumQstsFromSet; + unsigned NumQstInPrint = 0; /***** Get data of set of questions from database *****/ NumSets = (unsigned) @@ -175,9 +200,10 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, " ORDER BY SetInd", Exam->ExaCod); - /***** Show table with sets *****/ + /***** Get questions from all sets *****/ + Print->NumQsts = 0; if (NumSets) - /***** Write rows *****/ + /***** For each set in exam... *****/ for (NumSet = 0; NumSet < NumSets; NumSet++) @@ -227,9 +253,14 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, HTM_TR_End (); /***** Questions in this set *****/ - ExaPrn_ShowQuestionsFromSet (Print,&Set); + NumQstsFromSet = ExaPrn_GetSomeQstsFromSetToPrint (Print,&Set,&NumQstInPrint); + Print->NumQsts += NumQstsFromSet; } + /***** Check *****/ + if (Print->NumQsts != NumQstInPrint) + Lay_ShowErrorAndExit ("Wrong number of questions."); + /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } @@ -238,35 +269,35 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, /************************ Show questions from a set **************************/ /*****************************************************************************/ -static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print, - struct ExaSet_Set *Set) +static unsigned ExaPrn_GetSomeQstsFromSetToPrint (struct ExaPrn_Print *Print, + struct ExaSet_Set *Set, + unsigned *NumQstInPrint) { MYSQL_RES *mysql_res; MYSQL_ROW row; - unsigned NumQsts; - unsigned NumQst; - long QstCod; + unsigned NumQstsInSet; + unsigned NumQstInSet; Tst_AnswerType_t AnswerType; bool Shuffle; /***** Get questions from database *****/ - NumQsts = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get questions from set", - "SELECT tst_questions.QstCod," // row[0] - "tst_questions.AnsType," // row[1] - "tst_questions.Shuffle" // row[2] - " FROM exa_questions,tst_questions" - " WHERE exa_questions.setCod=%ld" - " AND exa_questions.QstCod=tst_questions.QstCod" - " ORDER BY RAND(NOW())" - " LIMIT %u", - Set->SetCod, - Set->NumQstsToPrint); + NumQstsInSet = (unsigned) + DB_QuerySELECT (&mysql_res,"can not get questions from set", + "SELECT tst_questions.QstCod," // row[0] + "tst_questions.AnsType," // row[1] + "tst_questions.Shuffle" // row[2] + " FROM exa_questions,tst_questions" + " WHERE exa_questions.setCod=%ld" + " AND exa_questions.QstCod=tst_questions.QstCod" + " 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 *****/ - for (NumQst = 0; - NumQst < NumQsts; - NumQst++) + for (NumQstInSet = 0; + NumQstInSet < NumQstsInSet; + NumQstInSet++, (*NumQstInPrint)++) { Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; @@ -279,7 +310,7 @@ static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print, */ /* Get question code (row[0]) */ - QstCod = Str_ConvertStrCodToLongCod (row[0]); + Print->PrintedQuestions[*NumQstInPrint].QstCod = Str_ConvertStrCodToLongCod (row[0]); /* Get answer type (row[1]) */ AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); @@ -294,13 +325,13 @@ static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print, case Tst_ANS_FLOAT: case Tst_ANS_TRUE_FALSE: case Tst_ANS_TEXT: - Print->PrintedQuestions[NumQst].StrIndexes[0] = '\0'; + Print->PrintedQuestions[*NumQstInPrint].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 */ - Tst_GenerateChoiceIndexesDependingOnShuffle (&Print->PrintedQuestions[NumQst],Shuffle); + Tst_GenerateChoiceIndexesDependingOnShuffle (&Print->PrintedQuestions[*NumQstInPrint],Shuffle); break; default: break; @@ -310,14 +341,14 @@ static void ExaPrn_ShowQuestionsFromSet (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[NumQst].StrAnswers[0] = '\0'; + Print->PrintedQuestions[*NumQstInPrint].StrAnswers[0] = '\0'; /* Begin row for this question */ HTM_TR_Begin (NULL); /* Title */ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - HTM_TxtF ("Pregunta %ld",QstCod); + HTM_TxtF ("Pregunta %ld",Print->PrintedQuestions[*NumQstInPrint].QstCod); HTM_TD_End (); /* Number of questions to appear in exam print */ @@ -328,4 +359,97 @@ static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print, /* End title for this question */ HTM_TR_End (); } + + return NumQstsInSet; + } + +/*****************************************************************************/ +/***************** Create new blank exam print in database *******************/ +/*****************************************************************************/ + +static void ExaPrn_CreatePrintInDB (const struct ExaEvt_Event *Event, + struct ExaPrn_Print *Print) + { + /***** Insert new exam print into table *****/ + Print->PrnCod = + DB_QueryINSERTandReturnCode ("can not create new exam print", + "INSERT INTO exa_prints" + " (EvtCod,UsrCod,StartTime,EndTime,NumQsts,NumQstsNotBlank,Sent,Score)" + " VALUES" + " (%ld,%ld,NOW(),NOW(),%u,0,'N',0)", + Event->EvtCod, + Gbl.Usrs.Me.UsrDat.UsrCod, + Print->NumQsts); + } + +/*****************************************************************************/ +/*********** Compute score of each question and store in database ************/ +/*****************************************************************************/ + +static void ExaPrn_ComputeScoresAndStoreQuestionsOfPrint (struct ExaPrn_Print *Print, + bool UpdateQstScore) + { + unsigned NumQst; + struct Tst_Question Question; + + /***** Initialize total score *****/ + Print->Score = 0.0; + Print->NumQstsNotBlank = 0; + + /***** Compute and store scores of all questions *****/ + for (NumQst = 0; + NumQst < Print->NumQsts; + NumQst++) + { + /* Compute question score */ + Tst_QstConstructor (&Question); + Question.QstCod = Print->PrintedQuestions[NumQst].QstCod; + Question.Answer.Type = Tst_GetQstAnswerType (Question.QstCod); + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); + Tst_QstDestructor (&Question); + + /* Store test exam question in database */ + ExaPrn_StoreOneQstOfPrintInDB (Print, + NumQst); // 0, 1, 2, 3... + + /* Accumulate total score */ + Print->Score += Print->PrintedQuestions[NumQst].Score; + if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) + Print->NumQstsNotBlank++; + + /* Update the number of hits and the score of this question in tests database */ + if (UpdateQstScore) + Tst_UpdateQstScoreInDB (&Print->PrintedQuestions[NumQst]); + } + } + + +/*****************************************************************************/ +/************* Store user's answers of an test exam into database ************/ +/*****************************************************************************/ + +static void ExaPrn_StoreOneQstOfPrintInDB (const struct ExaPrn_Print *Print, + unsigned NumQst) + { + char StrIndexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; + char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; + + /***** Replace each separator of multiple parameters by a comma *****/ + /* In database commas are used as separators instead of special chars */ + Par_ReplaceSeparatorMultipleByComma (Print->PrintedQuestions[NumQst].StrIndexes,StrIndexes); + Par_ReplaceSeparatorMultipleByComma (Print->PrintedQuestions[NumQst].StrAnswers,StrAnswers); + + /***** 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,Score,Indexes,Answers)" + " VALUES" + " (%ld,%ld,%u,'%.15lg','%s','%s')", + Print->PrnCod,Print->PrintedQuestions[NumQst].QstCod, + NumQst, // 0, 1, 2, 3... + Print->PrintedQuestions[NumQst].Score, + StrIndexes, + StrAnswers); + Str_SetDecimalPointToLocal (); // Return to local system } diff --git a/swad_exam_result.c b/swad_exam_result.c index 0def0284..c8b00a95 100644 --- a/swad_exam_result.c +++ b/swad_exam_result.c @@ -1353,13 +1353,13 @@ void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod, /* Get indexes for this question (row[2]) */ Str_Copy (Print->PrintedQuestions[NumQst].StrIndexes,row[2], - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); /* Get answers selected by user for this question */ ExaEvt_GetQstAnsFromDB (EvtCod,UsrCod,QstInd,&UsrAnswer); if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected { - snprintf (Print->PrintedQuestions[NumQst].StrAnswers,TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1, + snprintf (Print->PrintedQuestions[NumQst].StrAnswers,Tst_MAX_BYTES_ANSWERS_ONE_QST + 1, "%d",UsrAnswer.AnsInd); Print->NumQstsNotBlank++; } diff --git a/swad_match.c b/swad_match.c index ae72e90c..99d243ba 100644 --- a/swad_match.c +++ b/swad_match.c @@ -1612,7 +1612,7 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, long LongNum; unsigned AnsInd; char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; - char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; /***** Initialize list of answers to empty string *****/ StrAnswersOneQst[0] = '\0'; @@ -1645,9 +1645,9 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, /* Concatenate answer index to list of answers */ if (NumAns) Str_Concat (StrAnswersOneQst,",", - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); Str_Concat (StrAnswersOneQst,StrOneAnswer, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); } /***** Free structure that stores the query result *****/ @@ -1671,7 +1671,7 @@ void Mch_GetIndexes (long MchCod,unsigned QstInd, { MYSQL_RES *mysql_res; MYSQL_ROW row; - char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1]; + char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; /***** Get indexes for a question from database *****/ if (!DB_QuerySELECT (&mysql_res,"can not get data of a question", @@ -1684,7 +1684,7 @@ void Mch_GetIndexes (long MchCod,unsigned QstInd, /* Get indexes (row[0]) */ Str_Copy (StrIndexesOneQst,row[0], - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -4017,7 +4017,7 @@ static void Mch_ComputeScore (struct TstPrn_Print *Print) Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; /***** Compute score for this answer ******/ - TstPrn_ComputeChoiceAnsScore (Print,NumQst,&Question); + TstPrn_ComputeChoiceAnsScore (&Print->PrintedQuestions[NumQst],&Question); /***** Update total score *****/ Print->Score += Print->PrintedQuestions[NumQst].Score; diff --git a/swad_match_result.c b/swad_match_result.c index e30723e0..02f180d2 100644 --- a/swad_match_result.c +++ b/swad_match_result.c @@ -1344,13 +1344,13 @@ void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod, /* Get indexes for this question (row[2]) */ Str_Copy (Print->PrintedQuestions[NumQst].StrIndexes,row[2], - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); /* Get answers selected by user for this question */ Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer); if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected { - snprintf (Print->PrintedQuestions[NumQst].StrAnswers,TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1, + snprintf (Print->PrintedQuestions[NumQst].StrAnswers,Tst_MAX_BYTES_ANSWERS_ONE_QST + 1, "%d",UsrAnswer.AnsInd); Print->NumQstsNotBlank++; } diff --git a/swad_test.c b/swad_test.c index 8ea5a03c..325c86ef 100644 --- a/swad_test.c +++ b/swad_test.c @@ -467,8 +467,8 @@ void Tst_ShowNewTest (void) NumExamsGeneratedByMe = Tst_GetNumExamsGeneratedByMe (); /***** Create new test exam in database *****/ - TstPrn_CreateExamInDB (&Print); - TstPrn_ComputeScoresAndStoreExamQuestions (&Print, + TstPrn_CreatePrintInDB (&Print); + TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print, false); // Don't update question score /***** Show test exam to be answered *****/ @@ -552,7 +552,7 @@ void Tst_ReceiveTestDraft (void) Tst_GetAnswersFromForm (&Print); /***** Update test exam in database *****/ - TstPrn_ComputeScoresAndStoreExamQuestions (&Print, + TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print, false); // Don't update question score TstPrn_UpdateExamInDB (&Print); @@ -612,7 +612,7 @@ void Tst_AssessTest (void) Print.AllowTeachers = Par_GetParToBool ("AllowTchs"); /***** Update test exam in database *****/ - TstPrn_ComputeScoresAndStoreExamQuestions (&Print, + TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print, Gbl.Usrs.Me.Role.Logged == Rol_STD); // Update question score? TstPrn_UpdateExamInDB (&Print); @@ -646,7 +646,7 @@ void Tst_AssessTest (void) HTM_TxtColonNBSP (Txt_Grade); TstPrn_ComputeAndShowGrade (Print.NumQsts, Print.Score, - TstPrn_SCORE_MAX); + Tst_SCORE_MAX); HTM_DIV_End (); } @@ -674,7 +674,7 @@ static void Tst_GetAnswersFromForm (struct TstPrn_Print *Print) "Ans%010u", NumQst); Par_GetParMultiToText (StrAns,Print->PrintedQuestions[NumQst].StrAnswers, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */ + Tst_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */ } } @@ -2611,7 +2611,7 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test, } /* End query */ - Str_Concat (Query," ORDER BY RAND(NOW()) LIMIT ", + Str_Concat (Query," ORDER BY RAND() LIMIT ", Tst_MAX_BYTES_QUERY_TEST); snprintf (StrNumQsts,sizeof (StrNumQsts), "%u", @@ -2737,7 +2737,7 @@ void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstPrn_PrintedQuestion else snprintf (StrInd,sizeof (StrInd),"%s%u",Par_SEPARATOR_PARAM_MULTIPLE,Index); Str_Concat (PrintedQuestion->StrIndexes,StrInd, - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); } /***** Free structure that stores the query result *****/ @@ -3319,7 +3319,7 @@ void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, " WHERE QstCod=%ld" " ORDER BY %s", Question->QstCod, - Shuffle ? "RAND(NOW())" : + Shuffle ? "RAND()" : "AnsInd"); if (!Question->Answer.NumOptions) Ale_ShowAlert (Ale_ERROR,"Error when getting answers of a question."); @@ -3762,7 +3762,7 @@ static void Tst_WriteTextAnsSeeing (const struct TstPrn_Print *Print, snprintf (StrAns,sizeof (StrAns), "Ans%010u", NumQst); - HTM_INPUT_TEXT (StrAns,TstPrn_MAX_CHARS_ANSWERS_ONE_QST,Print->PrintedQuestions[NumQst].StrAnswers, + HTM_INPUT_TEXT (StrAns,Tst_MAX_CHARS_ANSWERS_ONE_QST,Print->PrintedQuestions[NumQst].StrAnswers, HTM_DONT_SUBMIT_ON_CHANGE, "size=\"40\""); } @@ -5049,7 +5049,7 @@ static void Tst_GetQstFromForm (struct Tst_Question *Question) char TagStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char AnsStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char FbStr[5 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; - char StrMultiAns[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char StrMultiAns[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; char TF[1 + 1]; // (T)rue or (F)alse const char *Ptr; unsigned NumCorrectAns; @@ -5201,7 +5201,7 @@ static void Tst_GetQstFromForm (struct Tst_Question *Question) } else if (Question->Answer.Type == Tst_ANS_MULTIPLE_CHOICE) { - Par_GetParMultiToText ("AnsMulti",StrMultiAns,TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Par_GetParMultiToText ("AnsMulti",StrMultiAns,Tst_MAX_BYTES_ANSWERS_ONE_QST); Ptr = StrMultiAns; while (*Ptr) { @@ -6156,6 +6156,31 @@ static void Tst_InsertAnswersIntoDB (struct Tst_Question *Question) } } +/*****************************************************************************/ +/*********************** Update the score of a question **********************/ +/*****************************************************************************/ + +void Tst_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion) + { + /***** Update number of clicks and score of the question *****/ + Str_SetDecimalPointToUS (); // To print the floating point as a dot + if (PrintedQuestion->AnswerIsNotBlank) + DB_QueryUPDATE ("can not update the score of a question", + "UPDATE tst_questions" + " SET NumHits=NumHits+1,NumHitsNotBlank=NumHitsNotBlank+1," + "Score=Score+(%.15lg)" + " WHERE QstCod=%ld", + PrintedQuestion->Score, + PrintedQuestion->QstCod); + else // The answer is blank + DB_QueryUPDATE ("can not update the score of a question", + "UPDATE tst_questions" + " SET NumHits=NumHits+1" + " WHERE QstCod=%ld", + PrintedQuestion->QstCod); + Str_SetDecimalPointToLocal (); // Return to local system + } + /*****************************************************************************/ /******************* Remove all test questions in a course *******************/ /*****************************************************************************/ diff --git a/swad_test.h b/swad_test.h index cdacf62d..7e94e711 100644 --- a/swad_test.h +++ b/swad_test.h @@ -177,6 +177,8 @@ void Tst_PutParamQstCod (void *QstCod); void Tst_InsertOrUpdateQstTagsAnsIntoDB (struct Tst_Question *Question); +void Tst_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion); + void Tst_RemoveCrsTests (long CrsCod); void Tst_GetTestStats (Tst_AnswerType_t AnsType,struct Tst_Stats *Stats); diff --git a/swad_test_print.c b/swad_test_print.c index 584b65f3..f29790b1 100644 --- a/swad_test_print.c +++ b/swad_test_print.c @@ -78,30 +78,22 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat, struct Tst_Question *Question, bool QuestionExists, unsigned Visibility); -static void TstPrn_ComputeAnswerScore (struct TstPrn_Print *Print, - unsigned NumQst, - struct Tst_Question *Question); -static void TstPrn_ComputeIntAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question); static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question); -static void TstPrn_ComputeFloatAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeFloatAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question); static void TstPrn_GetCorrectFloatAnswerFromDB (struct Tst_Question *Question); -static void TstPrn_ComputeTFAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeTFAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question); static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question); static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question); -static void TstPrn_ComputeScoreQst (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeScoreQst (struct TstPrn_PrintedQuestion *PrintedQuestion, const struct Tst_Question *Question, unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]); -static void TstPrn_ComputeTextAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeTextAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question); static void TstPrn_GetCorrectTextAnswerFromDB (struct Tst_Question *Question); @@ -137,9 +129,8 @@ static void TstPrn_WriteTextAnsExam (struct UsrData *UsrDat, unsigned Visibility); static void TstPrn_WriteHeadUserCorrect (struct UsrData *UsrDat); -static void TstPrn_StoreOneExamQstInDB (const struct TstPrn_Print *Print, - unsigned NumQst); -static void Tst_UpdateQstScoreInDB (const struct TstPrn_Print *Print,unsigned NumQst); +static void TstPrn_StoreOneQstOfPrintInDB (const struct TstPrn_Print *Print, + unsigned NumQst); static void TstPrn_PutFormToSelectUsrsToViewUsrsExams (__attribute__((unused)) void *Args); @@ -175,20 +166,18 @@ static void TstPrn_ResetExamExceptExaCod (struct TstPrn_Print *Print) } /*****************************************************************************/ -/***************** Create new blank test exam in database ********************/ +/************** Create new blank test exam print in database *****************/ /*****************************************************************************/ -void TstPrn_CreateExamInDB (struct TstPrn_Print *Print) +void TstPrn_CreatePrintInDB (struct TstPrn_Print *Print) { - /***** Insert new test exam into table *****/ + /***** Insert new test exam print into table *****/ Print->PrnCod = - DB_QueryINSERTandReturnCode ("can not create new test exam", + DB_QueryINSERTandReturnCode ("can not create new test exam print", "INSERT INTO tst_exams" - " (CrsCod,UsrCod,StartTime,EndTime,NumQsts," - "Sent,AllowTeachers,Score)" + " (CrsCod,UsrCod,StartTime,EndTime,NumQsts,NumQstsNotBlank,Sent,AllowTeachers,Score)" " VALUES" - " (%ld,%ld,NOW(),NOW(),%u," - "'N','N',0)", + " (%ld,%ld,NOW(),NOW(),%u,0,'N','N',0)", Gbl.Hierarchy.Crs.CrsCod, Gbl.Usrs.Me.UsrDat.UsrCod, Print->NumQsts); @@ -259,7 +248,7 @@ void TstPrn_ShowExamAfterAssess (struct TstPrn_Print *Print) TstCfg_GetConfigVisibility ()); /***** Store test exam question in database *****/ - TstPrn_StoreOneExamQstInDB (Print,NumQst); + TstPrn_StoreOneQstOfPrintInDB (Print,NumQst); /***** Compute total score *****/ Print->Score += Print->PrintedQuestions[NumQst].Score; @@ -268,7 +257,7 @@ void TstPrn_ShowExamAfterAssess (struct TstPrn_Print *Print) /***** Update the number of accesses and the score of this question *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_STD) - Tst_UpdateQstScoreInDB (Print,NumQst); + Tst_UpdateQstScoreInDB (&Print->PrintedQuestions[NumQst]); /***** Destroy test question *****/ Tst_QstDestructor (&Question); @@ -328,7 +317,7 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat, "TEST_MED_SHOW"); /* Answers */ - TstPrn_ComputeAnswerScore (Print,NumQst,Question); + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],Question); TstPrn_WriteAnswersExam (UsrDat,Print,NumQst,Question,Visibility); } else @@ -367,8 +356,8 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat, /*********** Compute score of each question and store in database ************/ /*****************************************************************************/ -void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print, - bool UpdateQstScore) +void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print, + bool UpdateQstScore) { unsigned NumQst; struct Tst_Question Question; @@ -386,12 +375,12 @@ void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print, Tst_QstConstructor (&Question); Question.QstCod = Print->PrintedQuestions[NumQst].QstCod; Question.Answer.Type = Tst_GetQstAnswerType (Question.QstCod); - TstPrn_ComputeAnswerScore (Print,NumQst,&Question); + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); Tst_QstDestructor (&Question); /* Store test exam question in database */ - TstPrn_StoreOneExamQstInDB (Print, - NumQst); // 0, 1, 2, 3... + TstPrn_StoreOneQstOfPrintInDB (Print, + NumQst); // 0, 1, 2, 3... /* Accumulate total score */ Print->Score += Print->PrintedQuestions[NumQst].Score; @@ -400,7 +389,7 @@ void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print, /* Update the number of hits and the score of this question in tests database */ if (UpdateQstScore) - Tst_UpdateQstScoreInDB (Print,NumQst); + Tst_UpdateQstScoreInDB (&Print->PrintedQuestions[NumQst]); } } @@ -408,28 +397,27 @@ void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print, /************* Write answers of a question when assessing a test *************/ /*****************************************************************************/ -static void TstPrn_ComputeAnswerScore (struct TstPrn_Print *Print, - unsigned NumQst, - struct Tst_Question *Question) +void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion, + struct Tst_Question *Question) { /***** Write answer depending on type *****/ switch (Question->Answer.Type) { case Tst_ANS_INT: - TstPrn_ComputeIntAnsScore (Print,NumQst,Question); + TstPrn_ComputeIntAnsScore (PrintedQuestion,Question); break; case Tst_ANS_FLOAT: - TstPrn_ComputeFloatAnsScore (Print,NumQst,Question); + TstPrn_ComputeFloatAnsScore (PrintedQuestion,Question); break; case Tst_ANS_TRUE_FALSE: - TstPrn_ComputeTFAnsScore (Print,NumQst,Question); + TstPrn_ComputeTFAnsScore (PrintedQuestion,Question); break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: - TstPrn_ComputeChoiceAnsScore (Print,NumQst,Question); + TstPrn_ComputeChoiceAnsScore (PrintedQuestion,Question); break; case Tst_ANS_TEXT: - TstPrn_ComputeTextAnsScore (Print,NumQst,Question); + TstPrn_ComputeTextAnsScore (PrintedQuestion,Question); break; default: break; @@ -440,8 +428,7 @@ static void TstPrn_ComputeAnswerScore (struct TstPrn_Print *Print, /**************** Write integer answer when assessing a test *****************/ /*****************************************************************************/ -static void TstPrn_ComputeIntAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question) { long AnswerUsr; @@ -450,12 +437,12 @@ static void TstPrn_ComputeIntAnsScore (struct TstPrn_Print *Print, TstPrn_GetCorrectIntAnswerFromDB (Question); /***** Compute score *****/ - Print->PrintedQuestions[NumQst].Score = 0.0; // Default score for blank or wrong answer - Print->PrintedQuestions[NumQst].AnswerIsNotBlank = (Print->PrintedQuestions[NumQst].StrAnswers[0] != '\0'); - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) // If user has answered the answer - if (sscanf (Print->PrintedQuestions[NumQst].StrAnswers,"%ld",&AnswerUsr) == 1) + PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer + PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0'); + if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer + if (sscanf (PrintedQuestion->StrAnswers,"%ld",&AnswerUsr) == 1) if (AnswerUsr == Question->Answer.Integer) // Correct answer - Print->PrintedQuestions[NumQst].Score = 1.0; + PrintedQuestion->Score = 1.0; } static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question) @@ -487,8 +474,7 @@ static void TstPrn_GetCorrectIntAnswerFromDB (struct Tst_Question *Question) /***************** Write float answer when assessing a test ******************/ /*****************************************************************************/ -static void TstPrn_ComputeFloatAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeFloatAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question) { double AnswerUsr; @@ -497,16 +483,16 @@ static void TstPrn_ComputeFloatAnsScore (struct TstPrn_Print *Print, TstPrn_GetCorrectFloatAnswerFromDB (Question); /***** Compute score *****/ - Print->PrintedQuestions[NumQst].Score = 0.0; // Default score for blank or wrong answer - Print->PrintedQuestions[NumQst].AnswerIsNotBlank = (Print->PrintedQuestions[NumQst].StrAnswers[0] != '\0'); - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) // If user has answered the answer + PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer + PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0'); + if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer { - AnswerUsr = Str_GetDoubleFromStr (Print->PrintedQuestions[NumQst].StrAnswers); + AnswerUsr = Str_GetDoubleFromStr (PrintedQuestion->StrAnswers); // A bad formatted floating point answer will interpreted as 0.0 - Print->PrintedQuestions[NumQst].Score = (AnswerUsr >= Question->Answer.FloatingPoint[0] && - AnswerUsr <= Question->Answer.FloatingPoint[1]) ? 1.0 : // If correct (inside the interval) - 0.0; // If wrong (outside the interval) + PrintedQuestion->Score = (AnswerUsr >= Question->Answer.FloatingPoint[0] && + AnswerUsr <= Question->Answer.FloatingPoint[1]) ? 1.0 : // If correct (inside the interval) + 0.0; // If wrong (outside the interval) } } @@ -554,20 +540,19 @@ static void TstPrn_GetCorrectFloatAnswerFromDB (struct Tst_Question *Question) /************** Write false / true answer when assessing a test **************/ /*****************************************************************************/ -static void TstPrn_ComputeTFAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeTFAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question) { /***** Get answer true or false *****/ TstPrn_GetCorrectTFAnswerFromDB (Question); /***** Compute score *****/ - Print->PrintedQuestions[NumQst].AnswerIsNotBlank = (Print->PrintedQuestions[NumQst].StrAnswers[0] != '\0'); - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) // User has selected T or F - Print->PrintedQuestions[NumQst].Score = (Print->PrintedQuestions[NumQst].StrAnswers[0] == Question->Answer.TF) ? 1.0 : // Correct - -1.0; // Wrong + PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0'); + if (PrintedQuestion->AnswerIsNotBlank) // User has selected T or F + PrintedQuestion->Score = (PrintedQuestion->StrAnswers[0] == Question->Answer.TF) ? 1.0 : // Correct + -1.0; // Wrong else - Print->PrintedQuestions[NumQst].Score = 0.0; + PrintedQuestion->Score = 0.0; } static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question) @@ -598,8 +583,7 @@ static void TstPrn_GetCorrectTFAnswerFromDB (struct Tst_Question *Question) /************ Compute score for single or multiple choice answer *************/ /*****************************************************************************/ -void TstPrn_ComputeChoiceAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +void TstPrn_ComputeChoiceAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question) { unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question @@ -609,13 +593,13 @@ void TstPrn_ComputeChoiceAnsScore (struct TstPrn_Print *Print, TstPrn_GetCorrectChoiceAnswerFromDB (Question); /***** Get indexes for this question from string *****/ - TstPrn_GetIndexesFromStr (Print->PrintedQuestions[NumQst].StrIndexes,Indexes); + TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes); /***** Get the user's answers for this question from string *****/ - TstPrn_GetAnswersFromStr (Print->PrintedQuestions[NumQst].StrAnswers,UsrAnswers); + TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers); /***** Compute the total score of this question *****/ - TstPrn_ComputeScoreQst (Print,NumQst,Question,Indexes,UsrAnswers); + TstPrn_ComputeScoreQst (PrintedQuestion,Question,Indexes,UsrAnswers); } static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question) @@ -651,8 +635,8 @@ static void TstPrn_GetCorrectChoiceAnswerFromDB (struct Tst_Question *Question) /********************* Get vector of indexes from string *********************/ /*****************************************************************************/ -void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. - unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]) +void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. + unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]) { unsigned NumOpt; const char *Ptr; @@ -683,7 +667,7 @@ void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[TstPrn_MAX_BYTES_INDE /****************** Get vector of user's answers from string *****************/ /*****************************************************************************/ -void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1], +void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1], bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]) { unsigned NumOpt; @@ -718,8 +702,7 @@ void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSW /*********************** Compute the score of a question *********************/ /*****************************************************************************/ -static void TstPrn_ComputeScoreQst (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeScoreQst (struct TstPrn_PrintedQuestion *PrintedQuestion, const struct Tst_Question *Question, unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]) @@ -749,64 +732,63 @@ static void TstPrn_ComputeScoreQst (struct TstPrn_Print *Print, } /* The answer is blank? */ - Print->PrintedQuestions[NumQst].AnswerIsNotBlank = NumAnsGood != 0 || NumAnsBad != 0; - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) + PrintedQuestion->AnswerIsNotBlank = NumAnsGood != 0 || NumAnsBad != 0; + if (PrintedQuestion->AnswerIsNotBlank) { /* Compute the score */ if (Question->Answer.Type == Tst_ANS_UNIQUE_CHOICE) { if (NumOptTotInQst >= 2) // It should be 2 options at least - Print->PrintedQuestions[NumQst].Score = (double) NumAnsGood - - (double) NumAnsBad / (double) (NumOptTotInQst - 1); + PrintedQuestion->Score = (double) NumAnsGood - + (double) NumAnsBad / (double) (NumOptTotInQst - 1); else // 0 or 1 options (impossible) - Print->PrintedQuestions[NumQst].Score = (double) NumAnsGood; + PrintedQuestion->Score = (double) NumAnsGood; } else // AnswerType == Tst_ANS_MULTIPLE_CHOICE { if (NumOptCorrInQst) // There are correct options in the question { if (NumOptCorrInQst < NumOptTotInQst) // If there are correct options and wrong options (typical case) - Print->PrintedQuestions[NumQst].Score = (double) NumAnsGood / (double) NumOptCorrInQst - - (double) NumAnsBad / (double) (NumOptTotInQst - NumOptCorrInQst); + PrintedQuestion->Score = (double) NumAnsGood / (double) NumOptCorrInQst - + (double) NumAnsBad / (double) (NumOptTotInQst - NumOptCorrInQst); else // If all options are correct (extrange case) - Print->PrintedQuestions[NumQst].Score = (double) NumAnsGood / (double) NumOptCorrInQst; + PrintedQuestion->Score = (double) NumAnsGood / (double) NumOptCorrInQst; } else { if (NumOptTotInQst) // There are options but none is correct (extrange case) - Print->PrintedQuestions[NumQst].Score = - (double) NumAnsBad / (double) NumOptTotInQst; + PrintedQuestion->Score = - (double) NumAnsBad / (double) NumOptTotInQst; else // There are no options (impossible!) - Print->PrintedQuestions[NumQst].Score = 0.0; + PrintedQuestion->Score = 0.0; } } } else // Answer is blank - Print->PrintedQuestions[NumQst].Score = 0.0; + PrintedQuestion->Score = 0.0; } /*****************************************************************************/ /********************* Compute score for text answer *************************/ /*****************************************************************************/ -static void TstPrn_ComputeTextAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +static void TstPrn_ComputeTextAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question) { unsigned NumOpt; - char TextAnsUsr[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; - char TextAnsOK[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char TextAnsUsr[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char TextAnsOK[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; /***** Get correct answers for this question from database *****/ TstPrn_GetCorrectTextAnswerFromDB (Question); /***** Compute score *****/ - Print->PrintedQuestions[NumQst].Score = 0.0; // Default score for blank or wrong answer - Print->PrintedQuestions[NumQst].AnswerIsNotBlank = (Print->PrintedQuestions[NumQst].StrAnswers[0] != '\0'); - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) // If user has answered the answer + PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer + PrintedQuestion->AnswerIsNotBlank = (PrintedQuestion->StrAnswers[0] != '\0'); + if (PrintedQuestion->AnswerIsNotBlank) // If user has answered the answer { /* Filter the user answer */ - Str_Copy (TextAnsUsr,Print->PrintedQuestions[NumQst].StrAnswers, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Str_Copy (TextAnsUsr,PrintedQuestion->StrAnswers, + Tst_MAX_BYTES_ANSWERS_ONE_QST); /* In order to compare student answer to stored answer, the text answers are stored avoiding two or more consecurive spaces */ @@ -819,12 +801,12 @@ static void TstPrn_ComputeTextAnsScore (struct TstPrn_Print *Print, { /* Filter this correct answer */ Str_Copy (TextAnsOK,Question->Answer.Options[NumOpt].Text, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); Str_ConvertToComparable (TextAnsOK); /* Check is user answer is correct */ if (!strcoll (TextAnsUsr,TextAnsOK)) - Print->PrintedQuestions[NumQst].Score = 1.0; // Correct answer + PrintedQuestion->Score = 1.0; // Correct answer } } } @@ -1254,8 +1236,8 @@ static void TstPrn_WriteTextAnsExam (struct UsrData *UsrDat, unsigned Visibility) { unsigned NumOpt; - char TextAnsUsr[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; - char TextAnsOK[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char TextAnsUsr[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char TextAnsOK[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; bool Correct = false; /***** Get text and correctness of answers for this question from database (one row per answer) *****/ @@ -1290,7 +1272,7 @@ static void TstPrn_WriteTextAnsExam (struct UsrData *UsrDat, { /* Filter the user answer */ Str_Copy (TextAnsUsr,Print->PrintedQuestions[NumQst].StrAnswers, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); /* In order to compare student answer to stored answer, the text answers are stored avoiding two or more consecurive spaces */ @@ -1304,7 +1286,7 @@ static void TstPrn_WriteTextAnsExam (struct UsrData *UsrDat, { /* Filter this correct answer */ Str_Copy (TextAnsOK,Question->Answer.Options[NumOpt].Text, - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); Str_ConvertToComparable (TextAnsOK); /* Check is user answer is correct */ @@ -1398,14 +1380,14 @@ static void TstPrn_WriteHeadUserCorrect (struct UsrData *UsrDat) } /*****************************************************************************/ -/************* Store user's answers of an test exam into database ************/ +/************ Store user's answers of an test print into database ************/ /*****************************************************************************/ -static void TstPrn_StoreOneExamQstInDB (const struct TstPrn_Print *Print, - unsigned NumQst) +static void TstPrn_StoreOneQstOfPrintInDB (const struct TstPrn_Print *Print, + unsigned NumQst) { - char StrIndexes[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1]; - char StrAnswers[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; + char StrIndexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; + char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; /***** Replace each separator of multiple parameters by a comma *****/ /* In database commas are used as separators instead of special chars */ @@ -1427,31 +1409,6 @@ static void TstPrn_StoreOneExamQstInDB (const struct TstPrn_Print *Print, Str_SetDecimalPointToLocal (); // Return to local system } -/*****************************************************************************/ -/*********************** Update the score of a question **********************/ -/*****************************************************************************/ - -static void Tst_UpdateQstScoreInDB (const struct TstPrn_Print *Print,unsigned NumQst) - { - /***** Update number of clicks and score of the question *****/ - Str_SetDecimalPointToUS (); // To print the floating point as a dot - if (Print->PrintedQuestions[NumQst].AnswerIsNotBlank) - DB_QueryUPDATE ("can not update the score of a question", - "UPDATE tst_questions" - " SET NumHits=NumHits+1,NumHitsNotBlank=NumHitsNotBlank+1," - "Score=Score+(%.15lg)" - " WHERE QstCod=%ld", - Print->PrintedQuestions[NumQst].Score, - Print->PrintedQuestions[NumQst].QstCod); - else // The answer is blank - DB_QueryUPDATE ("can not update the score of a question", - "UPDATE tst_questions" - " SET NumHits=NumHits+1" - " WHERE QstCod=%ld", - Print->PrintedQuestions[NumQst].QstCod); - Str_SetDecimalPointToLocal (); // Return to local system - } - /*****************************************************************************/ /************* Select users and dates to show their test exams ***************/ /*****************************************************************************/ @@ -1798,7 +1755,7 @@ static void TstPrn_ShowExams (struct UsrData *UsrDat) HTM_TD_Begin ("class=\"%s RT COLOR%u\"",ClassDat,Gbl.RowEvenOdd); if (ICanView.Score) TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score, - TstPrn_SCORE_MAX); + Tst_SCORE_MAX); HTM_TD_End (); /* Link to show this test exam */ @@ -1927,7 +1884,7 @@ static void TstPrn_ShowExamsSummaryRow (bool ItsMe, HTM_TD_Begin ("class=\"DAT_N_LINE_TOP RM COLOR%u\"",Gbl.RowEvenOdd); if (ICanViewTotalScore) TstPrn_ComputeAndShowGrade (NumTotalQsts,TotalScoreOfAllTests, - TstPrn_SCORE_MAX); + Tst_SCORE_MAX); HTM_TD_End (); /***** Last cell *****/ @@ -2128,7 +2085,7 @@ void TstPrn_ShowOneExam (void) HTM_TD_Begin ("class=\"DAT LT\""); if (ICanViewScore) TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score, - TstPrn_SCORE_MAX); + Tst_SCORE_MAX); else Ico_PutIconNotVisible (); HTM_TD_End (); @@ -2164,7 +2121,7 @@ void TstPrn_ShowOneExam (void) HTM_BR (); HTM_TxtColonNBSP (Txt_Grade); TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score, - TstPrn_SCORE_MAX); + Tst_SCORE_MAX); HTM_DIV_End (); } @@ -2344,11 +2301,11 @@ void TstPrn_GetExamQuestionsFromDB (struct TstPrn_Print *Print) /* Get indexes for this question (row[2]) */ Str_Copy (Print->PrintedQuestions[NumQst].StrIndexes,row[2], - TstPrn_MAX_BYTES_INDEXES_ONE_QST); + Tst_MAX_BYTES_INDEXES_ONE_QST); /* Get answers selected by user for this question (row[3]) */ Str_Copy (Print->PrintedQuestions[NumQst].StrAnswers,row[3], - TstPrn_MAX_BYTES_ANSWERS_ONE_QST); + Tst_MAX_BYTES_ANSWERS_ONE_QST); /* Replace each comma by a separator of multiple parameters */ /* In database commas are used as separators instead of special chars */ diff --git a/swad_test_print.h b/swad_test_print.h index f5427522..e65f78b3 100644 --- a/swad_test_print.h +++ b/swad_test_print.h @@ -35,13 +35,6 @@ /***************************** Public constants ******************************/ /*****************************************************************************/ -#define TstPrn_MAX_BYTES_INDEXES_ONE_QST (Tst_MAX_OPTIONS_PER_QUESTION * (3 + 1)) - -#define TstPrn_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127 -#define TstPrn_MAX_BYTES_ANSWERS_ONE_QST ((TstPrn_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 - -#define TstPrn_SCORE_MAX 10 // Maximum score of a test (10 in Spain). Must be unsigned! // TODO: Make this configurable by teachers - /*****************************************************************************/ /******************************* Public types ********************************/ /*****************************************************************************/ @@ -49,8 +42,8 @@ struct TstPrn_PrintedQuestion { long QstCod; // Question code - char StrIndexes[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc. - char StrAnswers[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user + char StrIndexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc. + char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user double Score; // Question score bool AnswerIsNotBlank; // Answer not blank? }; @@ -73,19 +66,20 @@ struct TstPrn_Print /*****************************************************************************/ void TstPrn_ResetResult (struct TstPrn_Print *Print); -void TstPrn_CreateExamInDB (struct TstPrn_Print *Print); +void TstPrn_CreatePrintInDB (struct TstPrn_Print *Print); void TstPrn_UpdateExamInDB (const struct TstPrn_Print *Print); void TstPrn_ShowExamAfterAssess (struct TstPrn_Print *Print); -void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print, +void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print, bool UpdateQstScore); -void TstPrn_ComputeChoiceAnsScore (struct TstPrn_Print *Print, - unsigned NumQst, +void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion, + struct Tst_Question *Question); +void TstPrn_ComputeChoiceAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, struct Tst_Question *Question); -void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. +void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]); -void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1], +void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1], bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]); void TstPrn_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade); diff --git a/swad_test_type.h b/swad_test_type.h index 3a2733db..7d6e0ce2 100644 --- a/swad_test_type.h +++ b/swad_test_type.h @@ -38,6 +38,13 @@ #define Tst_MAX_OPTIONS_PER_QUESTION 10 +#define Tst_MAX_BYTES_INDEXES_ONE_QST (Tst_MAX_OPTIONS_PER_QUESTION * (3 + 1)) + +#define Tst_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127 +#define Tst_MAX_BYTES_ANSWERS_ONE_QST ((Tst_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 + +#define Tst_SCORE_MAX 10 // Maximum score of a test (10 in Spain). Must be unsigned! // TODO: Make this configurable by teachers + /*****************************************************************************/ /******************************* Public types ********************************/ /*****************************************************************************/ diff --git a/swad_user.c b/swad_user.c index ca73a38a..4c7225a4 100644 --- a/swad_user.c +++ b/swad_user.c @@ -4091,7 +4091,7 @@ long Usr_GetRamdomStdFromCrs (long CrsCod) " from the current course", "SELECT UsrCod FROM crs_usr" " WHERE CrsCod=%ld AND Role=%u" - " ORDER BY RAND(NOW()) LIMIT 1", + " ORDER BY RAND() LIMIT 1", CrsCod,(unsigned) Rol_STD)) { /***** Get user code *****/ @@ -4121,7 +4121,7 @@ long Usr_GetRamdomStdFromGrp (long GrpCod) "SELECT crs_grp_usr.UsrCod FROM crs_grp_usr,crs_usr" " WHERE crs_grp_usr.GrpCod=%ld" " AND crs_grp_usr.UsrCod=crs_usr.UsrCod" - " AND crs_usr.Role=%u ORDER BY RAND(NOW()) LIMIT 1", + " AND crs_usr.Role=%u ORDER BY RAND() LIMIT 1", GrpCod,(unsigned) Rol_STD)) { /***** Get user code *****/