diff --git a/swad_action.c b/swad_action.c index 0559657a2..52f079d30 100644 --- a/swad_action.c +++ b/swad_action.c @@ -507,6 +507,8 @@ Assessment: NEW. ActAddTstQstToGam Add selected test questions to game NEW. ActReqRemGamQst Request the removal of a question of a game NEW. ActRemGamQst Confirm the removal of a question of a game + NEW. ActUp_GamQst, Move up a question of a game + NEW. ActDwnGamQst, Move down a question of a game 361. ActSeeOneExaAnn Show one exam announcement 362. ActSeeDatExaAnn Show exam announcements of a given date @@ -1967,6 +1969,8 @@ struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = /* ActAddTstQstToGam */{1667,-1,TabUnk,ActSeeAllGam ,0x3E0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Gam_AddTstQuestionsToGame ,NULL}, /* ActReqRemGamQst */{1664,-1,TabUnk,ActSeeAllGam ,0x3E0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Gam_RequestRemoveQst ,NULL}, /* ActRemGamQst */{1665,-1,TabUnk,ActSeeAllGam ,0x3E0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Gam_RemoveQst ,NULL}, + /* ActUp_GamQst */{1668,-1,TabUnk,ActSeeAllGam ,0x3E0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Gam_MoveUpQst ,NULL}, + /* ActDwnGamQst */{1669,-1,TabUnk,ActSeeAllGam ,0x3E0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Gam_MoveDownQst ,NULL}, /* ActSeeOneSvy */{ 982,-1,TabUnk,ActSeeAllSvy ,0x3F8,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Svy_SeeOneSurvey ,NULL}, /* ActAnsSvy */{ 983,-1,TabUnk,ActSeeAllSvy ,0x3F8,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_THIS_WINDOW,NULL ,Svy_ReceiveSurveyAnswers ,NULL}, @@ -4711,6 +4715,8 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un ActRemGamQst, // #1665 ActGamLstTstQst, // #1666 ActAddTstQstToGam, // #1667 + ActUp_GamQst, // #1668 + ActDwnGamQst, // #1669 }; /*****************************************************************************/ diff --git a/swad_action.h b/swad_action.h index d50509578..84a319319 100644 --- a/swad_action.h +++ b/swad_action.h @@ -57,9 +57,9 @@ typedef enum typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to indicate obsolete action -#define Act_NUM_ACTIONS (1 + 9 + 43 + 17 + 47 + 33 + 24 + 115 + 90 + 416 + 165 + 172 + 42 + 14 + 97) +#define Act_NUM_ACTIONS (1 + 9 + 43 + 17 + 47 + 33 + 24 + 115 + 92 + 416 + 165 + 172 + 42 + 14 + 97) -#define Act_MAX_ACTION_COD 1667 +#define Act_MAX_ACTION_COD 1669 #define Act_MAX_OPTIONS_IN_MENU_PER_TAB 12 @@ -502,33 +502,35 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to #define ActAddTstQstToGam (ActChgCalCrs1stDay + 63) #define ActReqRemGamQst (ActChgCalCrs1stDay + 64) #define ActRemGamQst (ActChgCalCrs1stDay + 65) +#define ActUp_GamQst (ActChgCalCrs1stDay + 66) +#define ActDwnGamQst (ActChgCalCrs1stDay + 67) -#define ActSeeOneSvy (ActChgCalCrs1stDay + 66) -#define ActAnsSvy (ActChgCalCrs1stDay + 67) -#define ActFrmNewSvy (ActChgCalCrs1stDay + 68) -#define ActEdiOneSvy (ActChgCalCrs1stDay + 69) -#define ActNewSvy (ActChgCalCrs1stDay + 70) -#define ActChgSvy (ActChgCalCrs1stDay + 71) -#define ActReqRemSvy (ActChgCalCrs1stDay + 72) -#define ActRemSvy (ActChgCalCrs1stDay + 73) -#define ActReqRstSvy (ActChgCalCrs1stDay + 74) -#define ActRstSvy (ActChgCalCrs1stDay + 75) -#define ActHidSvy (ActChgCalCrs1stDay + 76) -#define ActShoSvy (ActChgCalCrs1stDay + 77) -#define ActEdiOneSvyQst (ActChgCalCrs1stDay + 78) -#define ActRcvSvyQst (ActChgCalCrs1stDay + 79) -#define ActReqRemSvyQst (ActChgCalCrs1stDay + 80) -#define ActRemSvyQst (ActChgCalCrs1stDay + 81) +#define ActSeeOneSvy (ActChgCalCrs1stDay + 68) +#define ActAnsSvy (ActChgCalCrs1stDay + 69) +#define ActFrmNewSvy (ActChgCalCrs1stDay + 70) +#define ActEdiOneSvy (ActChgCalCrs1stDay + 71) +#define ActNewSvy (ActChgCalCrs1stDay + 72) +#define ActChgSvy (ActChgCalCrs1stDay + 73) +#define ActReqRemSvy (ActChgCalCrs1stDay + 74) +#define ActRemSvy (ActChgCalCrs1stDay + 75) +#define ActReqRstSvy (ActChgCalCrs1stDay + 76) +#define ActRstSvy (ActChgCalCrs1stDay + 77) +#define ActHidSvy (ActChgCalCrs1stDay + 78) +#define ActShoSvy (ActChgCalCrs1stDay + 79) +#define ActEdiOneSvyQst (ActChgCalCrs1stDay + 80) +#define ActRcvSvyQst (ActChgCalCrs1stDay + 81) +#define ActReqRemSvyQst (ActChgCalCrs1stDay + 82) +#define ActRemSvyQst (ActChgCalCrs1stDay + 83) -#define ActSeeOneExaAnn (ActChgCalCrs1stDay + 82) -#define ActSeeDatExaAnn (ActChgCalCrs1stDay + 83) -#define ActEdiExaAnn (ActChgCalCrs1stDay + 84) -#define ActRcvExaAnn (ActChgCalCrs1stDay + 85) -#define ActPrnExaAnn (ActChgCalCrs1stDay + 86) -#define ActReqRemExaAnn (ActChgCalCrs1stDay + 87) -#define ActRemExaAnn (ActChgCalCrs1stDay + 88) -#define ActHidExaAnn (ActChgCalCrs1stDay + 89) -#define ActShoExaAnn (ActChgCalCrs1stDay + 90) +#define ActSeeOneExaAnn (ActChgCalCrs1stDay + 84) +#define ActSeeDatExaAnn (ActChgCalCrs1stDay + 85) +#define ActEdiExaAnn (ActChgCalCrs1stDay + 86) +#define ActRcvExaAnn (ActChgCalCrs1stDay + 87) +#define ActPrnExaAnn (ActChgCalCrs1stDay + 88) +#define ActReqRemExaAnn (ActChgCalCrs1stDay + 89) +#define ActRemExaAnn (ActChgCalCrs1stDay + 90) +#define ActHidExaAnn (ActChgCalCrs1stDay + 91) +#define ActShoExaAnn (ActChgCalCrs1stDay + 92) /*****************************************************************************/ /******************************** Files tab **********************************/ diff --git a/swad_changelog.h b/swad_changelog.h index 90fc3f0d9..cd191e629 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -234,17 +234,26 @@ // TODO: "Solicitar inscripción" como superusuario: "Usted no tiene permiso para realizar esta acción" +// TODO: "Administrar varios profesores no editores" -> debería poder hacerlo un profesor (Perico) + /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 16.252.3 (2017-09-11)" +#define Log_PLATFORM_VERSION "SWAD 16.253 (2017-09-11)" #define CSS_FILE "swad16.252.2.css" #define JS_FILE "swad16.206.3.js" // Number of lines (includes comments but not blank lines) has been got with the following command: // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*?.h sql/swad*.sql | tail -1 /* + Version 16.253: Sep 11, 2017 Actions to move up and down questions in a game. (227070 lines) + 4 changes necessary in database: +UPDATE actions SET Txt='Subir posición item teoría' WHERE ActCod='221' AND Language='es'; +UPDATE actions SET Txt='Bajar posición item teoría' WHERE ActCod='220' AND Language='es'; +INSERT INTO actions (ActCod,Language,Obsolete,Txt) VALUES ('1668','es','N','Subir posición pregunta juego'); +INSERT INTO actions (ActCod,Language,Obsolete,Txt) VALUES ('1669','es','N','Bajar posición pregunta juego'); + Version 16.252.3: Sep 11, 2017 HTML optimization in icons. (226822 lines) Version 16.252.2: Sep 10, 2017 Code refactoring in edition of syllabus. (226819 lines) Version 16.252.1: Sep 09, 2017 Icons to move up and down questions in a game. (226864 lines) diff --git a/swad_game.c b/swad_game.c index 00f686210..b2df4430f 100644 --- a/swad_game.c +++ b/swad_game.c @@ -122,8 +122,11 @@ static void Gam_PutParamQstCod (long QstCod); static long Gam_GetParamQstCod (void); static void Gam_RemAnswersOfAQuestion (long QstCod); -static unsigned Gam_GetQstIndFromQstCod (long QstCod); -static unsigned Gam_GetNextQuestionIndexInGame (long GamCod); +static unsigned Gam_GetQstIndFromQstCod (long GamCod,long QstCod); +static long Gam_GetQstCodFromQstInd (long GamCod,unsigned QstInd); +static int Gam_GetMaxQuestionIndexInGame (long GamCod); +static unsigned Gam_GetNextQuestionIndexInGame (long GamCod,unsigned QstInd); +static unsigned Gam_GetPrevQuestionIndexInGame (long GamCod,unsigned QstInd); static void Gam_ListGameQuestions (struct Game *Game); static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, unsigned NumQsts, @@ -141,6 +144,9 @@ static void Gam_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs); // static void Gam_PutIconToRemoveOneQst (void); static void Gam_PutParamsOneQst (void); +static void Gam_ExchangeQuestions (long GamCod, + unsigned QstIndTop,unsigned QstIndBottom); + static void Gam_ReceiveAndStoreUserAnswersToAGame (long GamCod); static void Gam_IncreaseAnswerInDB (long QstCod,unsigned AnsInd); static void Gam_RegisterIHaveAnsweredGame (long GamCod); @@ -944,7 +950,7 @@ void Gam_GetListGames (void) { /* Get next game code */ row = mysql_fetch_row (mysql_res); - if ((Gbl.Games.LstGamCods[NumGame] = Str_ConvertStrCodToLongCod (row[0])) < 0) + if ((Gbl.Games.LstGamCods[NumGame] = Str_ConvertStrCodToLongCod (row[0])) <= 0) Lay_ShowErrorAndExit ("Error: wrong game code."); } } @@ -2571,27 +2577,26 @@ static void Gam_RemAnswersOfAQuestion (long QstCod) /******************** Get next question index in a game **********************/ /*****************************************************************************/ -static unsigned Gam_GetQstIndFromQstCod (long QstCod) +static unsigned Gam_GetQstIndFromQstCod (long GamCod,long QstCod) { - char Query[128]; + char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; - unsigned long NumRows; unsigned QstInd = 0; /***** Get number of games with a field value from database *****/ - sprintf (Query,"SELECT QstInd FROM gam_questions WHERE QstCod=%ld", - QstCod); - NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get question index"); + sprintf (Query,"SELECT QstInd FROM gam_questions" + " WHERE GamCod=%ld AND QstCod=%ld", + GamCod,QstCod); + if (!DB_QuerySELECT (Query,&mysql_res,"can not get question index")) + { + Ale_ShowAlert (Ale_INFO,Query); + Lay_ShowErrorAndExit ("Error when getting question index."); + } - /***** Get number of users *****/ - if (NumRows) - { - row = mysql_fetch_row (mysql_res); - if (sscanf (row[0],"%u",&QstInd) != 1) - Lay_ShowErrorAndExit ("Error when getting question index."); - } - else + /***** Get question index (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%u",&QstInd) != 1) Lay_ShowErrorAndExit ("Error when getting question index."); /***** Free structure that stores the query result *****/ @@ -2601,15 +2606,46 @@ static unsigned Gam_GetQstIndFromQstCod (long QstCod) } /*****************************************************************************/ -/******************* Get next question index in a game *********************/ +/************ Get question code given game and index of question *************/ /*****************************************************************************/ -static unsigned Gam_GetNextQuestionIndexInGame (long GamCod) +static long Gam_GetQstCodFromQstInd (long GamCod,unsigned QstInd) + { + char Query[256]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long QstCod; + + /***** Get question code of thw question to be moved up *****/ + sprintf (Query,"SELECT QstCod FROM gam_questions" + " WHERE GamCod=%ld AND QstInd=%u", + GamCod,QstInd); + if (!DB_QuerySELECT (Query,&mysql_res,"can not get question code")) + Lay_ShowErrorAndExit ("Error: wrong question code."); + + /***** Get question code (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) + Lay_ShowErrorAndExit ("Error: wrong question code."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return QstCod; + } + +/*****************************************************************************/ +/****************** Get maximum question index in a game *********************/ +/*****************************************************************************/ +// Question index can be 0, 1, 2,... +// Return -1 if no questions + +static int Gam_GetMaxQuestionIndexInGame (long GamCod) { char Query[128]; MYSQL_RES *mysql_res; MYSQL_ROW row; - unsigned QstInd = 0; + int QstInd = -1; /***** Get maximum question index in a game from database *****/ sprintf (Query,"SELECT MAX(QstInd) FROM gam_questions WHERE GamCod=%ld", @@ -2617,11 +2653,8 @@ static unsigned Gam_GetNextQuestionIndexInGame (long GamCod) DB_QuerySELECT (Query,&mysql_res,"can not get last question index"); row = mysql_fetch_row (mysql_res); if (row[0]) // There are questions - { - if (sscanf (row[0],"%u",&QstInd) != 1) + if (sscanf (row[0],"%d",&QstInd) != 1) Lay_ShowErrorAndExit ("Error when getting last question index."); - QstInd++; - } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -2629,6 +2662,68 @@ static unsigned Gam_GetNextQuestionIndexInGame (long GamCod) return QstInd; } +/*****************************************************************************/ +/*********** Get previous question index to a given index in a game **********/ +/*****************************************************************************/ + +static unsigned Gam_GetPrevQuestionIndexInGame (long GamCod,unsigned QstInd) + { + char Query[256]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned PrevQstInd; + + /***** Get previous question index in a game from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + sprintf (Query,"SELECT MAX(QstInd) FROM gam_questions" + " WHERE GamCod=%ld AND QstInd<%u", + GamCod,QstInd); + if (!DB_QuerySELECT (Query,&mysql_res,"can not get previous question index")) + Lay_ShowErrorAndExit ("Error: previous question index not found."); + + /***** Get previous question index (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%u",&PrevQstInd) != 1) + Lay_ShowErrorAndExit ("Error when getting previous question index."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return PrevQstInd; + } + +/*****************************************************************************/ +/************* Get next question index to a given index in a game ************/ +/*****************************************************************************/ + +static unsigned Gam_GetNextQuestionIndexInGame (long GamCod,unsigned QstInd) + { + char Query[256]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NextQstInd; + + /***** Get next question index in a game from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + sprintf (Query,"SELECT MIN(QstInd) FROM gam_questions" + " WHERE GamCod=%ld AND QstInd>%u", + GamCod,QstInd); + if (!DB_QuerySELECT (Query,&mysql_res,"can not get next question index")) + Lay_ShowErrorAndExit ("Error: next question index not found."); + + /***** Get next question index (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%u",&NextQstInd) != 1) + Lay_ShowErrorAndExit ("Error when getting next question index."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NextQstInd; + } + /*****************************************************************************/ /************************ List the questions of a game ***********************/ /*****************************************************************************/ @@ -2780,11 +2875,12 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, Tst_QstConstructor (); /* row[0] holds the code of the question */ - if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) + if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) Lay_ShowErrorAndExit ("Wrong code of question."); - Gbl.Test.QstCod = QstCod; /***** Icons *****/ + Gbl.Games.CurrentGamCod = Game->GamCod; + Gbl.Games.CurrentQstCod = QstCod; fprintf (Gbl.F.Out,"" "",Gbl.RowEvenOdd); @@ -2795,11 +2891,11 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, Ico_PutIconRemove (); Act_FormEnd (); - /* Write icon to move up the question */ + /* Put icon to move up the question */ if (NumQst) { sprintf (Gbl.Title,Txt_Move_up_X,StrNumQst); - Lay_PutContextualLink (ActEdiOneTstQst,NULL,Gam_PutParamsOneQst, + Lay_PutContextualLink (ActUp_GamQst,NULL,Gam_PutParamsOneQst, "up_on16x16.gif", Gbl.Title,NULL, NULL); @@ -2807,11 +2903,11 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, else Ico_PutIcon ("up_off16x16.gif",Txt_Movement_not_allowed); - /* Write icon to move down the question */ + /* Put icon to move down the question */ if (NumQst + 1 < NumQsts) { sprintf (Gbl.Title,Txt_Move_down_X,StrNumQst); - Lay_PutContextualLink (ActEdiOneTstQst,NULL,Gam_PutParamsOneQst, + Lay_PutContextualLink (ActDwnGamQst,NULL,Gam_PutParamsOneQst, "down_on16x16.gif", Gbl.Title,NULL, NULL); @@ -2819,7 +2915,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, else Ico_PutIcon ("down_off16x16.gif",Txt_Movement_not_allowed); - /* Write icon to edit the question */ + /* Put icon to edit the question */ Gbl.Test.QstCod = QstCod; Ico_PutContextualIconToEdit (ActEdiOneTstQst,Tst_PutParamQstCod); @@ -2918,7 +3014,7 @@ void Gam_AddTstQuestionsToGame (void) const char *Ptr; char LongStr[1 + 10 + 1]; long QstCod; - unsigned QstInd; + int MaxQstInd; char Query[256]; /***** Get game code *****/ @@ -2950,15 +3046,15 @@ void Gam_AddTstQuestionsToGame (void) if (sscanf (LongStr,"%ld",&QstCod) != 1) Lay_ShowErrorAndExit ("Wrong question code."); - /* Get next index */ - QstInd = Gam_GetNextQuestionIndexInGame (Game.GamCod); + /* Get current maximum index */ + MaxQstInd = Gam_GetMaxQuestionIndexInGame (Game.GamCod); // -1 if no questions /* Insert question in the table of questions */ sprintf (Query,"INSERT INTO gam_questions" " (GamCod,QstCod,QstInd)" " VALUES" " (%ld,%ld,%u)", - Game.GamCod,QstCod,QstInd); + Game.GamCod,QstCod,(unsigned) (MaxQstInd + 1)); DB_QueryINSERT (Query,"can not create question"); } @@ -3141,11 +3237,11 @@ void Gam_RequestRemoveQst (void) Lay_ShowErrorAndExit ("Code of game is missing."); /* Get question code */ - if ((QstCod = Gam_GetParamQstCod ()) < 0) + if ((QstCod = Gam_GetParamQstCod ()) <= 0) Lay_ShowErrorAndExit ("Wrong code of question."); /* Get question index */ - QstInd = Gam_GetQstIndFromQstCod (QstCod); + QstInd = Gam_GetQstIndFromQstCod (Game.GamCod,QstCod); /***** Show question and button to remove question *****/ Gbl.Games.CurrentGamCod = Game.GamCod; @@ -3178,11 +3274,11 @@ void Gam_RemoveQst (void) Lay_ShowErrorAndExit ("Code of game is missing."); /* Get question code */ - if ((QstCod = Gam_GetParamQstCod ()) < 0) + if ((QstCod = Gam_GetParamQstCod ()) <= 0) Lay_ShowErrorAndExit ("Wrong code of question."); /* Get question index */ - QstInd = Gam_GetQstIndFromQstCod (QstCod); + QstInd = Gam_GetQstIndFromQstCod (Game.GamCod,QstCod); /***** Remove the question from all the tables *****/ /* Remove answers from this test question */ @@ -3209,6 +3305,145 @@ void Gam_RemoveQst (void) Gam_ShowOneGame (Game.GamCod,true); } +/*****************************************************************************/ +/***************** Move up position of a question in a game ******************/ +/*****************************************************************************/ + +void Gam_MoveUpQst (void) + { + extern const char *Txt_The_question_has_been_moved_up; + struct Game Game; + long QstCod; + unsigned QstIndTop; + unsigned QstIndBottom; + + /***** Get parameters from form *****/ + /* Get game code */ + if ((Game.GamCod = Gam_GetParamGameCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of game is missing."); + + /* Get question code */ + if ((QstCod = Gam_GetParamQstCod ()) <= 0) + Lay_ShowErrorAndExit ("Wrong code of question."); + + /* Get question index */ + QstIndBottom = Gam_GetQstIndFromQstCod (Game.GamCod,QstCod); + + /***** Move up question *****/ + if (QstIndBottom > 0) + { + /* Indexes of questions to be exchanged */ + QstIndTop = Gam_GetPrevQuestionIndexInGame (Game.GamCod,QstIndBottom); + + /* Exchange questions */ + Gam_ExchangeQuestions (Game.GamCod, + QstIndTop,QstIndBottom); + + /* Success alert */ + Ale_ShowAlert (Ale_SUCCESS,Txt_The_question_has_been_moved_up); + } + + /***** Show current game *****/ + Gam_ShowOneGame (Game.GamCod,true); + } + +/*****************************************************************************/ +/**************** Move down position of a question in a game *****************/ +/*****************************************************************************/ + +void Gam_MoveDownQst (void) + { + extern const char *Txt_The_question_has_been_moved_down; + struct Game Game; + long QstCod; + unsigned QstIndTop; + unsigned QstIndBottom; + int MaxQstInd; // -1 if no questions + + /***** Get parameters from form *****/ + /* Get game code */ + if ((Game.GamCod = Gam_GetParamGameCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of game is missing."); + + /* Get question code */ + if ((QstCod = Gam_GetParamQstCod ()) <= 0) + Lay_ShowErrorAndExit ("Wrong code of question."); + + /* Get question index */ + QstIndTop = Gam_GetQstIndFromQstCod (Game.GamCod,QstCod); + + /* Get maximum question index */ + MaxQstInd = Gam_GetMaxQuestionIndexInGame (Game.GamCod); + + /***** Move down question *****/ + if (MaxQstInd > 0) + if (QstIndTop < (unsigned) MaxQstInd) + { + /* Indexes of questions to be exchanged */ + QstIndBottom = Gam_GetNextQuestionIndexInGame (Game.GamCod,QstIndTop); + + /* Exchange questions */ + Gam_ExchangeQuestions (Game.GamCod,QstIndTop,QstIndBottom); + + /* Success alert */ + Ale_ShowAlert (Ale_SUCCESS,Txt_The_question_has_been_moved_down); + } + + /***** Show current game *****/ + Gam_ShowOneGame (Game.GamCod,true); + } + +/*****************************************************************************/ +/********* Exchange the order of two consecutive questions in a game *********/ +/*****************************************************************************/ + +static void Gam_ExchangeQuestions (long GamCod, + unsigned QstIndTop,unsigned QstIndBottom) + { + char Query[256]; + long QstCodTop; + long QstCodBottom; + + /***** Lock table to make the inscription atomic *****/ + DB_Query ("LOCK TABLES gam_questions WRITE", + "Can not lock tables to move game question"); + Gbl.DB.LockedTables = true; + + /***** Get question code of the questions to be moved *****/ + QstCodTop = Gam_GetQstCodFromQstInd (GamCod,QstIndTop); + QstCodBottom = Gam_GetQstCodFromQstInd (GamCod,QstIndBottom); + + /***** Exchange indexes of questions *****/ + /* + Example: + QstIndTop = 0; QstCodTop = 218 + QstIndBottom = 1; QstCodBottom = 220 + +--------+--------+ +--------+--------+ +--------+--------+ + | QstInd | QstCod | | QstInd | QstCod | | QstInd | QstCod | + +--------+--------+ +--------+--------+ +--------+--------+ + | 0 | 218 | -----> | 1 | 218 | = | 0 | 220 | + | 1 | 220 | | 0 | 220 | | 1 | 218 | + | 2 | 232 | | 2 | 232 | | 2 | 232 | + +--------+--------+ +--------+--------+ +--------+--------+ + */ + sprintf (Query,"UPDATE gam_questions SET QstInd=%u" + " WHERE GamCod=%ld AND QstCod=%ld", + QstIndBottom, + GamCod,QstCodTop); + DB_QueryUPDATE (Query,"can not exchange indexes of questions"); + sprintf (Query,"UPDATE gam_questions SET QstInd=%u" + " WHERE GamCod=%ld AND QstCod=%ld", + QstIndTop, + GamCod,QstCodBottom); + DB_QueryUPDATE (Query,"can not exchange indexes of questions"); + + /***** Unlock table *****/ + Gbl.DB.LockedTables = false; // Set to false before the following unlock... + // ...to not retry the unlock if error in unlocking + DB_Query ("UNLOCK TABLES", + "Can not unlock tables after moving game questions"); + } + /*****************************************************************************/ /************************ Receive answers of a game ************************/ /*****************************************************************************/ diff --git a/swad_game.h b/swad_game.h index b35e2f2d1..89f74797c 100644 --- a/swad_game.h +++ b/swad_game.h @@ -122,6 +122,9 @@ void Gam_AddTstQuestionsToGame (void); void Gam_RequestRemoveQst (void); void Gam_RemoveQst (void); +void Gam_MoveUpQst (void); +void Gam_MoveDownQst (void); + void Gam_ReceiveGameAnswers (void); unsigned Gam_GetNumCoursesWithCrsGames (Sco_Scope_t Scope); diff --git a/swad_group.c b/swad_group.c index 3c820aa38..e00c27792 100644 --- a/swad_group.c +++ b/swad_group.c @@ -874,7 +874,7 @@ bool Grp_ChangeMyGrpsAtomically (struct ListCodGrps *LstGrpsIWant) /***** Unlock tables after changes in my groups *****/ Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking + // ...to not retry the unlock if error in unlocking DB_Query ("UNLOCK TABLES", "Can not unlock tables after changes in user's groups"); @@ -947,7 +947,7 @@ void Grp_ChangeGrpsOtherUsrAtomically (struct ListCodGrps *LstGrpsUsrWants) if (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role == Rol_STD) { Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking + // ...to not retry the unlock if error in unlocking DB_Query ("UNLOCK TABLES", "Can not unlock tables after changes in user's groups"); } diff --git a/swad_text.c b/swad_text.c index aa55bb35f..de1f99e00 100644 --- a/swad_text.c +++ b/swad_text.c @@ -46023,6 +46023,48 @@ const char *Txt_The_properties_of_file_X_have_been_saved = // Warning: it is ver "The properties of file %s have been saved."; // Necessita de tradução #endif +const char *Txt_The_question_has_been_moved_down = +#if L==1 + "La pregunta ha estat moguda cap avall."; +#elif L==2 + "Die Frage wurde nach unten bewegt."; +#elif L==3 + "The question has been moved down."; +#elif L==4 + "La pregunta se ha movido hacia abajo."; +#elif L==5 + "La question a été déplacée vers le bas."; +#elif L==6 + "La pregunta se ha movido hacia arriba."; // Okoteve traducción +#elif L==7 + "La questione è stata abbattuta."; +#elif L==8 + "Pytanie zostało przeniesione."; +#elif L==9 + "A questão foi movida para baixo."; +#endif + +const char *Txt_The_question_has_been_moved_up = +#if L==1 + "La pregunta ha estat moguda cap amunt."; +#elif L==2 + "Die Frage wurde nach oben verschoben."; +#elif L==3 + "The question has been moved up."; +#elif L==4 + "La pregunta se ha movido hacia arriba."; +#elif L==5 + "La question a été déplacée vers le haut."; +#elif L==6 + "La pregunta se ha movido hacia arriba."; // Okoteve traducción +#elif L==7 + "La questione è stata spostata."; +#elif L==8 + "Pytanie zostało poruszone."; +#elif L==9 + "A questão foi movida para cima."; +#endif + const char *Txt_The_record_field_X_already_exists = // Warning: it is very important to include %s in the following sentences #if L==1 "El campo de ficha %s ya existe."; // Necessita traduccio