diff --git a/swad_changelog.h b/swad_changelog.h index 476a97f7..54ce1aa8 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -629,10 +629,11 @@ TODO: Emilce Barrera Mesa: Podr TODO: Emilce Barrera Mesa: Mis estudiantes presentan muchas dificultades a la hora de poner la foto porque la plataforma es muy exigente respecto al fondo de la imagen. */ -#define Log_PLATFORM_VERSION "SWAD 22.112 (2023-05-18)" +#define Log_PLATFORM_VERSION "SWAD 22.113 (2023-05-19)" #define CSS_FILE "swad22.107.36.css" #define JS_FILE "swad22.49.js" /* + Version 22.113: May 19, 2023 Check if a rubric is recursive. (336936 lines) Version 22.112: May 18, 2023 Code refactoring in options of selectors. (336794 lines) Version 22.111: May 17, 2023 A project can have more than one rubric in each category. (336691 lines) Version 22.110.3: May 15, 2023 Changes in rubrics. (336550 lines) diff --git a/swad_error.c b/swad_error.c index 4213fe8c..e7c3cb35 100644 --- a/swad_error.c +++ b/swad_error.c @@ -418,6 +418,17 @@ void Err_WrongMatchExit (void) Err_ShowErrorAndExit ("Wrong match."); } +/*****************************************************************************/ +/************** Write error message when a rubric is recursive ***************/ +/*****************************************************************************/ + +void Err_RecursiveRubric (void) + { + extern const char *Txt_Recursive_rubric; + + Ale_ShowAlert (Ale_ERROR,Txt_Recursive_rubric); + } + /*****************************************************************************/ /************** Write error message and exit when wrong ribric ***************/ /*****************************************************************************/ diff --git a/swad_error.h b/swad_error.h index 4fae9b84..bb14f4b6 100644 --- a/swad_error.h +++ b/swad_error.h @@ -78,6 +78,7 @@ void Err_WrongAnswerTypeExit (void); void Err_WrongExamSessionExit (void); void Err_WrongGameExit (void); void Err_WrongMatchExit (void); +void Err_RecursiveRubric (void); void Err_WrongRubricExit (void); void Err_WrongCriterionExit (void); void Err_WrongCriterionIndexExit (void); diff --git a/swad_project.c b/swad_project.c index 1d9d02d8..79cbd90c 100644 --- a/swad_project.c +++ b/swad_project.c @@ -4577,8 +4577,19 @@ static void Prj_ShowRubricsOfType (struct Prj_Projects *Projects, /* Change color for rubric criteria */ The_ChangeRowColor (); - /* Write criteria of this rubric */ - RubCri_ListCriteriaInProject (Projects,Rubric.RubCod,ICanFill); + /* Check if rubric tree is correct */ + if (Rub_CheckRubricsTree (Rubric.RubCod, + NULL)) // The stack has not yet been created + /* Write criteria of this rubric */ + RubCri_ListCriteriaInProject (Projects,Rubric.RubCod,ICanFill); + else + { + HTM_TR_Begin (NULL); + HTM_TD_Begin ("colspan=\"8\" class=\"CT %s\"",The_GetColorRows ()); + Err_RecursiveRubric (); + HTM_TD_End (); + HTM_TR_End (); + } /* Change color for next rubric */ The_ChangeRowColor (); diff --git a/swad_rubric.c b/swad_rubric.c index 6a646420..86e15e1f 100644 --- a/swad_rubric.c +++ b/swad_rubric.c @@ -356,6 +356,11 @@ void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics) Rub_ShowRubricMainData (Rubrics, true); // Show only this rubric + /***** Check if rubric tree is correct *****/ + if (!Rub_CheckRubricsTree (Rubrics->Rubric.RubCod, + NULL)) // The stack has not yet been created + Err_RecursiveRubric (); + /***** Write criteria of this rubric *****/ RubCri_ListCriteriaForSeeing (Rubrics); @@ -794,6 +799,11 @@ void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics, /***** Put form to create/edit a rubric *****/ Rub_PutFormEditionRubric (Rubrics,ExistingNewRubric); + /***** Check if rubric tree is correct *****/ + if (!Rub_CheckRubricsTree (Rubrics->Rubric.RubCod, + NULL)) // The stack has not yet been created + Err_RecursiveRubric (); + /***** Show list of criteria inside box *****/ if (ExistingNewRubric == Rub_EXISTING_RUBRIC) RubCri_ListCriteriaForEdition (Rubrics); @@ -1013,6 +1023,103 @@ static void Rub_UpdateRubric (struct Rub_Rubric *Rubric) Ale_ShowAlert (Ale_SUCCESS,Txt_The_rubric_has_been_modified); } +/*****************************************************************************/ +/********** Recursive function to compute the score of a criterion ***********/ +/*****************************************************************************/ +// Return true if tree is ok, or false if infinite recursion +/* Tree Stack + _______ ______ + | Rub 1 | TOS (Top Of Stack)____\|___5__| + |_______| /|_Prev_| + /|\ _____/ + / | \ / ______ + / | \ \_\|___4__| + / | \ /|_Prev_| + / ___|___ \ _____/ + / | Rub 2 | \ / ______ + Handwritten |_______| Handwritten \_\|___2__| + /|\ /|_Prev_| + / | \ _____/ + / | \ / ______ + / | \ \_\|___1__| + / | \ /|_NULL_| + _______/ | \_______ + | Rub 3 | | | Rub 4 | + |_______|Handwritten|_______| + / /|\ + / / | \ + / / | \ + / / | \ + / / ___|___ \ + / / | Rub 5 | \ +Handwritten Handwritten |_______| Handwritten + /|\ + / | \ + / | \ + / | \ + / | \ + / | \ + Handwritten Handwritten Handwritten +*/ + +bool Rub_CheckRubricsTree (long RubCod,struct Node *TOS) + { + struct Node *Node; + bool TreeOk; + MYSQL_RES *mysql_res; + unsigned NumCriteria; + unsigned NumCriterion; + struct RubCri_Criterion Criterion; + + /***** Check that rubric is not yet in the stack *****/ + for (Node = TOS, TreeOk = true; + Node && TreeOk; + Node = Node->Prev) + if (Node->RubCod == RubCod) + TreeOk = false; + + if (TreeOk) + { + /***** Push rubric code in stack *****/ + /* Save current top of stack */ + Node = TOS; + + /* Create top of stack node */ + if ((TOS = malloc (sizeof (struct Node))) == NULL) + Err_NotEnoughMemoryExit (); + TOS->RubCod = RubCod; + TOS->Prev = Node; + + /* For each criteria in this rubric... */ + NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod); + for (NumCriterion = 0; + NumCriterion < NumCriteria && TreeOk; + NumCriterion++) + { + /* Get criterion data */ + RubCri_GetCriterionDataFromRow (mysql_res,&Criterion); + + switch (Criterion.Link.Type) + { + case Rsc_RUBRIC: + if (!Rub_CheckRubricsTree (Criterion.Link.Cod,TOS)) + TreeOk = false; + break; + default: + break; + } + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** Pop rubric code from stack *****/ + free (TOS); + } + + return TreeOk; + } + /*****************************************************************************/ /************************** Show stats about rubrics *************************/ /*****************************************************************************/ diff --git a/swad_rubric.h b/swad_rubric.h index de35bea5..1ea908ae 100644 --- a/swad_rubric.h +++ b/swad_rubric.h @@ -37,6 +37,12 @@ #define RubCri_AFTER_LAST_CRITERION ((unsigned)((1UL << 31) - 1)) // 2^31 - 1, don't change this number because it is used in database +struct Node + { + long RubCod; + struct Node *Prev; + }; + /*****************************************************************************/ /***************************** Public prototypes *****************************/ /*****************************************************************************/ @@ -72,6 +78,8 @@ void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics, void Rub_ReceiveFormRubric (void); +bool Rub_CheckRubricsTree (long RubCod,struct Node *TOS); + //-------------------------------- Figures ------------------------------------ void Rub_GetAndShowRubricsStats (void); diff --git a/swad_rubric_criteria.c b/swad_rubric_criteria.c index e87c2c98..d2b2864e 100644 --- a/swad_rubric_criteria.c +++ b/swad_rubric_criteria.c @@ -120,12 +120,10 @@ static void RubCri_WriteMinimumMaximum (const struct RubCri_Criterion *Criterion static void RubCri_WriteWeight (const struct RubCri_Criterion *Criterion); static void RubCri_WriteTotalLabel (unsigned ColSpan); static void RubCri_WriteTotalValue (double Total); + static double RubCri_ComputeScore (long PrjCod, const struct RubCri_Criterion *Criterion); -static void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res, - struct RubCri_Criterion *Criterion); - static void RubCri_PutTableHeadingForCriteria (RubCri_PutColumnForIcons_t PutColumnForIcons, RubCri_PutColumnsForScore_t PutColumnsForScore); @@ -995,7 +993,6 @@ static void RubCri_WriteTotalValue (double Total) static double RubCri_ComputeScore (long PrjCod, const struct RubCri_Criterion *Criterion) { - long RubCod; MYSQL_RES *mysql_res; unsigned NumCriteria; unsigned NumCriterion; @@ -1010,10 +1007,9 @@ static double RubCri_ComputeScore (long PrjCod, break; case Rsc_RUBRIC: Score = 0.0; - RubCod = Criterion->Link.Cod; /***** Get data of rubric criteria from database *****/ - NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod); + NumCriteria = Rub_DB_GetCriteria (&mysql_res,Criterion->Link.Cod); for (NumCriterion = 0; NumCriterion < NumCriteria; NumCriterion++) @@ -1056,8 +1052,8 @@ double RubCri_GetParScore (void) /************************** Get rubric criteria data *************************/ /*****************************************************************************/ -static void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res, - struct RubCri_Criterion *Criterion) +void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res, + struct RubCri_Criterion *Criterion) { MYSQL_ROW row; RubCri_ValueRange_t ValueRange; diff --git a/swad_rubric_criteria.h b/swad_rubric_criteria.h index 9fab5160..00ed929f 100644 --- a/swad_rubric_criteria.h +++ b/swad_rubric_criteria.h @@ -46,8 +46,12 @@ void RubCri_ListCriteriaForSeeing (const struct Rub_Rubrics *Rubrics); void RubCri_ListCriteriaForEdition (struct Rub_Rubrics *Rubrics); void RubCri_ListCriteriaInProject (struct Prj_Projects *Projects,long RubCod, bool ICanFill); + double RubCri_GetParScore (void); +void RubCri_GetCriterionDataFromRow (MYSQL_RES *mysql_res, + struct RubCri_Criterion *Criterion); + void RubCri_ResetCriterion (struct RubCri_Criterion *Criterion); void RubCri_ReqRemCriterion (void); diff --git a/swad_text.c b/swad_text.c index 0bdfa2cb..a37c36fe 100644 --- a/swad_text.c +++ b/swad_text.c @@ -32920,6 +32920,29 @@ const char *Txt_Recipients = "Recipients"; // Çeviri lazim! #endif +const char *Txt_Recursive_rubric = +#if L==1 // ca + "Rúbrica recursiva"; +#elif L==2 // de + "Rekursive Rubrik"; +#elif L==3 // en + "Recursive rubric"; +#elif L==4 // es + "Rúbrica recursiva"; +#elif L==5 // fr + "Rubrique récursive"; +#elif L==6 // gn + "Rúbrica recursiva"; +#elif L==7 // it + "Rubrica ricorsiva"; +#elif L==8 // pl + "Rubryka rekurencyjna"; +#elif L==9 // pt + "Rubrica recursiva"; +#elif L==10 // tr + "Özyinelemeli değerlendirme listesi"; +#endif + const char *Txt_Register = #if L==1 // ca "Inscriure";