Version 21.16: Sep 24, 2021 New module swad_match_database for database queries related to game matches.

This commit is contained in:
acanas 2021-09-24 21:49:06 +02:00
parent b1bc902f24
commit f0681a98aa
14 changed files with 719 additions and 458 deletions

View File

@ -63,8 +63,9 @@ OBJS = swad_account.o swad_account_database.o swad_action.o swad_admin.o \
swad_log.o swad_log_database.o swad_logo.o \
swad_MAC.o swad_mail.o swad_mail_database.o swad_main.o \
swad_maintenance.o swad_map.o swad_mark.o swad_mark_database.o \
swad_match.o swad_match_print.o swad_match_result.o swad_media.o \
swad_media_database.o swad_menu.o swad_message.o swad_MFU.o \
swad_match.o swad_match_database.o swad_match_print.o \
swad_match_result.o swad_media.o swad_media_database.o swad_menu.o \
swad_message.o swad_MFU.o \
swad_network.o swad_nickname.o swad_notice.o swad_notification.o \
swad_notification_database.o swad_pagination.o swad_parameter.o \
swad_password.o swad_photo.o swad_place.o swad_plugin.o swad_privacy.o \

View File

@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
*/
#define Log_PLATFORM_VERSION "SWAD 21.15 (2021-09-24)"
#define Log_PLATFORM_VERSION "SWAD 21.16 (2021-09-24)"
#define CSS_FILE "swad20.45.css"
#define JS_FILE "swad20.69.1.js"
/*
TODO: Rename CENTRE to CENTER in help wiki.
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
Version 21.16: Sep 24, 2021 New module swad_match_database for database queries related to game matches. (316995 lines)
Version 21.15: Sep 24, 2021 New module swad_mark_database for database queries related to files of marks. (316792 lines)
Version 21.14.1: Sep 23, 2021 Queries moved to module swad_mail_database. (316687 lines)
Version 21.14: Sep 22, 2021 New module swad_mail_database for database queries related to mail domains. (316594 lines)

View File

@ -1750,7 +1750,7 @@ void Exa_DB_RemoveAllGrpsOfType (long GrpTypCod)
/******************** Remove one group from all sessions *********************/
/*****************************************************************************/
void Exa_DB_RemoveGrpAssociatedToExamSess (long GrpCod)
void Exa_DB_RemoveGroup (long GrpCod)
{
/***** Remove group from all the sessions *****/
DB_QueryDELETE ("can not remove group"

View File

@ -135,7 +135,7 @@ void Exa_DB_RemoveAllGrpsFromExa (long ExaCod);
void Exa_DB_RemoveAllGrpsFromCrs (long CrsCod);
void Exa_DB_RemoveAllGrpsFromSes (long SesCod);
void Exa_DB_RemoveAllGrpsOfType (long GrpTypCod);
void Exa_DB_RemoveGrpAssociatedToExamSess (long GrpCod);
void Exa_DB_RemoveGroup (long GrpCod);
//---------------------------------- Prints -----------------------------------
long Exa_DB_CreatePrint (const struct ExaPrn_Print *Print);

View File

@ -43,6 +43,7 @@
#include "swad_hierarchy_level.h"
#include "swad_HTML.h"
#include "swad_match.h"
#include "swad_match_database.h"
#include "swad_match_result.h"
#include "swad_pagination.h"
#include "swad_role.h"
@ -1654,7 +1655,7 @@ static void Gam_ListGameQuestions (struct Gam_Games *Games,struct Gam_Game *Game
bool ICanEditQuestions = Gam_CheckIfEditable (Game);
/***** Get data of questions from database *****/
NumQsts = Gam_DB_GetGameQuestions (&mysql_res,Game->GamCod);
NumQsts = Gam_DB_GetGameQuestionsBasic (&mysql_res,Game->GamCod);
/***** Begin box *****/
Games->GamCod = Game->GamCod;
@ -1743,17 +1744,16 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Gam_Games *Games,
/***** Get question data *****/
row = mysql_fetch_row (mysql_res);
/*
row[0] QstInd
row[1] QstCod
row[0] QstCod
row[1] QstInd
*/
/* Get question code (row[0]) */
Question.QstCod = Str_ConvertStrCodToLongCod (row[0]);
/* Get question index (row[0]) */
QstInd = Str_ConvertStrToUnsigned (row[0]);
/* Get question index (row[1]) */
QstInd = Str_ConvertStrToUnsigned (row[1]);
snprintf (StrQstInd,sizeof (StrQstInd),"%u",QstInd);
/* Get question code (row[1]) */
Question.QstCod = Str_ConvertStrCodToLongCod (row[1]);
/* Initialize context */
Games->GamCod = GamCod;
Games->QstInd = QstInd;

View File

@ -511,22 +511,43 @@ unsigned Gam_DB_GetNumQstsGame (long GamCod)
" WHERE GamCod=%ld",
GamCod);
}
/*****************************************************************************/
/************************ Get the questions of a game ************************/
/*****************************************************************************/
unsigned Gam_DB_GetGameQuestions (MYSQL_RES **mysql_res,long GamCod)
unsigned Gam_DB_GetGameQuestionsBasic (MYSQL_RES **mysql_res,long GamCod)
{
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get game questions",
"SELECT QstInd," // row[0]
"QstCod" // row[1]
"SELECT QstCod," // row[0]
"QstInd" // row[1]
" FROM gam_questions"
" WHERE GamCod=%ld"
" ORDER BY QstInd",
GamCod);
}
/*****************************************************************************/
/************************ Get the questions of a game ************************/
/*****************************************************************************/
unsigned Gam_DB_GetGameQuestionsFull (MYSQL_RES **mysql_res,long GamCod)
{
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get questions of a game",
"SELECT gam_questions.QstCod," // row[0]
"gam_questions.QstInd," // row[1]
"tst_questions.AnsType," // row[2]
"tst_questions.Shuffle" // row[3]
" FROM gam_questions,"
"tst_questions"
" WHERE gam_questions.GamCod=%ld"
" AND gam_questions.QstCod=tst_questions.QstCod"
" ORDER BY gam_questions.QstInd",
GamCod);
}
/*****************************************************************************/
/************ Get question code given game and index of question *************/
/*****************************************************************************/

View File

@ -61,7 +61,8 @@ void Gam_DB_LockTable (void);
void Gam_DB_UnlockTable (void);
unsigned Gam_DB_GetNumQstsGame (long GamCod);
unsigned Gam_DB_GetGameQuestions (MYSQL_RES **mysql_res,long GamCod);
unsigned Gam_DB_GetGameQuestionsBasic (MYSQL_RES **mysql_res,long GamCod);
unsigned Gam_DB_GetGameQuestionsFull (MYSQL_RES **mysql_res,long GamCod);
long Gam_DB_GetQstCodFromQstInd (long GamCod,unsigned QstInd);
unsigned Gam_DB_GetQstIndFromQstCod (long GamCod,long QstCod);
unsigned Gam_DB_GetMaxQuestionIndexInGame (long GamCod);

View File

@ -44,7 +44,7 @@
#include "swad_group.h"
#include "swad_group_database.h"
#include "swad_HTML.h"
#include "swad_match.h"
#include "swad_match_database.h"
#include "swad_notification.h"
#include "swad_parameter.h"
#include "swad_program.h"
@ -3563,7 +3563,7 @@ static void Grp_RemoveGroupCompletely (void)
Mch_DB_RemoveGroup (GrpDat.GrpCod);
/***** Remove this group from all exam sessions *****/
Exa_DB_RemoveGrpAssociatedToExamSess (GrpDat.GrpCod);
Exa_DB_RemoveGroup (GrpDat.GrpCod);
/***** Remove this group from all surveys *****/
Svy_DB_RemoveGroup (GrpDat.GrpCod);

View File

@ -42,6 +42,7 @@
#include "swad_group_database.h"
#include "swad_HTML.h"
#include "swad_match.h"
#include "swad_match_database.h"
#include "swad_match_result.h"
#include "swad_role.h"
#include "swad_setting.h"
@ -82,18 +83,6 @@ typedef enum
/***************************** Private constants *****************************/
/*****************************************************************************/
const char *Mch_ShowingStringsDB[Mch_NUM_SHOWING] =
{
[Mch_START ] = "start",
[Mch_STEM ] = "stem",
[Mch_ANSWERS] = "answers",
[Mch_RESULTS] = "results",
[Mch_END ] = "end",
};
#define Mch_MAX_COLS 4
#define Mch_NUM_COLS_DEFAULT 1
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
@ -136,14 +125,8 @@ static void Mch_ListOneOrMoreMatchesResultTch (struct Gam_Games *Games,
static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res,
struct Mch_Match *Match);
static Mch_Showing_t Mch_GetShowingFromStr (const char *Str);
static void Mch_RemoveMatchFromAllTables (long MchCod);
static void Mch_DB_RemoveMatchFromTable (long MchCod,const char *TableName);
static void Mch_DB_RemoveMatchesInGameFromTable (long GamCod,const char *TableName);
static void Mch_DB_RemoveMatchesInCourseFromTable (long CrsCod,const char *TableName);
static void Mch_DB_RemoveMatchesMadeByUsrFromTable (long UsrCod,const char *TableName);
static void Mch_DB_RemoveMatchesMadeByUsrInCrsFromTable (long UsrCod,long CrsCod,const char *TableName);
static void Mch_PutParamsPlay (void *MchCod);
static void Mch_PutParamMchCod (long MchCod);
@ -1060,7 +1043,7 @@ static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res,
Match->Status.QstCod = Str_ConvertStrCodToLongCod (row[7]);
/* Get what to show (stem, answers, results) (row(8)) */
Match->Status.Showing = Mch_GetShowingFromStr (row[8]);
Match->Status.Showing = Mch_DB_GetShowingFromStr (row[8]);
/* Get countdown (row[9]) */
Match->Status.Countdown = Str_ConvertStrCodToLongCod (row[9]);
@ -1084,23 +1067,6 @@ static void Mch_GetMatchDataFromRow (MYSQL_RES *mysql_res,
Match->Status.Playing = Mch_DB_GetIfMatchIsBeingPlayed (Match->MchCod);
}
/*****************************************************************************/
/****************** Get parameter with what is being shown *******************/
/*****************************************************************************/
static Mch_Showing_t Mch_GetShowingFromStr (const char *Str)
{
Mch_Showing_t Showing;
for (Showing = (Mch_Showing_t) 0;
Showing <= (Mch_Showing_t) (Mch_NUM_SHOWING - 1);
Showing++)
if (!strcmp (Str,Mch_ShowingStringsDB[Showing]))
return Showing;
return (Mch_Showing_t) Mch_SHOWING_DEFAULT;
}
/*****************************************************************************/
/************** Request the removal of a match (game instance) ***************/
/*****************************************************************************/
@ -1192,20 +1158,7 @@ static void Mch_RemoveMatchFromAllTables (long MchCod)
Mch_DB_RemoveMatchFromTable (MchCod,"mch_indexes");
/***** Remove match from main table *****/
DB_QueryDELETE ("can not remove match",
"DELETE FROM mch_matches"
" WHERE MchCod=%ld",
MchCod);
}
static void Mch_DB_RemoveMatchFromTable (long MchCod,const char *TableName)
{
/***** Remove match from secondary table *****/
DB_QueryDELETE ("can not remove match from table",
"DELETE FROM %s"
" WHERE MchCod=%ld",
TableName,
MchCod);
Mch_DB_RemoveMatchFromTable (MchCod,"mch_matches");
}
/*****************************************************************************/
@ -1215,34 +1168,16 @@ static void Mch_DB_RemoveMatchFromTable (long MchCod,const char *TableName)
void Mch_RemoveMatchesInGameFromAllTables (long GamCod)
{
/***** Remove matches from secondary tables *****/
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_players");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_playing");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_results");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_answers");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_times");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_groups");
Mch_DB_RemoveMatchesInGameFromTable (GamCod,"mch_indexes");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_players");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_playing");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_results");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_answers");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_times");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_groups");
Mch_DB_RemoveMatchesInGameFromOtherTable (GamCod,"mch_indexes");
/***** Remove matches from main table *****/
DB_QueryDELETE ("can not remove matches of a game",
"DELETE FROM mch_matches"
" WHERE GamCod=%ld",
GamCod);
}
static void Mch_DB_RemoveMatchesInGameFromTable (long GamCod,const char *TableName)
{
/***** Remove matches in game from secondary table *****/
DB_QueryDELETE ("can not remove matches of a game from table",
"DELETE FROM %s"
" USING mch_matches,"
"%s"
" WHERE mch_matches.GamCod=%ld"
" AND mch_matches.MchCod=%s.MchCod",
TableName,
TableName,
GamCod,
TableName);
/***** Remove matches in game from main table *****/
Mch_DB_RemoveMatchesInGameFromMainTable (GamCod);
}
/*****************************************************************************/
@ -1252,39 +1187,16 @@ static void Mch_DB_RemoveMatchesInGameFromTable (long GamCod,const char *TableNa
void Mch_RemoveMatchesInCourseFromAllTables (long CrsCod)
{
/***** Remove matches from secondary tables *****/
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_players");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_playing");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_results");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_answers");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_times");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_groups");
Mch_DB_RemoveMatchesInCourseFromTable (CrsCod,"mch_indexes");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_players");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_playing");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_results");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_answers");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_times");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_groups");
Mch_DB_RemoveMatchesInCrsFromOtherTable (CrsCod,"mch_indexes");
/***** Remove matches from main table *****/
DB_QueryDELETE ("can not remove matches of a course",
"DELETE FROM mch_matches"
" USING gam_games,"
"mch_matches"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod",
CrsCod);
}
static void Mch_DB_RemoveMatchesInCourseFromTable (long CrsCod,const char *TableName)
{
/***** Remove matches in course from secondary table *****/
DB_QueryDELETE ("can not remove matches of a course from table",
"DELETE FROM %s"
" USING gam_games,"
"mch_matches,"
"%s"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod"
" AND mch_matches.MchCod=%s.MchCod",
TableName,
TableName,
CrsCod,
TableName);
/***** Remove matches in course from main table *****/
Mch_DB_RemoveMatchesInCrsFromMainTable (CrsCod);
}
/*****************************************************************************/
@ -1299,16 +1211,6 @@ void Mch_RemoveMatchesMadeByUsrInAllCrss (long UsrCod)
Mch_DB_RemoveMatchesMadeByUsrFromTable (UsrCod,"mch_answers");
}
static void Mch_DB_RemoveMatchesMadeByUsrFromTable (long UsrCod,const char *TableName)
{
/***** Remove matches in course from secondary table *****/
DB_QueryDELETE ("can not remove matches of a user from table",
"DELETE FROM %s"
" WHERE UsrCod=%ld",
TableName,
UsrCod);
}
/*****************************************************************************/
/***************** Remove matches made by user in a course *******************/
/*****************************************************************************/
@ -1321,26 +1223,6 @@ void Mch_RemoveMatchesMadeByUsrInCrs (long UsrCod,long CrsCod)
Mch_DB_RemoveMatchesMadeByUsrInCrsFromTable (UsrCod,CrsCod,"mch_answers");
}
static void Mch_DB_RemoveMatchesMadeByUsrInCrsFromTable (long UsrCod,long CrsCod,const char *TableName)
{
/***** Remove matches in course from secondary table *****/
DB_QueryDELETE ("can not remove matches of a user from table",
"DELETE FROM %s"
" USING gam_games,"
"mch_matches,"
"%s"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod"
" AND mch_matches.MchCod=%s.MchCod"
" AND %s.UsrCod=%ld",
TableName,
TableName,
CrsCod,
TableName,
TableName,
UsrCod);
}
/*****************************************************************************/
/************************ Edit a match (game instance) ***********************/
/*****************************************************************************/
@ -1701,12 +1583,7 @@ void Mch_ChangeMatch (void)
static void Mch_UpdateMatchTitleAndGrps (const struct Mch_Match *Match)
{
/***** Update match title into database *****/
DB_QueryUPDATE ("can not update match",
"UPDATE mch_matches"
" SET Title='%s'"
" WHERE MchCod=%ld",
Match->Title,
Match->MchCod);
Mch_DB_UpdateMatchTitle (Match);
/***** Update groups associated to the match *****/
Mch_DB_RemoveMatchFromTable (Match->MchCod,"mch_groups"); // Remove all groups associated to this match
@ -1756,30 +1633,7 @@ static long Mch_CreateMatch (long GamCod,char Title[Mch_MAX_BYTES_TITLE + 1])
long MchCod;
/***** Insert this new match into database *****/
MchCod =
DB_QueryINSERTandReturnCode ("can not create match",
"INSERT mch_matches"
" (GamCod,UsrCod,StartTime,EndTime,Title,"
"QstInd,QstCod,Showing,Countdown,"
"NumCols,ShowQstResults,ShowUsrResults)"
" VALUES"
" (%ld," // GamCod
"%ld," // UsrCod
"NOW()," // StartTime
"NOW()," // EndTime
"'%s'," // Title
"0," // QstInd: Match has not started, so not the first question yet
"-1," // QstCod: Non-existent question
"'%s'," // Showing: What is being shown
"-1," // Countdown: No countdown
"%u," // NumCols: Number of columns in answers
"'N'," // ShowQstResults: Don't show question results initially
"'N')", // ShowUsrResults: Don't show user results initially
GamCod,
Gbl.Usrs.Me.UsrDat.UsrCod, // Game creator
Title,
Mch_ShowingStringsDB[Mch_SHOWING_DEFAULT],
Mch_NUM_COLS_DEFAULT);
MchCod = Mch_DB_CreateMatch (GamCod,Title);
/***** Create indexes for answers *****/
Mch_CreateIndexes (GamCod,MchCod);
@ -1809,18 +1663,7 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
unsigned QstInd;
/***** Get questions of the game *****/
NumQsts = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions of a game",
"SELECT gam_questions.QstCod," // row[0]
"gam_questions.QstInd," // row[1]
"tst_questions.AnsType," // row[2]
"tst_questions.Shuffle" // row[3]
" FROM gam_questions,"
"tst_questions"
" WHERE gam_questions.GamCod=%ld"
" AND gam_questions.QstCod=tst_questions.QstCod"
" ORDER BY gam_questions.QstInd",
GamCod);
NumQsts = Gam_DB_GetGameQuestionsFull (&mysql_res,GamCod);
/***** For each question in game... *****/
for (NumQst = 0;
@ -1883,16 +1726,8 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
/***** Initialize list of answers to empty string *****/
StrAnswersOneQst[0] = '\0';
/***** Get questions of the game *****/
NumAnss = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions of a game",
"SELECT AnsInd" // row[0]
" FROM tst_answers"
" WHERE QstCod=%ld"
" ORDER BY %s",
Question->QstCod,
Question->Answer.Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order
"AnsInd");
/***** Get suffled/not-shuffled answers indexes of question *****/
NumAnss = Tst_DB_GetShuffledAnswersIndexes (&mysql_res,Question);
/***** For each answer in question... *****/
for (NumAns = 0;
@ -1915,14 +1750,7 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
DB_FreeMySQLResult (&mysql_res);
/***** Create entry for this question in table of match indexes *****/
DB_QueryINSERT ("can not create match indexes",
"INSERT INTO mch_indexes"
" (MchCod,QstInd,Indexes)"
" VALUES"
" (%ld,%u,'%s')",
MchCod,
QstInd,
StrAnswersOneQst);
Mch_DB_CreateQstIndexes (MchCod,QstInd,StrAnswersOneQst);
}
/*****************************************************************************/
@ -1935,14 +1763,7 @@ void Mch_GetIndexes (long MchCod,unsigned QstInd,
char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1];
/***** Get indexes for a question from database *****/
DB_QuerySELECTString (StrIndexesOneQst,sizeof (StrIndexesOneQst) - 1,
"can not get data of a question",
"SELECT Indexes" // row[0]
" FROM mch_indexes"
" WHERE MchCod=%ld"
" AND QstInd=%u",
MchCod,
QstInd);
Mch_DB_GetIndexes (MchCod,QstInd,StrIndexesOneQst);
if (!StrIndexesOneQst[0])
Err_ShowErrorAndExit ("No indexes found for a question.");
@ -1958,100 +1779,23 @@ static void Mch_CreateGrps (long MchCod)
{
unsigned NumGrpSel;
/***** Create groups associated to the match *****/
for (NumGrpSel = 0;
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
NumGrpSel++)
/* Create group */
DB_QueryINSERT ("can not associate a group to a match",
"INSERT INTO mch_groups"
" (MchCod,GrpCod)"
" VALUES"
" (%ld,%ld)",
MchCod,
Mch_DB_AssociateGroupToMatch (MchCod,
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]);
}
/*****************************************************************************/
/********************* Remove one group from all matches *********************/
/*****************************************************************************/
void Mch_DB_RemoveGroup (long GrpCod)
{
/***** Remove group from all the matches *****/
DB_QueryDELETE ("can not remove group"
" from the associations between matches and groups",
"DELETE FROM mch_groups"
" WHERE GrpCod=%ld",
GrpCod);
}
/*****************************************************************************/
/***************** Remove groups of one type from all matches ****************/
/*****************************************************************************/
void Mch_DB_RemoveGroupsOfType (long GrpTypCod)
{
/***** Remove group from all the matches *****/
DB_QueryDELETE ("can not remove groups of a type"
" from the associations between matches and groups",
"DELETE FROM mch_groups"
" USING grp_groups,"
"mch_groups"
" WHERE grp_groups.GrpTypCod=%ld"
" AND grp_groups.GrpCod=mch_groups.GrpCod",
GrpTypCod);
}
/*****************************************************************************/
/***************** Insert/update a game match being played *******************/
/*****************************************************************************/
static void Mch_UpdateMatchStatusInDB (const struct Mch_Match *Match)
{
char *MchSubQuery;
/***** Update end time only if match is currently being played *****/
if (Match->Status.Playing) // Match is being played
{
if (asprintf (&MchSubQuery,"mch_matches.EndTime=NOW(),") < 0)
Err_NotEnoughMemoryExit ();
}
else // Match is paused, not being played
{
if (asprintf (&MchSubQuery,"%s","") < 0)
Err_NotEnoughMemoryExit ();
}
/***** Update match status in database *****/
DB_QueryUPDATE ("can not update match being played",
"UPDATE mch_matches,"
"gam_games"
" SET %s"
"mch_matches.QstInd=%u,"
"mch_matches.QstCod=%ld,"
"mch_matches.Showing='%s',"
"mch_matches.Countdown=%ld,"
"mch_matches.NumCols=%u,"
"mch_matches.ShowQstResults='%c',"
"mch_matches.ShowUsrResults='%c'"
" WHERE mch_matches.MchCod=%ld"
" AND mch_matches.GamCod=gam_games.GamCod"
" AND gam_games.CrsCod=%ld", // Extra check
MchSubQuery,
Match->Status.QstInd,
Match->Status.QstCod,
Mch_ShowingStringsDB[Match->Status.Showing],
Match->Status.Countdown,
Match->Status.NumCols,
Match->Status.ShowQstResults ? 'Y' :
'N',
Match->Status.ShowUsrResults ? 'Y' :
'N',
Match->MchCod,
Gbl.Hierarchy.Crs.CrsCod);
free (MchSubQuery);
Mch_DB_UpdateMatchStatus (Match);
/***** Update match as being/not-being played */
if (Match->Status.Playing) // Match is being played
/* Update match as being played */
Mch_DB_UpdateMatchAsBeingPlayed (Match->MchCod);
@ -2070,17 +1814,7 @@ static void Mch_UpdateElapsedTimeInQuestion (const struct Mch_Match *Match)
if (Match->Status.Playing && // Match is being played
Match->Status.Showing != Mch_START &&
Match->Status.Showing != Mch_END)
DB_QueryINSERT ("can not update elapsed time in question",
"INSERT INTO mch_times"
" (MchCod,QstInd,ElapsedTime)"
" VALUES"
" (%ld,%u,SEC_TO_TIME(%u))"
" ON DUPLICATE KEY"
" UPDATE ElapsedTime=ADDTIME(ElapsedTime,SEC_TO_TIME(%u))",
Match->MchCod,
Match->Status.QstInd,
Cfg_SECONDS_TO_REFRESH_MATCH_TCH,
Cfg_SECONDS_TO_REFRESH_MATCH_TCH);
Mch_DB_UpdateElapsedTimeInQuestion (Match->MchCod,Match->Status.QstInd);
}
/*****************************************************************************/
@ -2504,46 +2238,6 @@ static void Mch_ShowMatchStatusForStd (struct Mch_Match *Match,Mch_Update_t Upda
Mch_ShowRightColumnStd (Match,&UsrAnswer,Update);
}
/*****************************************************************************/
/********************** Get number of matches in a game **********************/
/*****************************************************************************/
unsigned Mch_DB_GetNumMchsInGame (long GamCod)
{
/***** Trivial check *****/
if (GamCod < 0) // A non-existing game...
return 0; // ...has no matches
/***** Get number of matches in a game from database *****/
return (unsigned)
DB_QueryCOUNT ("can not get number of matches of a game",
"SELECT COUNT(*)"
" FROM mch_matches"
" WHERE GamCod=%ld",
GamCod);
}
/*****************************************************************************/
/*************** Get number of unfinished matches in a game ******************/
/*****************************************************************************/
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod)
{
/***** Trivial check *****/
if (GamCod < 0) // A non-existing game...
return 0; // ...has no matches
/***** Get number of matches in a game from database *****/
return (unsigned)
DB_QueryCOUNT ("can not get number of unfinished matches of a game",
"SELECT COUNT(*)"
" FROM mch_matches"
" WHERE GamCod=%ld"
" AND Showing<>'%s'",
GamCod,
Mch_ShowingStringsDB[Mch_END]);
}
/*****************************************************************************/
/************ Check if I belong to any of the groups of a match **************/
/*****************************************************************************/
@ -4516,21 +4210,3 @@ unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod)
" WHERE GamCod=%ld",
GamCod);
}
/*****************************************************************************/
/********************** Remove answers of a game question ********************/
/*****************************************************************************/
void Mch_DB_RemAnswersOfAQuestion (long GamCod,unsigned QstInd)
{
/***** Remove answers from all matches of this game *****/
DB_QueryDELETE ("can not remove the answers of a question",
"DELETE FROM mch_answers"
" USING mch_matches,"
"mch_answers"
" WHERE mch_matches.GamCod=%ld" // From all matches of this game...
" AND mch_matches.MchCod=mch_answers.MchCod"
" AND mch_answers.QstInd=%u", // ...remove only answers to this question
GamCod,
QstInd);
}

View File

@ -52,6 +52,10 @@ typedef enum
} Mch_Showing_t;
#define Mch_SHOWING_DEFAULT Mch_START
/* Columns */
#define Mch_MAX_COLS 4
#define Mch_NUM_COLS_DEFAULT 1
struct Mch_Match
{
long MchCod;
@ -119,18 +123,12 @@ void Mch_ResumeMatch (void);
void Mch_GetIndexes (long MchCod,unsigned QstInd,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void Mch_DB_RemoveGroup (long GrpCod);
void Mch_DB_RemoveGroupsOfType (long GrpTypCod);
void Mch_PlayPauseMatch (void);
void Mch_ChangeNumColsMch (void);
void Mch_ToggleVisResultsMchQst (void);
void Mch_BackMatch (void);
void Mch_ForwardMatch (void);
unsigned Mch_DB_GetNumMchsInGame (long GamCod);
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod);
bool Mch_CheckIfICanPlayThisMatchBasedOnGrps (const struct Mch_Match *Match);
bool Mch_RegisterMeAsPlayerInMatch (struct Mch_Match *Match);
@ -161,6 +159,5 @@ void Mch_DrawBarNumUsrs (unsigned NumRespondersAns,unsigned NumRespondersQst,boo
void Mch_DB_UpdateIndexesOfQstsGreaterThan (long GamCod,unsigned QstInd);
unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod);
void Mch_DB_RemAnswersOfAQuestion (long GamCod,unsigned QstInd);
#endif

463
swad_match_database.c Normal file
View File

@ -0,0 +1,463 @@
// swad_match_database.c: matches in games using remote control, operations woth database
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2021 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
// #include <linux/limits.h> // For PATH_MAX
// #include <stddef.h> // For NULL
#include <stdio.h> // For asprintf
// #include <stdlib.h> // For free
#include <string.h> // For string functions
#include "swad_database.h"
// #include "swad_date.h"
#include "swad_error.h"
// #include "swad_form.h"
// #include "swad_game.h"
// #include "swad_game_database.h"
#include "swad_global.h"
// #include "swad_group_database.h"
// #include "swad_HTML.h"
// #include "swad_match.h"
#include "swad_match_database.h"
// #include "swad_match_result.h"
// #include "swad_role.h"
// #include "swad_setting.h"
// #include "swad_test.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
const char *Mch_ShowingStringsDB[Mch_NUM_SHOWING] =
{
[Mch_START ] = "start",
[Mch_STEM ] = "stem",
[Mch_ANSWERS] = "answers",
[Mch_RESULTS] = "results",
[Mch_END ] = "end",
};
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
/*****************************************************************************/
/********************** Create a new match in a game *************************/
/*****************************************************************************/
long Mch_DB_CreateMatch (long GamCod,char Title[Mch_MAX_BYTES_TITLE + 1])
{
return
DB_QueryINSERTandReturnCode ("can not create match",
"INSERT mch_matches"
" (GamCod,UsrCod,StartTime,EndTime,Title,"
"QstInd,QstCod,Showing,Countdown,"
"NumCols,ShowQstResults,ShowUsrResults)"
" VALUES"
" (%ld," // GamCod
"%ld," // UsrCod
"NOW()," // StartTime
"NOW()," // EndTime
"'%s'," // Title
"0," // QstInd: Match has not started, so not the first question yet
"-1," // QstCod: Non-existent question
"'%s'," // Showing: What is being shown
"-1," // Countdown: No countdown
"%u," // NumCols: Number of columns in answers
"'N'," // ShowQstResults: Don't show question results initially
"'N')", // ShowUsrResults: Don't show user results initially
GamCod,
Gbl.Usrs.Me.UsrDat.UsrCod, // Game creator
Title,
Mch_ShowingStringsDB[Mch_SHOWING_DEFAULT],
Mch_NUM_COLS_DEFAULT);
}
/*****************************************************************************/
/******************** Update a game match being played ***********************/
/*****************************************************************************/
void Mch_DB_UpdateMatchStatus (const struct Mch_Match *Match)
{
char *MchSubQuery;
/***** Update end time only if match is currently being played *****/
if (Match->Status.Playing) // Match is being played
{
if (asprintf (&MchSubQuery,"mch_matches.EndTime=NOW(),") < 0)
Err_NotEnoughMemoryExit ();
}
else // Match is paused, not being played
{
if (asprintf (&MchSubQuery,"%s","") < 0)
Err_NotEnoughMemoryExit ();
}
/***** Update match status in database *****/
DB_QueryUPDATE ("can not update match being played",
"UPDATE mch_matches,"
"gam_games"
" SET %s"
"mch_matches.QstInd=%u,"
"mch_matches.QstCod=%ld,"
"mch_matches.Showing='%s',"
"mch_matches.Countdown=%ld,"
"mch_matches.NumCols=%u,"
"mch_matches.ShowQstResults='%c',"
"mch_matches.ShowUsrResults='%c'"
" WHERE mch_matches.MchCod=%ld"
" AND mch_matches.GamCod=gam_games.GamCod"
" AND gam_games.CrsCod=%ld", // Extra check
MchSubQuery,
Match->Status.QstInd,
Match->Status.QstCod,
Mch_ShowingStringsDB[Match->Status.Showing],
Match->Status.Countdown,
Match->Status.NumCols,
Match->Status.ShowQstResults ? 'Y' :
'N',
Match->Status.ShowUsrResults ? 'Y' :
'N',
Match->MchCod,
Gbl.Hierarchy.Crs.CrsCod);
free (MchSubQuery);
}
/*****************************************************************************/
/********************* Update title of an existing match *********************/
/*****************************************************************************/
void Mch_DB_UpdateMatchTitle (const struct Mch_Match *Match)
{
DB_QueryUPDATE ("can not update match",
"UPDATE mch_matches"
" SET Title='%s'"
" WHERE MchCod=%ld",
Match->Title,
Match->MchCod);
}
/*****************************************************************************/
/****************** Get parameter with what is being shown *******************/
/*****************************************************************************/
Mch_Showing_t Mch_DB_GetShowingFromStr (const char *Str)
{
Mch_Showing_t Showing;
for (Showing = (Mch_Showing_t) 0;
Showing <= (Mch_Showing_t) (Mch_NUM_SHOWING - 1);
Showing++)
if (!strcmp (Str,Mch_ShowingStringsDB[Showing]))
return Showing;
return (Mch_Showing_t) Mch_SHOWING_DEFAULT;
}
/*****************************************************************************/
/********************** Get number of matches in a game **********************/
/*****************************************************************************/
unsigned Mch_DB_GetNumMchsInGame (long GamCod)
{
/***** Trivial check *****/
if (GamCod < 0) // A non-existing game...
return 0; // ...has no matches
/***** Get number of matches in a game from database *****/
return (unsigned)
DB_QueryCOUNT ("can not get number of matches of a game",
"SELECT COUNT(*)"
" FROM mch_matches"
" WHERE GamCod=%ld",
GamCod);
}
/*****************************************************************************/
/*************** Get number of unfinished matches in a game ******************/
/*****************************************************************************/
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod)
{
/***** Trivial check *****/
if (GamCod < 0) // A non-existing game...
return 0; // ...has no matches
/***** Get number of matches in a game from database *****/
return (unsigned)
DB_QueryCOUNT ("can not get number of unfinished matches of a game",
"SELECT COUNT(*)"
" FROM mch_matches"
" WHERE GamCod=%ld"
" AND Showing<>'%s'",
GamCod,
Mch_ShowingStringsDB[Mch_END]);
}
/*****************************************************************************/
/************************* Remove match from table ***************************/
/*****************************************************************************/
void Mch_DB_RemoveMatchFromTable (long MchCod,const char *TableName)
{
DB_QueryDELETE ("can not remove match from table",
"DELETE FROM %s"
" WHERE MchCod=%ld",
TableName,
MchCod);
}
/*****************************************************************************/
/****************** Remove matches in game from main table *******************/
/*****************************************************************************/
void Mch_DB_RemoveMatchesInGameFromMainTable (long GamCod)
{
DB_QueryDELETE ("can not remove matches of a game",
"DELETE FROM mch_matches"
" WHERE GamCod=%ld",
GamCod);
}
/*****************************************************************************/
/***************** Remove matches in game from secondary table ***************/
/*****************************************************************************/
void Mch_DB_RemoveMatchesInGameFromOtherTable (long GamCod,const char *TableName)
{
DB_QueryDELETE ("can not remove matches of a game from table",
"DELETE FROM %s"
" USING mch_matches,"
"%s"
" WHERE mch_matches.GamCod=%ld"
" AND mch_matches.MchCod=%s.MchCod",
TableName,
TableName,
GamCod,
TableName);
}
/*****************************************************************************/
/***************** Remove matches in course from main table ******************/
/*****************************************************************************/
void Mch_DB_RemoveMatchesInCrsFromMainTable (long CrsCod)
{
DB_QueryDELETE ("can not remove matches of a course",
"DELETE FROM mch_matches"
" USING gam_games,"
"mch_matches"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod",
CrsCod);
}
/*****************************************************************************/
/*************** Remove matches in course from secondary table ***************/
/*****************************************************************************/
void Mch_DB_RemoveMatchesInCrsFromOtherTable (long CrsCod,const char *TableName)
{
DB_QueryDELETE ("can not remove matches of a course from table",
"DELETE FROM %s"
" USING gam_games,"
"mch_matches,"
"%s"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod"
" AND mch_matches.MchCod=%s.MchCod",
TableName,
TableName,
CrsCod,
TableName);
}
/*****************************************************************************/
/****************** Remove matches made by a user from table *****************/
/*****************************************************************************/
void Mch_DB_RemoveMatchesMadeByUsrFromTable (long UsrCod,const char *TableName)
{
DB_QueryDELETE ("can not remove matches of a user from table",
"DELETE FROM %s"
" WHERE UsrCod=%ld",
TableName,
UsrCod);
}
/*****************************************************************************/
/******* Remove matches made by a user in a course from secondary table ******/
/*****************************************************************************/
void Mch_DB_RemoveMatchesMadeByUsrInCrsFromTable (long UsrCod,long CrsCod,
const char *TableName)
{
DB_QueryDELETE ("can not remove matches of a user from table",
"DELETE FROM %s"
" USING gam_games,"
"mch_matches,"
"%s"
" WHERE gam_games.CrsCod=%ld"
" AND gam_games.GamCod=mch_matches.GamCod"
" AND mch_matches.MchCod=%s.MchCod"
" AND %s.UsrCod=%ld",
TableName,
TableName,
CrsCod,
TableName,
TableName,
UsrCod);
}
/*****************************************************************************/
/******************** Create group associated to a match *********************/
/*****************************************************************************/
void Mch_DB_AssociateGroupToMatch (long MchCod,long GrpCod)
{
DB_QueryINSERT ("can not associate a group to a match",
"INSERT INTO mch_groups"
" (MchCod,GrpCod)"
" VALUES"
" (%ld,%ld)",
MchCod,
GrpCod);
}
/*****************************************************************************/
/********************* Remove one group from all matches *********************/
/*****************************************************************************/
void Mch_DB_RemoveGroup (long GrpCod)
{
DB_QueryDELETE ("can not remove group"
" from the associations between matches and groups",
"DELETE FROM mch_groups"
" WHERE GrpCod=%ld",
GrpCod);
}
/*****************************************************************************/
/***************** Remove groups of one type from all matches ****************/
/*****************************************************************************/
void Mch_DB_RemoveGroupsOfType (long GrpTypCod)
{
DB_QueryDELETE ("can not remove groups of a type"
" from the associations between matches and groups",
"DELETE FROM mch_groups"
" USING grp_groups,"
"mch_groups"
" WHERE grp_groups.GrpTypCod=%ld"
" AND grp_groups.GrpCod=mch_groups.GrpCod",
GrpTypCod);
}
/*****************************************************************************/
/******** Remove answers of a question from all matches of this game *********/
/*****************************************************************************/
void Mch_DB_RemAnswersOfAQuestion (long GamCod,unsigned QstInd)
{
DB_QueryDELETE ("can not remove the answers of a question",
"DELETE FROM mch_answers"
" USING mch_matches,"
"mch_answers"
" WHERE mch_matches.GamCod=%ld" // From all matches of this game...
" AND mch_matches.MchCod=mch_answers.MchCod"
" AND mch_answers.QstInd=%u", // ...remove only answers to this question
GamCod,
QstInd);
}
/*****************************************************************************/
/********* Create entry for this question in table of match indexes **********/
/*****************************************************************************/
void Mch_DB_CreateQstIndexes (long MchCod,unsigned QstInd,
const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1])
{
DB_QueryINSERT ("can not create indexes of a question",
"INSERT INTO mch_indexes"
" (MchCod,QstInd,Indexes)"
" VALUES"
" (%ld,%u,'%s')",
MchCod,
QstInd,
StrAnswersOneQst);
}
/*****************************************************************************/
/***************** Get indexes for a question from database ******************/
/*****************************************************************************/
void Mch_DB_GetIndexes (long MchCod,unsigned QstInd,
char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1])
{
DB_QuerySELECTString (StrIndexesOneQst,Tst_MAX_BYTES_INDEXES_ONE_QST,
"can not get indexes of a question",
"SELECT Indexes" // row[0]
" FROM mch_indexes"
" WHERE MchCod=%ld"
" AND QstInd=%u",
MchCod,
QstInd);
}
/*****************************************************************************/
/********** Update elapsed time in current question (by a teacher) ***********/
/*****************************************************************************/
void Mch_DB_UpdateElapsedTimeInQuestion (long MchCod,long QstInd)
{
DB_QueryINSERT ("can not update elapsed time in question",
"INSERT INTO mch_times"
" (MchCod,QstInd,ElapsedTime)"
" VALUES"
" (%ld,%u,SEC_TO_TIME(%u))"
" ON DUPLICATE KEY"
" UPDATE ElapsedTime=ADDTIME(ElapsedTime,SEC_TO_TIME(%u))",
MchCod,
QstInd,
Cfg_SECONDS_TO_REFRESH_MATCH_TCH,
Cfg_SECONDS_TO_REFRESH_MATCH_TCH);
}

80
swad_match_database.h Normal file
View File

@ -0,0 +1,80 @@
// swad_match_database.h: matches in games using remote control, operations woth database
#ifndef _SWAD_MCH_DB
#define _SWAD_MCH_DB
/*
SWAD (Shared Workspace At a Distance in Spanish),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2021 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
// #include "swad_game.h"
#include "swad_match.h"
// #include "swad_match_print.h"
// #include "swad_scope.h"
// #include "swad_test.h"
/*****************************************************************************/
/************************** Public types and constants ***********************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Public prototypes *****************************/
/*****************************************************************************/
//------------------------------- Matches -------------------------------------
long Mch_DB_CreateMatch (long GamCod,char Title[Mch_MAX_BYTES_TITLE + 1]);
void Mch_DB_UpdateMatchStatus (const struct Mch_Match *Match);
void Mch_DB_UpdateMatchTitle (const struct Mch_Match *Match);
Mch_Showing_t Mch_DB_GetShowingFromStr (const char *Str);
unsigned Mch_DB_GetNumMchsInGame (long GamCod);
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod);
void Mch_DB_RemoveMatchFromTable (long MchCod,const char *TableName);
void Mch_DB_RemoveMatchesInGameFromMainTable (long GamCod);
void Mch_DB_RemoveMatchesInGameFromOtherTable (long GamCod,const char *TableName);
void Mch_DB_RemoveMatchesInCrsFromMainTable (long CrsCod);
void Mch_DB_RemoveMatchesInCrsFromOtherTable (long CrsCod,const char *TableName);
void Mch_DB_RemoveMatchesMadeByUsrFromTable (long UsrCod,const char *TableName);
void Mch_DB_RemoveMatchesMadeByUsrInCrsFromTable (long UsrCod,long CrsCod,
const char *TableName);
//---------------------------------Groups -------------------------------------
void Mch_DB_AssociateGroupToMatch (long MchCod,long GrpCod);
void Mch_DB_RemoveGroup (long GrpCod);
void Mch_DB_RemoveGroupsOfType (long GrpTypCod);
//-------------------------------- Answers ------------------------------------
void Mch_DB_RemAnswersOfAQuestion (long GamCod,unsigned QstInd);
//----------------------------- Answers indexes -------------------------------
void Mch_DB_CreateQstIndexes (long MchCod,unsigned QstInd,
const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]);
void Mch_DB_GetIndexes (long MchCod,unsigned QstInd,
char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]);
//----------------------------- Elapsed times ---------------------------------
void Mch_DB_UpdateElapsedTimeInQuestion (long MchCod,long QstInd);
#endif

View File

@ -5891,3 +5891,21 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (HieLvl_Level_t Scope
return 0;
}
}
/*****************************************************************************/
/*********** Get suffled/not-shuffled answers indexes of question ************/
/*****************************************************************************/
unsigned Tst_DB_GetShuffledAnswersIndexes (MYSQL_RES **mysql_res,
const struct Tst_Question *Question)
{
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get questions of a game",
"SELECT AnsInd" // row[0]
" FROM tst_answers"
" WHERE QstCod=%ld"
" ORDER BY %s",
Question->QstCod,
Question->Answer.Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order
"AnsInd");
}

View File

@ -187,4 +187,7 @@ void Tst_RemoveCrsTests (long CrsCod);
void Tst_GetTestStats (Tst_AnswerType_t AnsType,struct Tst_Stats *Stats);
unsigned Tst_DB_GetShuffledAnswersIndexes (MYSQL_RES **mysql_res,
const struct Tst_Question *Question);
#endif