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,49 +1779,11 @@ 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,
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);
Mch_DB_AssociateGroupToMatch (MchCod,
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]);
}
/*****************************************************************************/
@ -2009,49 +1792,10 @@ void Mch_DB_RemoveGroupsOfType (long GrpTypCod)
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);
}
/*****************************************************************************/
@ -2375,11 +2109,11 @@ static void Mch_SetMatchStatusToPrevQst (struct Mch_Match *Match)
{
/***** Get index of the previous question *****/
Match->Status.QstInd = Gam_DB_GetPrevQuestionIndexInGame (Match->GamCod,
Match->Status.QstInd);
Match->Status.QstInd);
if (Match->Status.QstInd) // Start of questions not reached
{
Match->Status.QstCod = Gam_DB_GetQstCodFromQstInd (Match->GamCod,
Match->Status.QstInd);
Match->Status.QstInd);
Match->Status.Showing = Match->Status.ShowQstResults ? Mch_RESULTS :
Mch_ANSWERS;
}
@ -2438,13 +2172,13 @@ static void Mch_SetMatchStatusToNextQst (struct Mch_Match *Match)
{
/***** Get index of the next question *****/
Match->Status.QstInd = Gam_DB_GetNextQuestionIndexInGame (Match->GamCod,
Match->Status.QstInd);
Match->Status.QstInd);
/***** Get question code *****/
if (Match->Status.QstInd < Gam_AFTER_LAST_QUESTION) // End of questions not reached
{
Match->Status.QstCod = Gam_DB_GetQstCodFromQstInd (Match->GamCod,
Match->Status.QstInd);
Match->Status.QstInd);
Match->Status.Showing = Mch_STEM;
}
else // End of questions reached
@ -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 **************/
/*****************************************************************************/
@ -2705,7 +2399,7 @@ static void Mch_WriteNumRespondersQst (struct Mch_Match *Match)
break;
default:
HTM_Unsigned (Mch_DB_GetNumUsrsWhoAnsweredQst (Match->MchCod,
Match->Status.QstInd));
Match->Status.QstInd));
break;
}
@ -2905,7 +2599,7 @@ static void Mch_ShowLeftColumnStd (const struct Mch_Match *Match,
/***** Write whether question is answered or not *****/
Mch_PutIfAnswered (Match,Answered);
if (Match->Status.Playing && // Match is being played
if (Match->Status.Playing && // Match is being played
Match->Status.Showing == Mch_ANSWERS && // Teacher's screen is showing question answers
Answered) // I have answered this question
/***** Put icon to remove my answet *****/
@ -2934,7 +2628,7 @@ static void Mch_ShowRightColumnStd (struct Mch_Match *Match,
Mch_ShowMatchTitleStd (Match);
/***** Bottom row *****/
if (Match->Status.Playing) // Match is being played
if (Match->Status.Playing) // Match is being played
{
if (Match->Status.Showing == Mch_END) // Match over
Mch_ShowWaitImage (Txt_Please_wait_);
@ -2956,7 +2650,7 @@ static void Mch_ShowRightColumnStd (struct Mch_Match *Match,
HTM_DIV_End ();
}
}
else // Match is not being played
else // Match is not being played
Mch_ShowWaitImage (Txt_Please_wait_);
/***** End right container *****/
@ -2979,7 +2673,7 @@ static void Mch_ShowNumQstInMch (const struct Mch_Match *Match)
case Mch_START: // Not started
HTM_Txt (Txt_MATCH_Start);
break;
case Mch_END: // Match over
case Mch_END: // Match over
HTM_Txt (Txt_MATCH_End);
break;
default:
@ -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

@ -729,49 +729,49 @@ void Tst_ListQuestionForEdition (struct Tst_Question *Question,
/***** Number of question and answer type (row[1]) *****/
HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
Tst_WriteNumQst (QstInd,"BIG_INDEX");
if (QuestionExists)
Tst_WriteAnswerType (Question->Answer.Type,"DAT_SMALL");
Tst_WriteNumQst (QstInd,"BIG_INDEX");
if (QuestionExists)
Tst_WriteAnswerType (Question->Answer.Type,"DAT_SMALL");
HTM_TD_End ();
/***** Write question code *****/
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
HTM_TxtF ("%ld&nbsp;",Question->QstCod);
HTM_TxtF ("%ld&nbsp;",Question->QstCod);
HTM_TD_End ();
/***** Write the question tags *****/
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
if (QuestionExists)
Tst_GetAndWriteTagsQst (Question->QstCod);
if (QuestionExists)
Tst_GetAndWriteTagsQst (Question->QstCod);
HTM_TD_End ();
/***** Write stem (row[3]) and media *****/
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
HTM_ARTICLE_Begin (Anchor);
if (QuestionExists)
{
/* Write stem */
Tst_WriteQstStem (Question->Stem,"TEST_TXT",
true); // Visible
HTM_ARTICLE_Begin (Anchor);
if (QuestionExists)
{
/* Write stem */
Tst_WriteQstStem (Question->Stem,"TEST_TXT",
true); // Visible
/* Show media */
Med_ShowMedia (&Question->Media,
"TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST");
/* Show media */
Med_ShowMedia (&Question->Media,
"TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST");
/* Show feedback */
Tst_WriteQstFeedback (Question->Feedback,"TEST_TXT_LIGHT");
/* Show feedback */
Tst_WriteQstFeedback (Question->Feedback,"TEST_TXT_LIGHT");
/* Show answers */
Tst_WriteAnswersBank (Question,"TEST_TXT","TEST_TXT_LIGHT");
}
else
{
HTM_SPAN_Begin ("class=\"DAT_LIGHT\"");
HTM_Txt (Txt_Question_removed);
HTM_SPAN_End ();
}
HTM_ARTICLE_End ();
/* Show answers */
Tst_WriteAnswersBank (Question,"TEST_TXT","TEST_TXT_LIGHT");
}
else
{
HTM_SPAN_Begin ("class=\"DAT_LIGHT\"");
HTM_Txt (Txt_Question_removed);
HTM_SPAN_End ();
}
HTM_ARTICLE_End ();
HTM_TD_End ();
}
@ -2770,7 +2770,7 @@ static void Tst_WriteIntAnsBank (struct Tst_Question *Question,
__attribute__((unused)) const char *ClassFeedback)
{
HTM_SPAN_Begin ("class=\"%s\"",ClassTxt);
HTM_TxtF ("(%ld)",Question->Answer.Integer);
HTM_TxtF ("(%ld)",Question->Answer.Integer);
HTM_SPAN_End ();
}
@ -2783,11 +2783,11 @@ static void Tst_WriteFltAnsBank (struct Tst_Question *Question,
__attribute__((unused)) const char *ClassFeedback)
{
HTM_SPAN_Begin ("class=\"%s\"",ClassTxt);
HTM_Txt ("([");
HTM_Double (Question->Answer.FloatingPoint[0]);
HTM_Txt ("; ");
HTM_Double (Question->Answer.FloatingPoint[1]);
HTM_Txt ("])");
HTM_Txt ("([");
HTM_Double (Question->Answer.FloatingPoint[0]);
HTM_Txt ("; ");
HTM_Double (Question->Answer.FloatingPoint[1]);
HTM_Txt ("])");
HTM_SPAN_End ();
}
@ -2801,9 +2801,9 @@ static void Tst_WriteTF_AnsBank (struct Tst_Question *Question,
{
/***** Write answer *****/
HTM_SPAN_Begin ("class=\"%s\"",ClassTxt);
HTM_Txt ("(");
Tst_WriteAnsTF (Question->Answer.TF);
HTM_Txt (")");
HTM_Txt ("(");
Tst_WriteAnsTF (Question->Answer.TF);
HTM_Txt (")");
HTM_SPAN_End ();
}
@ -2825,42 +2825,42 @@ static void Tst_WriteChoAnsBank (struct Tst_Question *Question,
Tst_ChangeFormatAnswersFeedback (Question);
HTM_TABLE_BeginPadding (2);
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
NumOpt++)
{
HTM_TR_Begin (NULL);
for (NumOpt = 0;
NumOpt < Question->Answer.NumOptions;
NumOpt++)
{
HTM_TR_Begin (NULL);
/* Put an icon that indicates whether the answer is correct or wrong */
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
if (Question->Answer.Options[NumOpt].Correct)
Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,"CONTEXT_ICO_16x16");
HTM_TD_End ();
/* Put an icon that indicates whether the answer is correct or wrong */
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
if (Question->Answer.Options[NumOpt].Correct)
Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,"CONTEXT_ICO_16x16");
HTM_TD_End ();
/* Write the number of option */
HTM_TD_Begin ("class=\"%s LT\"",ClassTxt);
HTM_TxtF ("%c)&nbsp;",'a' + (char) NumOpt);
HTM_TD_End ();
/* Write the number of option */
HTM_TD_Begin ("class=\"%s LT\"",ClassTxt);
HTM_TxtF ("%c)&nbsp;",'a' + (char) NumOpt);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LT\"");
HTM_TD_Begin ("class=\"LT\"");
/* Write the text of the answer and the media */
HTM_DIV_Begin ("class=\"%s\"",ClassTxt);
HTM_Txt (Question->Answer.Options[NumOpt].Text);
Med_ShowMedia (&Question->Answer.Options[NumOpt].Media,
"TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST");
HTM_DIV_End ();
/* Write the text of the answer and the media */
HTM_DIV_Begin ("class=\"%s\"",ClassTxt);
HTM_Txt (Question->Answer.Options[NumOpt].Text);
Med_ShowMedia (&Question->Answer.Options[NumOpt].Media,
"TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST");
HTM_DIV_End ();
/* Write the text of the feedback */
HTM_DIV_Begin ("class=\"%s\"",ClassFeedback);
HTM_Txt (Question->Answer.Options[NumOpt].Feedback);
HTM_DIV_End ();
/* Write the text of the feedback */
HTM_DIV_Begin ("class=\"%s\"",ClassFeedback);
HTM_Txt (Question->Answer.Options[NumOpt].Feedback);
HTM_DIV_End ();
HTM_TD_End ();
HTM_TD_End ();
HTM_TR_End ();
}
HTM_TR_End ();
}
HTM_TABLE_End ();
}
@ -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