diff --git a/Makefile b/Makefile
index 08ae6b73..9caa948e 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/swad_changelog.h b/swad_changelog.h
index 5c5ea9a1..d2a37243 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
*/
-#define Log_PLATFORM_VERSION "SWAD 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)
diff --git a/swad_exam_database.c b/swad_exam_database.c
index 84b0a79b..4846d4bb 100644
--- a/swad_exam_database.c
+++ b/swad_exam_database.c
@@ -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"
diff --git a/swad_exam_database.h b/swad_exam_database.h
index 2876d28f..793f6ce7 100644
--- a/swad_exam_database.h
+++ b/swad_exam_database.h
@@ -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);
diff --git a/swad_game.c b/swad_game.c
index 886e24d1..a676c62b 100644
--- a/swad_game.c
+++ b/swad_game.c
@@ -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;
diff --git a/swad_game_database.c b/swad_game_database.c
index 8f5fb010..9c239068 100644
--- a/swad_game_database.c
+++ b/swad_game_database.c
@@ -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 *************/
/*****************************************************************************/
diff --git a/swad_game_database.h b/swad_game_database.h
index d107eee7..e338926d 100644
--- a/swad_game_database.h
+++ b/swad_game_database.h
@@ -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);
diff --git a/swad_group.c b/swad_group.c
index 608cf2e8..2f6ae397 100644
--- a/swad_group.c
+++ b/swad_group.c
@@ -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);
diff --git a/swad_match.c b/swad_match.c
index f4589fec..6e10001f 100644
--- a/swad_match.c
+++ b/swad_match.c
@@ -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);
- }
diff --git a/swad_match.h b/swad_match.h
index 9f2a8d88..20375416 100644
--- a/swad_match.h
+++ b/swad_match.h
@@ -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
diff --git a/swad_match_database.c b/swad_match_database.c
new file mode 100644
index 00000000..772384b1
--- /dev/null
+++ b/swad_match_database.c
@@ -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 .
+*/
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+#define _GNU_SOURCE // For asprintf
+// #include // For PATH_MAX
+// #include // For NULL
+#include // For asprintf
+// #include // For free
+#include // 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);
+ }
+
diff --git a/swad_match_database.h b/swad_match_database.h
new file mode 100644
index 00000000..4a64f274
--- /dev/null
+++ b/swad_match_database.h
@@ -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 .
+*/
+/*****************************************************************************/
+/********************************* 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
diff --git a/swad_test.c b/swad_test.c
index de3b14ef..5dff5649 100644
--- a/swad_test.c
+++ b/swad_test.c
@@ -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 ",Question->QstCod);
+ HTM_TxtF ("%ld ",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) ",'a' + (char) NumOpt);
- HTM_TD_End ();
+ /* Write the number of option */
+ HTM_TD_Begin ("class=\"%s LT\"",ClassTxt);
+ HTM_TxtF ("%c) ",'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");
+ }
diff --git a/swad_test.h b/swad_test.h
index 84b7990d..45b2627e 100644
--- a/swad_test.h
+++ b/swad_test.h
@@ -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