From 769096e0fb1e2fe8fb58b39ff8b7e0b9c0e0fb6f Mon Sep 17 00:00:00 2001 From: acanas Date: Wed, 1 Mar 2023 18:17:08 +0100 Subject: [PATCH] Version 22.65: Mar 01, 2023 New module swad_rubric for rubrics. Not finished. --- swad_rubric.c | 1445 ++++++++++++++++++++++++++++++++++++++++ swad_rubric.h | 119 ++++ swad_rubric_database.c | 672 +++++++++++++++++++ swad_rubric_database.h | 75 +++ 4 files changed, 2311 insertions(+) create mode 100644 swad_rubric.c create mode 100644 swad_rubric.h create mode 100644 swad_rubric_database.c create mode 100644 swad_rubric_database.h diff --git a/swad_rubric.c b/swad_rubric.c new file mode 100644 index 00000000..10210b17 --- /dev/null +++ b/swad_rubric.c @@ -0,0 +1,1445 @@ +// swad_rubric.c: assessment rubrics + +/* + 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-2022 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_action_list.h" +#include "swad_autolink.h" +#include "swad_box.h" +#include "swad_database.h" +#include "swad_error.h" +#include "swad_figure.h" +#include "swad_form.h" +#include "swad_global.h" +#include "swad_hierarchy_level.h" +#include "swad_HTML.h" +#include "swad_pagination.h" +#include "swad_parameter.h" +#include "swad_role.h" +#include "swad_rubric.h" +#include "swad_rubric_database.h" + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/***************************** Private constants *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ****************************/ +/*****************************************************************************/ + +static bool Rub_CheckIfICanEditRubrics (void); +static void Rub_PutIconsListRubrics (void *Rubrics); +static void Rub_PutIconToCreateNewRubric (struct Rub_Rubrics *Rubrics); +static void Rub_PutButtonToCreateNewRubric (struct Rub_Rubrics *Rubrics); +static void Rub_PutParamsToCreateNewRubric (void *Rubrics); + +static void Rub_ShowRubricMainData (struct Rub_Rubrics *Rubrics, + bool ShowOnlyThisRubric); + +static void Rub_PutIconsOneRubric (void *Rubrics); +static void Rub_WriteAuthor (struct Rub_Rubric *Rubric); + +static void Rub_PutIconsToRemEditOneRubric (struct Rub_Rubrics *Rubrics); + +static void Rub_RemoveRubricFromAllTables (long RubCod); + +static void Rub_PutFormsEditionRubric (struct Rub_Rubrics *Rubrics, + char Txt[Cns_MAX_BYTES_TEXT + 1], + bool ItsANewRubric); +static void Rub_ReceiveRubricFieldsFromForm (struct Rub_Rubric *Rubric, + char Txt[Cns_MAX_BYTES_TEXT + 1]); +static bool Rub_CheckRubricFieldsReceivedFromForm (const struct Rub_Rubric *Rubric); + +static void Rub_CreateRubric (struct Rub_Rubric *Rubric,const char *Txt); +static void Rub_UpdateRubric (struct Rub_Rubric *Rubric,const char *Txt); + +static void Rub_ListRubricCriteria (struct Rub_Rubrics *Rubrics); +static void Rub_ListOneOrMoreCriteriaForEdition (struct Rub_Rubrics *Rubrics, + unsigned NumCriteria, + MYSQL_RES *mysql_res, + bool ICanEditCriteria); +static void Rub_PutIconToAddNewCriterion (void *Rubrics); +static void Rub_PutButtonToAddNewCriterion (struct Rub_Rubrics *Rubrics); + +/*****************************************************************************/ +/*************************** Reset rubrics context ***************************/ +/*****************************************************************************/ + +void Rub_ResetRubrics (struct Rub_Rubrics *Rubrics) + { + Rubrics->LstIsRead = false; // List not read from database... + Rubrics->Num = 0; // Total number of rubrics + Rubrics->Lst = NULL; // List of rubrics + Rubrics->CurrentPage = 0; + Rubrics->Rubric.RubCod = -1L; // Current/selected rubric code + } + +/*****************************************************************************/ +/*************************** Initialize rubric to empty **********************/ +/*****************************************************************************/ + +void Rub_ResetRubric (struct Rub_Rubric *Rubric) + { + /***** Initialize to empty rubric *****/ + Rubric->RubCod = -1L; + Rubric->CrsCod = -1L; + Rubric->UsrCod = -1L; + Rubric->Title[0] = '\0'; + Rubric->NumCriteria = 0; + } + +/*****************************************************************************/ +/***************************** Show all rubrics ******************************/ +/*****************************************************************************/ + +void Rub_SeeAllRubrics (void) + { + struct Rub_Rubrics Rubrics; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Get parameters *****/ + Rub_GetParams (&Rubrics); // Return value ignored + + /***** Show all rubrics *****/ + Rub_ListAllRubrics (&Rubrics); + } + +/*****************************************************************************/ +/******************************* List all rubrics ****************************/ +/*****************************************************************************/ + +void Rub_ListAllRubrics (struct Rub_Rubrics *Rubrics) + { + extern const char *Hlp_ASSESSMENT_Rubrics; + extern const char *Txt_Rubrics; + extern const char *Txt_Rubric; + extern const char *Txt_Criteria; + extern const char *Txt_No_rubrics; + struct Pagination Pagination; + unsigned NumRubric; + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics->Rubric); + + /***** Get number of groups in current course *****/ + if (!Gbl.Crs.Grps.NumGrps) + Gbl.Crs.Grps.WhichGrps = Grp_ALL_GROUPS; + + /***** Get list of rubrics *****/ + Rub_GetListRubrics (Rubrics); + + /***** Compute variables related to pagination *****/ + Pagination.NumItems = Rubrics->Num; + Pagination.CurrentPage = (int) Rubrics->CurrentPage; + Pag_CalculatePagination (&Pagination); + Rubrics->CurrentPage = (unsigned) Pagination.CurrentPage; + + /***** Begin box *****/ + Box_BoxBegin ("100%",Txt_Rubrics, + Rub_PutIconsListRubrics,Rubrics, + Hlp_ASSESSMENT_Rubrics,Box_NOT_CLOSABLE); + + /***** Write links to pages *****/ + Pag_WriteLinksToPagesCentered (Pag_RUBRICS,&Pagination, + Rubrics,-1L); + + if (Rubrics->Num) + { + /***** Begin table *****/ + HTM_TABLE_BeginWideMarginPadding (5); + + /***** Table head *****/ + HTM_TR_Begin (NULL); + + HTM_TH_Span (NULL,HTM_HEAD_CENTER,1,1,"CONTEXT_COL"); // Column for contextual icons + + HTM_TH_Begin (HTM_HEAD_LEFT); + HTM_Txt (Txt_Rubric); + HTM_TH_End (); + + HTM_TH (Txt_Criteria,HTM_HEAD_RIGHT); + + HTM_TR_End (); + + /***** Write all rubrics *****/ + for (NumRubric = Pagination.FirstItemVisible; + NumRubric <= Pagination.LastItemVisible; + NumRubric++) + { + /* Get data of this rubric */ + Rubrics->Rubric.RubCod = Rubrics->Lst[NumRubric - 1]; + Rub_GetDataOfRubricByCod (&Rubrics->Rubric); + + /* Show a pair of rows with the main data of this rubric */ + Rub_ShowRubricMainData (Rubrics, + false); // Do not show only this rubric + } + + /***** End table *****/ + HTM_TABLE_End (); + } + else // No rubrics created + Ale_ShowAlert (Ale_INFO,Txt_No_rubrics); + + /***** Write again links to pages *****/ + Pag_WriteLinksToPagesCentered (Pag_RUBRICS,&Pagination, + Rubrics,-1L); + + /***** Button to create a new rubric *****/ + if (Rub_CheckIfICanEditRubrics ()) + Rub_PutButtonToCreateNewRubric (Rubrics); + + /***** End box *****/ + Box_BoxEnd (); + + /***** Free list of rubrics *****/ + Rub_FreeListRubrics (Rubrics); + } + +/*****************************************************************************/ +/************************ Check if I can edit rubrics ************************/ +/*****************************************************************************/ + +static bool Rub_CheckIfICanEditRubrics (void) + { + static const bool ICanEditRubrics[Rol_NUM_ROLES] = + { + [Rol_TCH ] = true, + [Rol_SYS_ADM] = true, + }; + + return ICanEditRubrics[Gbl.Usrs.Me.Role.Logged]; + } + +/*****************************************************************************/ +/****************** Put contextual icons in list of rubrics ******************/ +/*****************************************************************************/ + +static void Rub_PutIconsListRubrics (void *Rubrics) + { + if (Rubrics) + { + /***** Put icon to create a new rubric *****/ + if (Rub_CheckIfICanEditRubrics ()) + Rub_PutIconToCreateNewRubric ((struct Rub_Rubrics *) Rubrics); + + /***** Put icon to show a figure *****/ + Fig_PutIconToShowFigure (Fig_RUBRICS); + } + } + +/*****************************************************************************/ +/*********************** Put icon to create a new rubric ***********************/ +/*****************************************************************************/ + +static void Rub_PutIconToCreateNewRubric (struct Rub_Rubrics *Rubrics) + { + Ico_PutContextualIconToAdd (ActFrmNewRub,NULL, + Rub_PutParamsToCreateNewRubric,Rubrics); + } + +/*****************************************************************************/ +/********************* Put button to create a new rubric ***********************/ +/*****************************************************************************/ + +static void Rub_PutButtonToCreateNewRubric (struct Rub_Rubrics *Rubrics) + { + extern const char *Txt_New_rubric; + + Frm_BeginForm (ActFrmNewRub); + Rub_PutParamsToCreateNewRubric (Rubrics); + + Btn_PutConfirmButton (Txt_New_rubric); + + Frm_EndForm (); + } + +/*****************************************************************************/ +/******************** Put parameters to create a new rubric ********************/ +/*****************************************************************************/ + +static void Rub_PutParamsToCreateNewRubric (void *Rubrics) + { + if (Rubrics) + Pag_PutHiddenParamPagNum (Pag_RUBRICS,((struct Rub_Rubrics *) Rubrics)->CurrentPage); + } + +/*****************************************************************************/ +/******************************* Show one rubric *******************************/ +/*****************************************************************************/ + +void Rub_SeeOneRubric (void) + { + struct Rub_Rubrics Rubrics; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Get parameters *****/ + if ((Rubrics.Rubric.RubCod = Rub_GetParams (&Rubrics)) <= 0) + Err_WrongRubricExit (); + Rub_GetDataOfRubricByCod (&Rubrics.Rubric); + + /***** Show rubric *****/ + Rub_ShowOnlyOneRubric (&Rubrics, + false); // Do not list rubric criteria + } + +/*****************************************************************************/ +/******************************* Show one rubric *****************************/ +/*****************************************************************************/ + +void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics, + bool ListRubricCriteria) + { + Rub_ShowOnlyOneRubricBegin (Rubrics,ListRubricCriteria); + Rub_ShowOnlyOneRubricEnd (); + } + +void Rub_ShowOnlyOneRubricBegin (struct Rub_Rubrics *Rubrics, + bool ListRubricCriteria) + { + extern const char *Hlp_ASSESSMENT_Rubrics; + extern const char *Txt_Rubric; + + /***** Begin box *****/ + Box_BoxBegin (NULL,Txt_Rubric, + Rub_PutIconsOneRubric,Rubrics, + Hlp_ASSESSMENT_Rubrics,Box_NOT_CLOSABLE); + + /***** Show main data of this rubric *****/ + Rub_ShowRubricMainData (Rubrics, + true); // Show only this rubric + + /***** Write criteria of this rubric *****/ + if (ListRubricCriteria) + Ale_ShowAlert (Ale_INFO,"The criteria of the rubric should be listed here."); + // Rub_ListRubricCriteria (Rubrics); + } + +void Rub_ShowOnlyOneRubricEnd (void) + { + /***** End box *****/ + Box_BoxEnd (); + } + +/*****************************************************************************/ +/********** Show a pair of rows with the main data of a given rubric ***********/ +/*****************************************************************************/ + +static void Rub_ShowRubricMainData (struct Rub_Rubrics *Rubrics, + bool ShowOnlyThisRubric) + { + extern const char *Txt_View_rubric; + extern const char *Txt_Number_of_criteria; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Begin box and table *****/ + if (ShowOnlyThisRubric) + HTM_TABLE_BeginWidePadding (2); + + /***** Begin first row of this rubric *****/ + HTM_TR_Begin (NULL); + + /***** Icons related to this rubric *****/ + if (!ShowOnlyThisRubric) + { + HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL %s\"", + The_GetColorRows ()); + Rub_PutIconsToRemEditOneRubric (Rubrics); + HTM_TD_End (); + } + + /***** Rubric title and main data *****/ + if (ShowOnlyThisRubric) + HTM_TD_Begin ("class=\"LT\""); + else + HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ()); + + /* Rubric title */ + Frm_BeginForm (ActSeeRub); + Rub_PutParams (Rubrics); + HTM_BUTTON_Submit_Begin (Txt_View_rubric,"class=\"LT BT_LINK ASG_TITLE_%s\"", + The_GetSuffix ()); + HTM_Txt (Rubrics->Rubric.Title); + HTM_BUTTON_End (); + Frm_EndForm (); + + /* Number of criteria */ + HTM_DIV_Begin ("class=\"ASG_GRP_%s\"",The_GetSuffix ()); + HTM_TxtColonNBSP (Txt_Number_of_criteria); + HTM_Unsigned (Rubrics->Rubric.NumCriteria); + HTM_DIV_End (); + + /***** End 1st row of this rubric *****/ + HTM_TR_End (); + + /***** Begin 2nd row of this rubric *****/ + HTM_TR_Begin (NULL); + + /***** Author of the rubric *****/ + if (ShowOnlyThisRubric) + HTM_TD_Begin ("colspan=\"2\" class=\"LT\""); + else + HTM_TD_Begin ("colspan=\"2\" class=\"LT %s\"", + The_GetColorRows ()); + Rub_WriteAuthor (&Rubrics->Rubric); + HTM_TD_End (); + + /***** Text of the rubric *****/ + if (ShowOnlyThisRubric) + HTM_TD_Begin ("colspan=\"2\" class=\"LT\""); + else + HTM_TD_Begin ("colspan=\"2\" class=\"LT %s\"", + The_GetColorRows ()); + Rub_DB_GetRubricTxt (Rubrics->Rubric.RubCod,Txt); + Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, + Txt,Cns_MAX_BYTES_TEXT,false); // Convert from HTML to rigorous HTML + ALn_InsertLinks (Txt,Cns_MAX_BYTES_TEXT,60); // Insert links + HTM_DIV_Begin ("class=\"PAR DAT_%s\"",The_GetSuffix ()); + HTM_Txt (Txt); + HTM_DIV_End (); + HTM_TD_End (); + + /***** End 2nd row of this rubric *****/ + HTM_TR_End (); + + /***** End table *****/ + if (ShowOnlyThisRubric) + HTM_TABLE_End (); + else + The_ChangeRowColor (); + } + +/*****************************************************************************/ +/******************** Put icons to remove/edit one rubric **********************/ +/*****************************************************************************/ + +static void Rub_PutIconsOneRubric (void *Rubrics) + { + if (Rubrics) + Rub_PutIconsToRemEditOneRubric (Rubrics); + } + +/*****************************************************************************/ +/*********************** Write the author of a rubric ************************/ +/*****************************************************************************/ + +static void Rub_WriteAuthor (struct Rub_Rubric *Rubric) + { + Usr_WriteAuthor1Line (Rubric->UsrCod, + false); // Not hidden + } + +/*****************************************************************************/ +/******************** Put icons to remove/edit one rubric **********************/ +/*****************************************************************************/ + +static void Rub_PutIconsToRemEditOneRubric (struct Rub_Rubrics *Rubrics) + { + if (Rub_CheckIfICanEditRubrics ()) + { + /***** Icon to remove rubric *****/ + Ico_PutContextualIconToRemove (ActReqRemRub,NULL, + Rub_PutParams,Rubrics); + /***** Icon to edit rubric *****/ + Ico_PutContextualIconToEdit (ActEdiOneRub,NULL, + Rub_PutParams,Rubrics); + } + } + +/*****************************************************************************/ +/**************** Put parameter to move/remove one criterion ******************/ +/*****************************************************************************/ + +static void Rub_PutParamsOneQst (void *Rubrics) + { + if (Rubrics) + Rub_PutParams (Rubrics); + } + +/*****************************************************************************/ +/*********************** Params used to edit a rubric **************************/ +/*****************************************************************************/ + +void Rub_PutParams (void *Rubrics) + { + if (Rubrics) + { + if (((struct Rub_Rubrics *) Rubrics)->Rubric.RubCod > 0) + Rub_PutParamRubCod (((struct Rub_Rubrics *) Rubrics)->Rubric.RubCod); + Pag_PutHiddenParamPagNum (Pag_RUBRICS,((struct Rub_Rubrics *) Rubrics)->CurrentPage); + } + } + +/*****************************************************************************/ +/******************** Write parameter with code of rubric **********************/ +/*****************************************************************************/ + +void Rub_PutParamRubCod (long RubCod) + { + if (RubCod > 0) + Par_PutHiddenParamLong (NULL,"RubCod",RubCod); + } + +/*****************************************************************************/ +/********************* Get parameter with code of rubric ***********************/ +/*****************************************************************************/ + +long Rub_GetParamRubCod (void) + { + /***** Get code of rubric *****/ + return Par_GetParToLong ("RubCod"); + } + +/*****************************************************************************/ +/****************** Get parameters used to edit a rubric *********************/ +/*****************************************************************************/ + +long Rub_GetParams (struct Rub_Rubrics *Rubrics) + { + /***** Get other parameters *****/ + Rubrics->CurrentPage = Pag_GetParamPagNum (Pag_RUBRICS); + + /***** Get rubric code *****/ + return Rub_GetParamRubCod (); + } + +/*****************************************************************************/ +/************************** Get list of all rubrics ****************************/ +/*****************************************************************************/ + +void Rub_GetListRubrics (struct Rub_Rubrics *Rubrics) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumRubric; + + /***** Free list of rubrics *****/ + if (Rubrics->LstIsRead) + Rub_FreeListRubrics (Rubrics); + + /***** Get list of rubrics from database *****/ + if ((Rubrics->Num = Rub_DB_GetListRubrics (&mysql_res))) // Rubrics found... + { + /***** Create list of rubrics *****/ + if ((Rubrics->Lst = malloc ((size_t) Rubrics->Num * + sizeof (*Rubrics->Lst))) == NULL) + Err_NotEnoughMemoryExit (); + + /***** Get the rubrics codes *****/ + for (NumRubric = 0; + NumRubric < Rubrics->Num; + NumRubric++) + { + /* Get next rubric code (row[0]) */ + row = mysql_fetch_row (mysql_res); + if ((Rubrics->Lst[NumRubric] = Str_ConvertStrCodToLongCod (row[0])) <= 0) + Err_WrongRubricExit (); + } + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + Rubrics->LstIsRead = true; + } + +/*****************************************************************************/ +/********************** Get rubric data using its code *************************/ +/*****************************************************************************/ + +void Rub_GetDataOfRubricByCod (struct Rub_Rubric *Rubric) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + + /***** Get data of rubric from database *****/ + if (Rub_DB_GetDataOfRubricByCod (&mysql_res,Rubric->RubCod)) // Rubric found... + { + /* Get row */ + row = mysql_fetch_row (mysql_res); + + /* Get code of the rubric (row[0]) */ + Rubric->RubCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get code of the course (row[1]) */ + Rubric->CrsCod = Str_ConvertStrCodToLongCod (row[1]); + + /* Get author of the rubric (row[2]) */ + Rubric->UsrCod = Str_ConvertStrCodToLongCod (row[2]); + + /* Get the title of the rubric (row[3]) */ + Str_Copy (Rubric->Title,row[3],sizeof (Rubric->Title) - 1); + + /* Get number of criteria */ + Rubric->NumCriteria = Rub_DB_GetNumCriteriaInRubric (Rubric->RubCod); + } + else + /* Initialize to empty rubric */ + Rub_ResetRubric (Rubric); + + /* Free structure that stores the query result */ + DB_FreeMySQLResult (&mysql_res); + } + +/*****************************************************************************/ +/***************************** Free list of rubrics ****************************/ +/*****************************************************************************/ + +void Rub_FreeListRubrics (struct Rub_Rubrics *Rubrics) + { + if (Rubrics->LstIsRead && Rubrics->Lst) + { + /***** Free memory used by the list of rubrics *****/ + free (Rubrics->Lst); + Rubrics->Lst = NULL; + Rubrics->Num = 0; + Rubrics->LstIsRead = false; + } + } + +/*****************************************************************************/ +/*************** Ask for confirmation of removing of a rubric ******************/ +/*****************************************************************************/ + +void Rub_AskRemRubric (void) + { + extern const char *Txt_Do_you_really_want_to_remove_the_game_X; + extern const char *Txt_Remove_game; + struct Rub_Rubrics Rubrics; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Get parameters *****/ + if ((Rubrics.Rubric.RubCod = Rub_GetParams (&Rubrics)) <= 0) + Err_WrongRubricExit (); + + /***** Get data of the rubric from database *****/ + Rub_GetDataOfRubricByCod (&Rubrics.Rubric); + if (!Rub_CheckIfICanEditRubrics ()) + Err_NoPermissionExit (); + + /***** Show criterion and button to remove rubric *****/ + Ale_ShowAlertAndButton (ActRemGam,NULL,NULL, + Rub_PutParams,&Rubrics, + Btn_REMOVE_BUTTON,Txt_Remove_game, + Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_game_X, + Rubrics.Rubric.Title); + + /***** Show rubrics again *****/ + Rub_ListAllRubrics (&Rubrics); + } + +/*****************************************************************************/ +/******************************* Remove a rubric *******************************/ +/*****************************************************************************/ + +void Rub_RemoveRubric (void) + { + extern const char *Txt_Rubric_X_removed; + struct Rub_Rubrics Rubrics; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Get rubric code *****/ + if ((Rubrics.Rubric.RubCod = Rub_GetParamRubCod ()) <= 0) + Err_WrongRubricExit (); + + /***** Get data of the rubric from database *****/ + Rub_GetDataOfRubricByCod (&Rubrics.Rubric); + if (!Rub_CheckIfICanEditRubrics ()) + Err_NoPermissionExit (); + + /***** Remove rubric from all tables *****/ + Rub_RemoveRubricFromAllTables (Rubrics.Rubric.RubCod); + + /***** Write message to show the change made *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Rubric_X_removed, + Rubrics.Rubric.Title); + + /***** Show rubrics again *****/ + Rub_ListAllRubrics (&Rubrics); + } + +/*****************************************************************************/ +/*********************** Remove rubric from all tables *************************/ +/*****************************************************************************/ + +static void Rub_RemoveRubricFromAllTables (long RubCod) + { + /***** Remove rubric criteria *****/ + Rub_DB_RemoveRubricCriteria (RubCod); + + /***** Remove rubric *****/ + Rub_DB_RemoveRubric (RubCod); + } + +/*****************************************************************************/ +/*********************** Remove all rubrics of a course ************************/ +/*****************************************************************************/ + +void Rub_RemoveCrsRubrics (long CrsCod) + { + /***** Remove the criteria in rubrics *****/ + Rub_DB_RemoveCrsRubricCriteria (CrsCod); + + /***** Remove the rubrics *****/ + Rub_DB_RemoveCrsRubrics (CrsCod); + } + +/*****************************************************************************/ +/************************ List the criteria in a rubric ********************/ +/*****************************************************************************/ + +void Rub_ListRubric (void) + { + struct Rub_Rubrics Rubrics; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Get parameters *****/ + if ((Rubrics.Rubric.RubCod = Rub_GetParams (&Rubrics)) <= 0) + Err_WrongRubricExit (); + + /***** Get rubric data *****/ + Rub_GetDataOfRubricByCod (&Rubrics.Rubric); + Rub_DB_GetRubricTxt (Rubrics.Rubric.RubCod,Txt); + + /***** Show rubric *****/ + Rub_ShowOnlyOneRubric (&Rubrics, + true); // List rubric criteria + } + +/*****************************************************************************/ +/**************** Request the creation or edition of a rubric ******************/ +/*****************************************************************************/ + +void Rub_RequestCreatOrEditRubric (void) + { + struct Rub_Rubrics Rubrics; + bool ItsANewRubric; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Check if I can edit rubrics *****/ + if (!Rub_CheckIfICanEditRubrics ()) + Err_NoPermissionExit (); + + /***** Get parameters *****/ + ItsANewRubric = ((Rubrics.Rubric.RubCod = Rub_GetParams (&Rubrics)) <= 0); + + /***** Get rubric data *****/ + if (ItsANewRubric) + { + /* Initialize to empty rubric */ + Rub_ResetRubric (&Rubrics.Rubric); + Txt[0] = '\0'; + } + else + { + /* Get rubric data from database */ + Rub_GetDataOfRubricByCod (&Rubrics.Rubric); + Rub_DB_GetRubricTxt (Rubrics.Rubric.RubCod,Txt); + } + + /***** Put forms to create/edit a rubric *****/ + Rub_PutFormsEditionRubric (&Rubrics,Txt,ItsANewRubric); + + /***** Show rubrics or criteria *****/ + if (ItsANewRubric) + /* Show rubrics again */ + Rub_ListAllRubrics (&Rubrics); + else + /* Show criteria of the rubric ready to be edited */ + Rub_ListRubricCriteria (&Rubrics); + } + +/*****************************************************************************/ +/******************** Put a form to create/edit a rubric *********************/ +/*****************************************************************************/ + +static void Rub_PutFormsEditionRubric (struct Rub_Rubrics *Rubrics, + char Txt[Cns_MAX_BYTES_TEXT + 1], + bool ItsANewRubric) + { + extern const char *Hlp_ASSESSMENT_Rubrics_new_rubric; + extern const char *Hlp_ASSESSMENT_Rubrics_edit_rubric; + extern const char *Txt_New_rubric; + extern const char *Txt_Edit_rubric; + extern const char *Txt_Title; + extern const char *Txt_Description; + extern const char *Txt_Create_rubric; + extern const char *Txt_Save_changes; + + /***** Begin form *****/ + Frm_BeginForm (ItsANewRubric ? ActNewRub : + ActChgRub); + Rub_PutParams (Rubrics); + + /***** Begin box and table *****/ + if (ItsANewRubric) + Box_BoxTableBegin (NULL,Txt_New_rubric, + NULL,NULL, + Hlp_ASSESSMENT_Rubrics_new_rubric,Box_NOT_CLOSABLE,2); + else + Box_BoxTableBegin (NULL, + Rubrics->Rubric.Title[0] ? Rubrics->Rubric.Title : + Txt_Edit_rubric, + NULL,NULL, + Hlp_ASSESSMENT_Rubrics_edit_rubric,Box_NOT_CLOSABLE,2); + + /***** Rubric title *****/ + HTM_TR_Begin (NULL); + + /* Label */ + Frm_LabelColumn ("RT","Title",Txt_Title); + + /* Data */ + HTM_TD_Begin ("class=\"LT\""); + HTM_INPUT_TEXT ("Title",Rub_MAX_CHARS_TITLE,Rubrics->Rubric.Title, + HTM_DONT_SUBMIT_ON_CHANGE, + "id=\"Title\"" + " class=\"TITLE_DESCRIPTION_WIDTH INPUT_%s\"" + " required=\"required\"", + The_GetSuffix ()); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Rubric text *****/ + HTM_TR_Begin (NULL); + + /* Label */ + Frm_LabelColumn ("RT","Txt",Txt_Description); + + /* Data */ + HTM_TD_Begin ("class=\"LT\""); + HTM_TEXTAREA_Begin ("id=\"Txt\" name=\"Txt\" rows=\"5\"" + " class=\"TITLE_DESCRIPTION_WIDTH INPUT_%s\"", + The_GetSuffix ()); + HTM_Txt (Txt); + HTM_TEXTAREA_End (); + HTM_TD_End (); + + HTM_TR_End (); + + /***** End table, send button and end box *****/ + if (ItsANewRubric) + Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_rubric); + else + Box_BoxTableWithButtonEnd (Btn_CONFIRM_BUTTON,Txt_Save_changes); + + /***** End form *****/ + Frm_EndForm (); + } + +/*****************************************************************************/ +/********************** Receive form to create a new rubric ********************/ +/*****************************************************************************/ + +void Rub_ReceiveFormRubric (void) + { + struct Rub_Rubrics Rubrics; + bool ItsANewRubric; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Reset rubrics context *****/ + Rub_ResetRubrics (&Rubrics); + + /***** Reset rubric *****/ + Rub_ResetRubric (&Rubrics.Rubric); + + /***** Check if I can edit rubrics *****/ + if (!Rub_CheckIfICanEditRubrics ()) + Err_NoPermissionExit (); + + /***** Get parameters *****/ + ItsANewRubric = ((Rubrics.Rubric.RubCod = Rub_GetParams (&Rubrics)) <= 0); + + /***** If I can edit rubrics ==> receive rubric from form *****/ + if (Rub_CheckIfICanEditRubrics ()) + { + Rub_ReceiveRubricFieldsFromForm (&Rubrics.Rubric,Txt); + if (Rub_CheckRubricFieldsReceivedFromForm (&Rubrics.Rubric)) + { + /***** Create a new rubric or update an existing one *****/ + if (ItsANewRubric) + Rub_CreateRubric (&Rubrics.Rubric,Txt); // Add new rubric to database + else + Rub_UpdateRubric (&Rubrics.Rubric,Txt); // Update rubric data in database + + /***** Put forms to edit the rubric created or updated *****/ + Rub_PutFormsEditionRubric (&Rubrics,Txt, + false); // No new rubric + + /***** Show criteria of the rubric ready to be edited ******/ + Rub_ListRubricCriteria (&Rubrics); + } + else + { + /***** Put forms to create/edit the rubric *****/ + Rub_PutFormsEditionRubric (&Rubrics,Txt,ItsANewRubric); + + /***** Show rubrics or criteria *****/ + if (ItsANewRubric) + /* Show rubrics again */ + Rub_ListAllRubrics (&Rubrics); + else + /* Show criteria of the rubric ready to be edited */ + Rub_ListRubricCriteria (&Rubrics); + } + } + else + Err_NoPermissionExit (); + } + +static void Rub_ReceiveRubricFieldsFromForm (struct Rub_Rubric *Rubric, + char Txt[Cns_MAX_BYTES_TEXT + 1]) + { + /***** Get rubric title *****/ + Par_GetParToText ("Title",Rubric->Title,Rub_MAX_BYTES_TITLE); + + /***** Get rubric text *****/ + Par_GetParToHTML ("Txt",Txt,Cns_MAX_BYTES_TEXT); // Store in HTML format (not rigorous) + } + +static bool Rub_CheckRubricFieldsReceivedFromForm (const struct Rub_Rubric *Rubric) + { + extern const char *Txt_Already_existed_a_game_with_the_title_X; + bool NewRubricIsCorrect; + + /***** Check if title is correct *****/ + NewRubricIsCorrect = true; + if (Rubric->Title[0]) // If there's a rubric title + { + /* If title of rubric was in database... */ + if (Rub_DB_CheckIfSimilarRubricExists (Rubric)) + { + NewRubricIsCorrect = false; + Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_a_game_with_the_title_X, + Rubric->Title); + } + } + else // If there is not a rubric title + { + NewRubricIsCorrect = false; + Ale_ShowAlertYouMustSpecifyTheTitle (); + } + + return NewRubricIsCorrect; + } + +/*****************************************************************************/ +/**************************** Create a new rubric ******************************/ +/*****************************************************************************/ + +static void Rub_CreateRubric (struct Rub_Rubric *Rubric,const char *Txt) + { + extern const char *Txt_Created_new_game_X; + + /***** Create a new rubric *****/ + Rubric->RubCod = Rub_DB_CreateRubric (Rubric,Txt); + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_game_X, + Rubric->Title); + } + +/*****************************************************************************/ +/************************* Update an existing rubric *************************/ +/*****************************************************************************/ + +static void Rub_UpdateRubric (struct Rub_Rubric *Rubric,const char *Txt) + { + extern const char *Txt_The_rubric_has_been_modified; + + /***** Update the data of the rubric *****/ + Rub_DB_UpdateRubric (Rubric,Txt); + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_The_rubric_has_been_modified); + } + +/*****************************************************************************/ +/****************** Write parameter with index of criterion ******************/ +/*****************************************************************************/ + +void Rub_PutParamCriInd (unsigned CriInd) + { + Par_PutHiddenParamUnsigned (NULL,"CriInd",CriInd); + } + +/*****************************************************************************/ +/******************* Get parameter with index of criterion *******************/ +/*****************************************************************************/ + +unsigned Rub_GetParamCriInd (void) + { + long CriInd; + + if ((CriInd = Par_GetParToLong ("CriInd")) <= 0) // In rubrics, criterion index should be 1, 2, 3... + Err_WrongCriterionIndexExit (); + + return (unsigned) CriInd; + } + +/*****************************************************************************/ +/********************** List the criteria of a rubric **********************/ +/*****************************************************************************/ + +static void Rub_ListRubricCriteria (struct Rub_Rubrics *Rubrics) + { + extern const char *Hlp_ASSESSMENT_Rubrics_criteria; + extern const char *Txt_Criteria; + MYSQL_RES *mysql_res; + unsigned NumCriteria; + bool ICanEditCriteria = Rub_CheckIfICanEditRubrics (); + + /***** Get data of criteria from database *****/ + NumCriteria = Rub_DB_GetRubricCriteriaBasic (&mysql_res,Rubrics->Rubric.RubCod); + + /***** Begin box *****/ + if (ICanEditCriteria) + Box_BoxBegin (NULL,Txt_Criteria, + Rub_PutIconToAddNewCriterion,Rubrics, + Hlp_ASSESSMENT_Rubrics_criteria,Box_NOT_CLOSABLE); + else + Box_BoxBegin (NULL,Txt_Criteria, + NULL,NULL, + Hlp_ASSESSMENT_Rubrics_criteria,Box_NOT_CLOSABLE); + + /***** Show table with criteria *****/ + if (NumCriteria) + Rub_ListOneOrMoreCriteriaForEdition (Rubrics,NumCriteria,mysql_res, + ICanEditCriteria); + + /***** Put button to add a new criterion in this rubric *****/ + if (ICanEditCriteria) // I can edit criteria + Rub_PutButtonToAddNewCriterion (Rubrics); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** End box *****/ + Box_BoxEnd (); + } + +/*****************************************************************************/ +/********************* List rubric criteria for edition ***********************/ +/*****************************************************************************/ + +static void Rub_ListOneOrMoreCriteriaForEdition (struct Rub_Rubrics *Rubrics, + unsigned NumCriteria, + MYSQL_RES *mysql_res, + bool ICanEditCriteria) + { + extern const char *Txt_Criteria; + extern const char *Txt_No_INDEX; + extern const char *Txt_Code; + extern const char *Txt_Tags; + extern const char *Txt_Criterion; + extern const char *Txt_Movement_not_allowed; + unsigned NumCri; + unsigned CriInd; + unsigned MaxCriInd; + MYSQL_ROW row; + struct Rub_Criterion Criterion; + char StrCriInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; + bool CriterionExists; + char *Anchor = NULL; + + /***** Trivial check *****/ + if (!NumCriteria) + return; + + /***** Get maximum criterion index *****/ + MaxCriInd = Rub_DB_GetMaxCriterionIndexInRubric (Rubrics->Rubric.RubCod); // 0 is no criteria in rubric + + /***** Write the heading *****/ + HTM_TABLE_BeginWideMarginPadding (5); + + HTM_TR_Begin (NULL); + HTM_TH_Empty (1); + HTM_TH (Txt_No_INDEX ,HTM_HEAD_CENTER); + HTM_TH (Txt_Code ,HTM_HEAD_CENTER); + HTM_TH (Txt_Tags ,HTM_HEAD_CENTER); + HTM_TH (Txt_Criterion,HTM_HEAD_CENTER); + HTM_TR_End (); + + /***** Write rows *****/ + for (NumCri = 0, The_ResetRowColor (); + NumCri < NumCriteria; + NumCri++, The_ChangeRowColor ()) + { + /***** Create rubric criterion *****/ + Rub_CriterionConstructor (&Criterion); + + /***** Get criterion data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0] QstCod + row[1] QstInd + */ + /* Get criterion code (row[0]) */ + Criterion.CriCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get criterion index (row[1]) */ + CriInd = Str_ConvertStrToUnsigned (row[1]); + snprintf (StrCriInd,sizeof (StrCriInd),"%u",CriInd); + + /***** Build anchor string *****/ + Frm_SetAnchorStr (Criterion.CriCod,&Anchor); + + /***** Begin row *****/ + HTM_TR_Begin (NULL); + + /***** Icons *****/ + HTM_TD_Begin ("class=\"BT %s\"",The_GetColorRows ()); + + /* Put icon to remove the criterion */ + if (ICanEditCriteria) + Ico_PutContextualIconToRemove (ActReqRemGamQst,NULL, + Rub_PutParamsOneQst,Rubrics); + else + Ico_PutIconRemovalNotAllowed (); + + /* Put icon to move up the criterion */ + if (ICanEditCriteria && CriInd > 1) + Lay_PutContextualLinkOnlyIcon (ActUp_GamQst,Anchor, + Rub_PutParamsOneQst,Rubrics, + "arrow-up.svg",Ico_BLACK); + else + Ico_PutIconOff ("arrow-up.svg",Ico_BLACK, + Txt_Movement_not_allowed); + + /* Put icon to move down the criterion */ + if (ICanEditCriteria && CriInd < MaxCriInd) + Lay_PutContextualLinkOnlyIcon (ActDwnGamQst,Anchor, + Rub_PutParamsOneQst,Rubrics, + "arrow-down.svg",Ico_BLACK); + else + Ico_PutIconOff ("arrow-down.svg",Ico_BLACK, + Txt_Movement_not_allowed); + + /* Put icon to edit the criterion */ + if (ICanEditCriteria) + Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL, + Rub_PutParamCriCod,&Criterion.CriCod); + + HTM_TD_End (); + + /***** Criterion *****/ + CriterionExists = Rub_GetCriterionDataFromDB (&Criterion); + Rub_ListCriterionForEdition (&Criterion,CriInd,CriterionExists,Anchor); + + /***** End row *****/ + HTM_TR_End (); + + /***** Free anchor string *****/ + Frm_FreeAnchorStr (Anchor); + + /***** Destroy rubric criterion *****/ + Rub_CriterionDestructor (&Criterion); + } + + /***** End table *****/ + HTM_TABLE_End (); + } + +/*****************************************************************************/ +/***************** Put icon to add a new criterion to rubric *****************/ +/*****************************************************************************/ + +static void Rub_PutIconToAddNewCriterion (void *Rubrics) + { + Ico_PutContextualIconToAdd (ActAddOneGamQst,NULL,Rub_PutParams,Rubrics); + } + +/*****************************************************************************/ +/***************** Put button to add new criteria to rubric ******************/ +/*****************************************************************************/ + +static void Rub_PutButtonToAddNewCriterion (struct Rub_Rubrics *Rubrics) + { + extern const char *Txt_Add_criteria; + + Frm_BeginForm (ActAddOneGamQst); + Rub_PutParams (Rubrics); + + Btn_PutConfirmButton (Txt_Add_criteria); + + Frm_EndForm (); + } + +/*****************************************************************************/ +/************************** Show stats about rubrics *************************/ +/*****************************************************************************/ + +void Rub_GetAndShowRubricsStats (void) + { + extern const char *Hlp_ANALYTICS_Figures_rubrics; + extern const char *Txt_FIGURE_TYPES[Fig_NUM_FIGURES]; + extern const char *Txt_Number_of_BR_rubrics; + extern const char *Txt_Number_of_BR_courses_with_BR_rubrics; + extern const char *Txt_Average_number_BR_of_rubrics_BR_per_course; + extern const char *Txt_Average_number_BR_of_criteria_BR_per_rubric; + unsigned NumRubrics; + unsigned NumCoursesWithRubrics = 0; + double NumRubricsPerCourse = 0.0; + double NumCriteriaPerRubric = 0.0; + + // Err_ShowErrorAndExit ("Rub_GetAndShowRubricsStats ()"); + + /***** Get the number of rubrics from this location *****/ + if ((NumRubrics = Rub_DB_GetNumRubrics (Gbl.Scope.Current))) + { + if ((NumCoursesWithRubrics = Rub_DB_GetNumCoursesWithRubrics (Gbl.Scope.Current)) != 0) + NumRubricsPerCourse = (double) NumRubrics / + (double) NumCoursesWithRubrics; + NumCriteriaPerRubric = Rub_DB_GetNumCriteriaPerRubric (Gbl.Scope.Current); + } + + /***** Begin box and table *****/ + Box_BoxTableBegin (NULL,Txt_FIGURE_TYPES[Fig_RUBRICS], + NULL,NULL, + Hlp_ANALYTICS_Figures_rubrics,Box_NOT_CLOSABLE,2); + + /***** Write table heading *****/ + HTM_TR_Begin (NULL); + HTM_TH (Txt_Number_of_BR_rubrics ,HTM_HEAD_RIGHT); + HTM_TH (Txt_Number_of_BR_courses_with_BR_rubrics ,HTM_HEAD_RIGHT); + HTM_TH (Txt_Average_number_BR_of_rubrics_BR_per_course ,HTM_HEAD_RIGHT); + HTM_TH (Txt_Average_number_BR_of_criteria_BR_per_rubric,HTM_HEAD_RIGHT); + HTM_TR_End (); + + /***** Write number of rubrics *****/ + HTM_TR_Begin (NULL); + + HTM_TD_Begin ("class=\"RM DAT_%s\"",The_GetSuffix ()); + HTM_Unsigned (NumRubrics); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"RM DAT_%s\"",The_GetSuffix ()); + HTM_Unsigned (NumCoursesWithRubrics); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"RM DAT_%s\"",The_GetSuffix ()); + HTM_Double2Decimals (NumRubricsPerCourse); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"RM DAT_%s\"",The_GetSuffix ()); + HTM_Double2Decimals (NumCriteriaPerRubric); + HTM_TD_End (); + + HTM_TR_End (); + + /***** End table and box *****/ + Box_BoxTableEnd (); + } + +/*****************************************************************************/ +/********************** Initialize a new citerion to zero ********************/ +/*****************************************************************************/ + +void Rub_CriterionConstructor (struct Rub_Criterion *Criterion) + { + Criterion->CriCod = -1L; + } + +/*****************************************************************************/ +/*************** Free memory allocated for rubric criterion ******************/ +/*****************************************************************************/ + +void Rub_CriterionDestructor (struct Rub_Criterion *Criterion) + { + Criterion->CriCod = -1L; + } + +/*****************************************************************************/ +/*********** Put parameter with criterion code to edit, remove... ************/ +/*****************************************************************************/ + +void Rub_PutParamCriCod (void *CriCod) // Should be a pointer to long + { + if (CriCod) + if (*((long *) CriCod) > 0) // If criterion exists + Par_PutHiddenParamLong (NULL,"CriCod",*((long *) CriCod)); + } + +/*****************************************************************************/ +/*************** Get data of a rubric criterion from database ****************/ +/*****************************************************************************/ + +bool Rub_GetCriterionDataFromDB (struct Rub_Criterion *Criterion) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + bool CriterionExists; + + /***** Get question data from database *****/ + if ((CriterionExists = (Rub_DB_GetCriterionData (&mysql_res,Criterion->CriCod) != 0))) + { + row = mysql_fetch_row (mysql_res); + + /* Get the title (row[0]) */ + Criterion->Title[0] = '\0'; + if (row[0]) + if (row[0][0]) + Str_Copy (Criterion->Title,row[0],Cns_MAX_BYTES_TEXT); + } + + /* Free structure that stores the query result */ + DB_FreeMySQLResult (&mysql_res); + + return CriterionExists; + } + +/*****************************************************************************/ +/******************* List a rubric criterion for edition *********************/ +/*****************************************************************************/ + +void Rub_ListCriterionForEdition (struct Rub_Criterion *Criterion, + unsigned CriInd,bool CriterionExists, + const char *Anchor) + { + extern const char *Txt_Criterion_removed; + + /***** Number of criterion *****/ + HTM_TD_Begin ("class=\"RT %s\"",The_GetColorRows ()); + Rub_WriteNumCriterion (CriInd,"BIG_INDEX"); + HTM_TD_End (); + + /***** Write criterion code *****/ + HTM_TD_Begin ("class=\"CT DAT_SMALL_%s %s CT\"", + The_GetSuffix (),The_GetColorRows ()); + HTM_TxtF ("%ld ",Criterion->CriCod); + HTM_TD_End (); + + /***** Write title *****/ + HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ()); + HTM_ARTICLE_Begin (Anchor); + if (CriterionExists) + /* Write title */ + Rub_WriteCriterionTitle (Criterion->Title,"Qst_TXT", + true); // Visible + else + { + HTM_SPAN_Begin ("class=\"DAT_LIGHT_%s\"", + The_GetSuffix ()); + HTM_Txt (Txt_Criterion_removed); + HTM_SPAN_End (); + } + HTM_ARTICLE_End (); + HTM_TD_End (); + } + +/*****************************************************************************/ +/******************* Write the number of a rubric criterion ******************/ +/*****************************************************************************/ +// Number of criterion should be 1, 2, 3... + +void Rub_WriteNumCriterion (unsigned NumCri,const char *Class) + { + HTM_DIV_Begin ("class=\"%s_%s\"",Class,The_GetSuffix ()); + HTM_Unsigned (NumCri); + HTM_DIV_End (); + } + +/*****************************************************************************/ +/******************* Write the title of a rubric criterion *******************/ +/*****************************************************************************/ + +void Rub_WriteCriterionTitle (const char *Title,const char *ClassTitle,bool Visible) + { + unsigned long TitleLength; + char *TitleRigorousHTML; + + /***** DIV begin *****/ + HTM_DIV_Begin ("class=\"%s_%s\"",ClassTitle,The_GetSuffix ()); + + /***** Write title *****/ + if (Title && Visible) + { + if (Title[0]) + { + /* Convert the title, that is in HTML, to rigorous HTML */ + TitleLength = strlen (Title) * Str_MAX_BYTES_PER_CHAR; + if ((TitleRigorousHTML = malloc (TitleLength + 1)) == NULL) + Err_NotEnoughMemoryExit (); + Str_Copy (TitleRigorousHTML,Title,TitleLength); + + Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, + TitleRigorousHTML,TitleLength,false); + + /* Write title text */ + HTM_Txt (TitleRigorousHTML); + + /* Free memory allocated for the title */ + free (TitleRigorousHTML); + } + } + else + Ico_PutIconNotVisible (); + + /***** DIV end *****/ + HTM_DIV_End (); + } diff --git a/swad_rubric.h b/swad_rubric.h new file mode 100644 index 00000000..9cebae29 --- /dev/null +++ b/swad_rubric.h @@ -0,0 +1,119 @@ +// swad_rubric.h: assessment rubrics + +#ifndef _SWAD_RUB +#define _SWAD_RUB +/* + 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-2022 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_date.h" +#include "swad_scope.h" + +/*****************************************************************************/ +/************************** Public types and constants ***********************/ +/*****************************************************************************/ + +#define Rub_MAX_CHARS_TITLE (128 - 1) // 127 +#define Rub_MAX_BYTES_TITLE ((Rub_MAX_CHARS_TITLE + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 + +#define Rub_AFTER_LAST_CRITERION ((unsigned)((1UL << 31) - 1)) // 2^31 - 1, don't change this number because it is used in database + +struct Rub_Rubric + { + long RubCod; // Rubric code + long CrsCod; // Course code + long UsrCod; // Author code + char Title[Rub_MAX_BYTES_TITLE + 1]; + unsigned NumCriteria; // Number of criteria in the rubric + }; + +struct Rub_Rubrics + { + bool LstIsRead; // Is the list already read from database... + // ...or it needs to be read? + unsigned Num; // Total number of rubrics + long *Lst; // List of rubric codes + unsigned CurrentPage; + struct Rub_Rubric Rubric; // Selected/current rubric + }; + +struct Rub_Criterion + { + long RubCod; // Rubric code + long CriCod; // Course code + char Title[Rub_MAX_BYTES_TITLE + 1]; + }; + +/*****************************************************************************/ +/***************************** Public prototypes *****************************/ +/*****************************************************************************/ + +void Rub_ResetRubrics (struct Rub_Rubrics *Rubrics); +void Rub_ResetRubric (struct Rub_Rubric *Rubric); + +void Rub_SeeAllRubrics (void); +void Rub_ListAllRubrics (struct Rub_Rubrics *Rubrics); +void Rub_SeeOneRubric (void); +void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics, + bool ListRubricDims); +void Rub_ShowOnlyOneRubricBegin (struct Rub_Rubrics *Rubrics, + bool ListRubricDims); +void Rub_ShowOnlyOneRubricEnd (void); + +void Rub_SetCurrentRubCod (long GamCod); +void Rub_PutParams (void *Rubrics); +void Rub_PutParamRubCod (long RubCod); +long Rub_GetParamRubCod (void); +long Rub_GetParams (struct Rub_Rubrics *Rubrics); + +void Rub_GetListRubrics (struct Rub_Rubrics *Rubrics); +void Rub_GetDataOfRubricByCod (struct Rub_Rubric *Rubric); +void Rub_GetDataOfRubricByFolder (struct Rub_Rubric *Rubric); +void Rub_FreeListRubrics (struct Rub_Rubrics *Rubrics); + +void Rub_AskRemRubric (void); +void Rub_RemoveRubric (void); +void Rub_RemoveCrsRubrics (long CrsCod); + +void Rub_ListRubric (void); + +void Rub_RequestCreatOrEditRubric (void); + +void Rub_ReceiveFormRubric (void); + +//------------------------------- Criteria ------------------------------------ +void Rub_CriterionConstructor (struct Rub_Criterion *Criterion); +void Rub_CriterionDestructor (struct Rub_Criterion *Criterion); +void Rub_PutParamCriCod (void *CriCod); +bool Rub_GetCriterionDataFromDB (struct Rub_Criterion *Criterion); +void Rub_ListCriterionForEdition (struct Rub_Criterion *Criterion, + unsigned CriInd,bool CriterionExists, + const char *Anchor); +void Rub_WriteNumCriterion (unsigned NumDim,const char *Class); +void Rub_WriteCriterionTitle (const char *Title,const char *ClassTitle,bool Visible); + +//-------------------------------- Figures ------------------------------------ +void Rub_GetAndShowRubricsStats (void); + +#endif diff --git a/swad_rubric_database.c b/swad_rubric_database.c new file mode 100644 index 00000000..8c6a5e0d --- /dev/null +++ b/swad_rubric_database.c @@ -0,0 +1,672 @@ +// swad_rubric_database.c: assessment rubrics, operations with 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-2022 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 asprintf +#include // For free + +#include "swad_database.h" +#include "swad_error.h" +#include "swad_rubric.h" +#include "swad_rubric_database.h" +#include "swad_global.h" + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/*************************** Create a new rubric *****************************/ +/*****************************************************************************/ + +long Rub_DB_CreateRubric (const struct Rub_Rubric *Rubric,const char *Txt) + { + return + DB_QueryINSERTandReturnCode ("can not create new rubric", + "INSERT INTO rub_rubrics" + " (CrsCod,UsrCod,Title,Txt)" + " VALUES" + " (%ld,%ld,'%s','%s')", + Gbl.Hierarchy.Crs.CrsCod, + Gbl.Usrs.Me.UsrDat.UsrCod, + Rubric->Title, + Txt); + } + +/*****************************************************************************/ +/************************** Update an existing rubric ************************/ +/*****************************************************************************/ + +void Rub_DB_UpdateRubric (const struct Rub_Rubric *Rubric,const char *Txt) + { + DB_QueryUPDATE ("can not update rubric", + "UPDATE rub_rubrics" + " SET CrsCod=%ld," + "Title='%s'," + "Txt='%s'" + " WHERE RubCod=%ld", + Gbl.Hierarchy.Crs.CrsCod, + Rubric->Title, + Txt, + Rubric->RubCod); + } + +/*****************************************************************************/ +/************** Get list of all rubrics in the current course ****************/ +/*****************************************************************************/ + +unsigned Rub_DB_GetListRubrics (MYSQL_RES **mysql_res) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get rubrics", + "SELECT RubCod" // row[0] + " FROM rub_rubrics" + " WHERE CrsCod=%ld" + " ORDER BY Title", + Gbl.Hierarchy.Crs.CrsCod); + } + +/*****************************************************************************/ +/********************* Get rubric data using its code ************************/ +/*****************************************************************************/ + +unsigned Rub_DB_GetDataOfRubricByCod (MYSQL_RES **mysql_res,long RubCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get rubric data", + "SELECT RubCod," // row[0] + "CrsCod," // row[1] + "UsrCod," // row[2] + "Title" // row[3] + " FROM rub_rubrics" + " WHERE RubCod=%ld" + " AND CrsCod=%ld", // Extra check + RubCod, + Gbl.Hierarchy.Crs.CrsCod); + } + +/*****************************************************************************/ +/********************** Get rubric title from database ***********************/ +/*****************************************************************************/ + +void Rub_DB_GetRubricTitle (long RubCod,char Title[Rub_MAX_BYTES_TITLE + 1]) + { + DB_QuerySELECTString (Title,Rub_MAX_BYTES_TITLE,"can not get rubric title", + "SELECT Title" // row[0] + " FROM rub_rubrics" + " WHERE RubCod=%ld" + " AND CrsCod=%ld", // Extra check + RubCod, + Gbl.Hierarchy.Crs.CrsCod); + } + +/*****************************************************************************/ +/********************** Get rubric text from database ************************/ +/*****************************************************************************/ + +void Rub_DB_GetRubricTxt (long RubCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) + { + DB_QuerySELECTString (Txt,Cns_MAX_BYTES_TEXT,"can not get rubric text", + "SELECT Txt" // row[0] + " FROM rub_rubrics" + " WHERE RubCod=%ld", + RubCod); + } + +/*****************************************************************************/ +/******************* Check if the title of a rubric exists *******************/ +/*****************************************************************************/ + +bool Rub_DB_CheckIfSimilarRubricExists (const struct Rub_Rubric *Rubric) + { + return + DB_QueryEXISTS ("can not check similar rubrics", + "SELECT EXISTS" + "(SELECT *" + " FROM rub_rubrics" + " WHERE CrsCod=%ld" + " AND Title='%s'" + " AND RubCod<>%ld)", + Gbl.Hierarchy.Crs.CrsCod, + Rubric->Title, + Rubric->RubCod); + } + +/*****************************************************************************/ +/******************** Get number of courses with rubrics *********************/ +/*****************************************************************************/ +// Returns the number of courses with rubrics in this location + +unsigned Rub_DB_GetNumCoursesWithRubrics (HieLvl_Level_t Scope) + { + /***** Get number of courses with rubrics from database *****/ + switch (Scope) + { + case HieLvl_SYS: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT CrsCod)" + " FROM rub_rubrics"); + case HieLvl_CTY: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT rub_rubrics.CrsCod)" + " FROM ins_instits," + "ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE ins_instits.CtyCod=%ld" + " AND ins_instits.InsCod=ctr_centers.InsCod" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Ins.InsCod); + case HieLvl_INS: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT rub_rubrics.CrsCod)" + " FROM ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE ctr_centers.InsCod=%ld" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Ins.InsCod); + case HieLvl_CTR: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT rub_rubrics.CrsCod)" + " FROM deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE deg_degrees.CtrCod=%ld" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Ctr.CtrCod); + case HieLvl_DEG: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT rub_rubrics.CrsCod)" + " FROM crs_courses," + "rub_rubrics" + " WHERE crs_courses.DegCod=%ld" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Deg.DegCod); + case HieLvl_CRS: + return (unsigned) + DB_QueryCOUNT ("can not get number of courses with rubrics", + "SELECT COUNT(DISTINCT CrsCod)" + " FROM rub_rubrics" + " WHERE CrsCod=%ld", + Gbl.Hierarchy.Crs.CrsCod); + default: + return 0; + } + } + +/*****************************************************************************/ +/*************************** Get number of rubrics ***************************/ +/*****************************************************************************/ +// Returns the number of rubrics in this location + +unsigned Rub_DB_GetNumRubrics (HieLvl_Level_t Scope) + { + /***** Get number of rubrics from database *****/ + switch (Scope) + { + case HieLvl_SYS: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM rub_rubrics"); + case HieLvl_CTY: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM ins_instits," + "ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE ins_instits.CtyCod=%ld" + " AND ins_instits.InsCod=ctr_centers.InsCod" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Cty.CtyCod); + case HieLvl_INS: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE ctr_centers.InsCod=%ld" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Ins.InsCod); + case HieLvl_CTR: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM deg_degrees," + "crs_courses," + "rub_rubrics" + " WHERE deg_degrees.CtrCod=%ld" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Ctr.CtrCod); + case HieLvl_DEG: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM crs_courses," + "rub_rubrics" + " WHERE crs_courses.DegCod=%ld" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod", + Gbl.Hierarchy.Deg.DegCod); + case HieLvl_CRS: + return (unsigned) + DB_QueryCOUNT ("can not get number of rubrics", + "SELECT COUNT(*)" + " FROM rub_rubrics" + " WHERE CrsCod=%ld", + Gbl.Hierarchy.Crs.CrsCod); + default: + return 0; + } + } + +/*****************************************************************************/ +/******************************** Remove rubric ******************************/ +/*****************************************************************************/ + +void Rub_DB_RemoveRubric (long RubCod) + { + DB_QueryDELETE ("can not remove rubric", + "DELETE FROM rub_rubrics" + " WHERE RubCod=%ld", + RubCod); + } + +/*****************************************************************************/ +/********************** Remove the rubrics of a course ***********************/ +/*****************************************************************************/ + +void Rub_DB_RemoveCrsRubrics (long CrsCod) + { + DB_QueryDELETE ("can not remove course rubrics", + "DELETE FROM rub_rubrics" + " WHERE CrsCod=%ld", + CrsCod); + } + +/*****************************************************************************/ +/**************** Insert criterion in the table of criteria *****************/ +/*****************************************************************************/ + +void Rub_DB_InsertCriterionInRubric (long RubCod,unsigned CriInd,long CriCod) + { + DB_QueryINSERT ("can not add criterion to rubric", + "INSERT INTO rub_criteria" + " (RubCod,CriInd,CriCod)" + " VALUES" + " (%ld,%u,%ld)", + RubCod, + CriInd, + CriCod); + } + +/*****************************************************************************/ +/*********** Update indexes of criteria greater than a given one ***********/ +/*****************************************************************************/ + +void Rub_DB_UpdateIndexesOfCriteriaGreaterThan (long RubCod,unsigned CriInd) + { + DB_QueryUPDATE ("can not update indexes of criteria", + "UPDATE rub_criteria" + " SET CriInd=CriInd-1" + " WHERE RubCod=%ld" + " AND CriInd>%u", + RubCod, + CriInd); + } + +/*****************************************************************************/ +/****************** Change index of a criterion in a rubric ******************/ +/*****************************************************************************/ + +void Rub_DB_UpdateCriterionIndex (long CriInd,long RubCod,long CriCod) + { + DB_QueryUPDATE ("can not exchange indexes of criteria", + "UPDATE rub_criteria" + " SET CriInd=%ld" + " WHERE RubCod=%ld" + " AND CriCod=%ld", + CriInd, + RubCod, + CriCod); + } + +/*****************************************************************************/ +/************ Lock table to make the exchange of criteria atomic ***********/ +/*****************************************************************************/ + +void Rub_DB_LockTable (void) + { + DB_Query ("can not lock tables to move rubric criterion", + "LOCK TABLES rub_criteria WRITE"); + DB_SetThereAreLockedTables (); + } + +/*****************************************************************************/ +/******************* Get number of criteria of a rubric *********************/ +/*****************************************************************************/ + +unsigned Rub_DB_GetNumCriteriaInRubric (long RubCod) + { + /***** Get nuumber of criteria in a rubric from database *****/ + return (unsigned) + DB_QueryCOUNT ("can not get number of criteria of a rubric", + "SELECT COUNT(*)" + " FROM rub_criteria" + " WHERE RubCod=%ld", + RubCod); + } + +/*****************************************************************************/ +/*********************** Get the criteria of a rubric ***********************/ +/*****************************************************************************/ + +unsigned Rub_DB_GetRubricCriteriaBasic (MYSQL_RES **mysql_res,long RubCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get rubric criteria", + "SELECT CriCod," // row[0] + "CriInd" // row[1] + " FROM rub_criteria" + " WHERE RubCod=%ld" + " ORDER BY CriInd", + RubCod); + } + +/*****************************************************************************/ +/********* Get criterion code given rubric and index of criterion ************/ +/*****************************************************************************/ + +long Rub_DB_GetCriCodFromCriInd (long RubCod,unsigned CriInd) + { + long CriCod; + + CriCod = DB_QuerySELECTCode ("can not get criterion code", + "SELECT CriCod" + " FROM rub_criteria" + " WHERE RubCod=%ld" + " AND CriInd=%u", + RubCod, + CriInd); + if (CriCod <= 0) + Err_WrongCriterionExit (); + + return CriCod; + } + +/*****************************************************************************/ +/********** Get criterion index given rubric and code of criterion ***********/ +/*****************************************************************************/ +// Return 0 is criterion is not present in rubric + +unsigned Rub_DB_GetCriIndFromCriCod (long RubCod,long CriCod) + { + return DB_QuerySELECTUnsigned ("can not get criterion index", + "SELECT CriInd" + " FROM rub_criteria" + " WHERE RubCod=%ld" + " AND CriCod=%ld", + RubCod, + CriCod); + } + +/*****************************************************************************/ +/**************** Get maximum criterion index in a rubric ********************/ +/*****************************************************************************/ +// Criterion index can be 1, 2, 3... +// Return 0 if no criteria + +unsigned Rub_DB_GetMaxCriterionIndexInRubric (long RubCod) + { + /***** Get maximum criterion index in a rubric from database *****/ + return DB_QuerySELECTUnsigned ("can not get last criterion index", + "SELECT MAX(CriInd)" + " FROM rub_criteria" + " WHERE RubCod=%ld", + RubCod); + } + +/*****************************************************************************/ +/********* Get previous criterion index to a given index in a rubric *********/ +/*****************************************************************************/ +// Input criterion index can be 1, 2, 3... n-1 +// Return criterion index will be 1, 2, 3... n if previous criterion exists, or 0 if no previous criterion + +unsigned Rub_DB_GetPrevCriterionIndexInRubric (long RubCod,unsigned CriInd) + { + /***** Get previous criterion index in a rubric from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + return DB_QuerySELECTUnsigned ("can not get previous criterion index", + "SELECT COALESCE(MAX(CriInd),0)" + " FROM rub_criteria" + " WHERE RubCod=%ld" + " AND CriInd<%u", + RubCod, + CriInd); + } + +/*****************************************************************************/ +/*********** Get next criterion index to a given index in a rubric ***********/ +/*****************************************************************************/ +// Input criterion index can be 0, 1, 2, 3... n-1 +// Return criterion index will be 1, 2, 3... n if next criterion exists, or big number if no next criterion + +unsigned Rub_DB_GetNextCriterionIndexInRubric (long RubCod,unsigned CriInd) + { + /***** Get next criterion index in a rubric from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + return DB_QuerySELECTUnsigned ("can not get next criterion index", + "SELECT COALESCE(MIN(CriInd),%u)" + " FROM rub_criteria" + " WHERE RubCod=%ld" + " AND CriInd>%u", + Rub_AFTER_LAST_CRITERION, // End of criteria has been reached + RubCod, + CriInd); + } + +/*****************************************************************************/ +/****************** Get data of a criterion from database ********************/ +/*****************************************************************************/ + +unsigned Rub_DB_GetCriterionData (MYSQL_RES **mysql_res,long CriCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get a criterion", + "SELECT Title" // row[0] + " FROM rub_criteria" + " WHERE QstCod=%ld" + " AND CrsCod=%ld", // Extra check + CriCod, + Gbl.Hierarchy.Crs.CrsCod); + } + +/*****************************************************************************/ +/**************** Get average number of criteria per rubric ******************/ +/*****************************************************************************/ + +double Rub_DB_GetNumCriteriaPerRubric (HieLvl_Level_t Scope) + { + /***** Get number of criteria per rubric from database *****/ + switch (Scope) + { + case HieLvl_SYS: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM rub_rubrics," + "rub_criteria" + " WHERE rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable"); + case HieLvl_CTY: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM ins_instits," + "ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics," + "rub_criteria" + " WHERE ins_instits.CtyCod=%ld" + " AND ins_instits.InsCod=ctr_centers.InsCod" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod" + " AND rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable", + Gbl.Hierarchy.Cty.CtyCod); + case HieLvl_INS: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM ctr_centers," + "deg_degrees," + "crs_courses," + "rub_rubrics," + "rub_criteria" + " WHERE ctr_centers.InsCod=%ld" + " AND ctr_centers.CtrCod=deg_degrees.CtrCod" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod" + " AND rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable", + Gbl.Hierarchy.Ins.InsCod); + case HieLvl_CTR: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM deg_degrees," + "crs_courses," + "rub_rubrics," + "rub_criteria" + " WHERE deg_degrees.CtrCod=%ld" + " AND deg_degrees.DegCod=crs_courses.DegCod" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod" + " AND rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable", + Gbl.Hierarchy.Ctr.CtrCod); + case HieLvl_DEG: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM crs_courses," + "rub_rubrics," + "rub_criteria" + " WHERE crs_courses.DegCod=%ld" + " AND crs_courses.CrsCod=rub_rubrics.CrsCod" + " AND rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable", + Gbl.Hierarchy.Deg.DegCod); + case HieLvl_CRS: + return + DB_QuerySELECTDouble ("can not get number of criteria per rubric", + "SELECT AVG(NumCriteria)" + " FROM (SELECT COUNT(rub_criteria.QstCod) AS NumCriteria" + " FROM rub_rubrics," + "rub_criteria" + " WHERE rub_rubrics.Cod=%ld" + " AND rub_rubrics.RubCod=rub_criteria.RubCod" + " GROUP BY rub_criteria.RubCod) AS NumCriteriaTable", + Gbl.Hierarchy.Crs.CrsCod); + default: + Err_WrongScopeExit (); + return 0.0; // Not reached + } + } + +/*****************************************************************************/ +/*********************** Remove criterion from a rubric **********************/ +/*****************************************************************************/ + +void Rub_DB_RemoveCriterionFromRubric (long RubCod,unsigned CriInd) + { + DB_QueryDELETE ("can not remove a criterion", + "DELETE FROM rub_criteria" + " WHERE RubCod=%ld" + " AND CriInd=%u", + RubCod, + CriInd); + } + +/*****************************************************************************/ +/**************************** Remove rubric criteria *************************/ +/*****************************************************************************/ + +void Rub_DB_RemoveRubricCriteria (long RubCod) + { + DB_QueryDELETE ("can not remove rubric criteria", + "DELETE FROM rub_criteria" + " WHERE RubCod=%ld", + RubCod); + } + +/*****************************************************************************/ +/**************** Remove the criteria in rubrics of a course *****************/ +/*****************************************************************************/ + +void Rub_DB_RemoveCrsRubricCriteria (long CrsCod) + { + DB_QueryDELETE ("can not remove criteria in course rubrics", + "DELETE FROM rub_criteria" + " USING rub_rubrics," + "rub_criteria" + " WHERE rub_rubrics.CrsCod=%ld" + " AND rub_rubrics.RubCod=rub_criteria.RubCod", + CrsCod); + } diff --git a/swad_rubric_database.h b/swad_rubric_database.h new file mode 100644 index 00000000..b098f5b6 --- /dev/null +++ b/swad_rubric_database.h @@ -0,0 +1,75 @@ +// swad_rubric_database.h: assessment rubrics, operations with database + +#ifndef _SWAD_RUB_DB +#define _SWAD_RUB_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-2022 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 // To access MySQL databases + +#include "swad_game.h" +#include "swad_hierarchy_level.h" + +/*****************************************************************************/ +/***************************** Public prototypes *****************************/ +/*****************************************************************************/ + +//-------------------------------- Rubrics ------------------------------------ +long Rub_DB_CreateRubric (const struct Rub_Rubric *Rubric,const char *Txt); +void Rub_DB_UpdateRubric (const struct Rub_Rubric *Rubric,const char *Txt); +void Rub_DB_HideOrUnhideRubric (long RubCod,bool Hide); + +unsigned Rub_DB_GetListRubrics (MYSQL_RES **mysql_res); +unsigned Rub_DB_GetDataOfRubricByCod (MYSQL_RES **mysql_res,long RubCod); +void Rub_DB_GetRubricTitle (long RubCod,char Title[Rub_MAX_BYTES_TITLE + 1]); +void Rub_DB_GetRubricTxt (long RubCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); +bool Rub_DB_CheckIfSimilarRubricExists (const struct Rub_Rubric *Rubric); +unsigned Rub_DB_GetNumCoursesWithRubrics (HieLvl_Level_t Scope); +unsigned Rub_DB_GetNumRubrics (HieLvl_Level_t Scope); + +void Rub_DB_RemoveRubric (long RubCod); +void Rub_DB_RemoveCrsRubrics (long CrsCod); + +//--------------------------- Rubric criteria ------------------------------- +void Rub_DB_InsertCriterionInRubric (long RubCod,unsigned CriInd,long CriCod); +void Rub_DB_UpdateIndexesOfCriteriaGreaterThan (long RubCod,unsigned CriInd); +void Rub_DB_UpdateCriterionIndex (long CriInd,long RubCod,long CriCod); +void Rub_DB_LockTable (void); + +unsigned Rub_DB_GetNumCriteriaInRubric (long RubCod); +unsigned Rub_DB_GetRubricCriteriaBasic (MYSQL_RES **mysql_res,long RubCod); +long Rub_DB_GetCriCodFromCriInd (long RubCod,unsigned QstInd); +unsigned Rub_DB_GetCriIndFromCriCod (long RubCod,long QstCod); +unsigned Rub_DB_GetMaxCriterionIndexInRubric (long RubCod); +unsigned Rub_DB_GetPrevCriterionIndexInRubric (long RubCod,unsigned QstInd); +unsigned Rub_DB_GetNextCriterionIndexInRubric (long RubCod,unsigned QstInd); +unsigned Rub_DB_GetCriterionData (MYSQL_RES **mysql_res,long CriCod); +double Rub_DB_GetNumCriteriaPerRubric (HieLvl_Level_t Scope); + +void Rub_DB_RemoveCriterionFromRubric (long RubCod,unsigned CriInd); +void Rub_DB_RemoveRubricCriteria (long RubCod); +void Rub_DB_RemoveCrsRubricCriteria (long CrsCod); + +#endif