swad-core/swad_rubric.c

1158 lines
39 KiB
C

// 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-2024 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <stdbool.h> // For boolean type
#include <stddef.h> // For NULL
#include <stdlib.h> // For free, malloc
#include "swad_action_list.h"
#include "swad_autolink.h"
#include "swad_box.h"
#include "swad_constant.h"
#include "swad_database.h"
#include "swad_error.h"
#include "swad_figure.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_pagination.h"
#include "swad_parameter.h"
#include "swad_parameter_code.h"
#include "swad_rubric.h"
#include "swad_rubric_criteria.h"
#include "swad_rubric_database.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
static void Rub_PutIconsListRubrics (void *Rubrics);
static void Rub_PutIconToCreateNewRubric (struct Rub_Rubrics *Rubrics);
static void Prg_PutIconToViewResourceClipboard (void);
static void Rub_PutParsToCreateNewRubric (void *Rubrics);
static void Rub_PutIconsViewingOneRubric (void *Rubrics);
static void Rub_PutIconsEditingOneRubric (void *Rubrics);
static void Rub_PutIconsToRemEditOneRubric (struct Rub_Rubrics *Rubrics);
static void Rub_WriteAuthor (const struct Rub_Rubric *Rubric);
static void Rub_RemoveRubricFromAllTables (long RubCod);
static void Rub_PutFormEditionRubric (struct Rub_Rubrics *Rubrics,
Rub_ExistingNewRubric_t ExistingNewRubric);
static void Rub_ReceiveRubricFieldsFromForm (struct Rub_Rubric *Rubric);
static bool Rub_CheckRubricFieldsReceivedFromForm (const struct Rub_Rubric *Rubric);
static void Rub_CreateRubric (struct Rub_Rubric *Rubric);
static void Rub_UpdateRubric (struct Rub_Rubric *Rubric);
static bool Rub_CheckIfRecursiveTree (long RubCod,struct Rub_Node **TOS);
/*****************************************************************************/
/*************************** 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
}
/*****************************************************************************/
/************************ Rubric constructor/destructor **********************/
/*****************************************************************************/
void Rub_RubricConstructor (struct Rub_Rubric *Rubric)
{
/***** Initialize to empty rubric *****/
Rubric->RubCod = -1L;
Rubric->HieCod = -1L; // Course code
Rubric->UsrCod = -1L;
Rubric->Title[0] = '\0';
/***** Allocate memory for rubric text *****/
if ((Rubric->Txt = malloc (Cns_MAX_BYTES_TEXT + 1)) == NULL)
Err_NotEnoughMemoryExit ();
Rubric->Txt[0] = '\0';
}
void Rub_RubricDestructor (struct Rub_Rubric *Rubric)
{
/***** Free memory used for rubric text *****/
if (Rubric->Txt != NULL)
{
free (Rubric->Txt);
Rubric->Txt = NULL;
}
}
/*****************************************************************************/
/***************************** Show all rubrics ******************************/
/*****************************************************************************/
void Rub_SeeAllRubrics (void)
{
struct Rub_Rubrics Rubrics;
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_DONT_CHECK_RUB_COD);
/***** 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_No_rubrics;
struct Pag_Pagination Pagination;
unsigned NumRubric;
/***** 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 (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_Span (Txt_Rubric,HTM_HEAD_LEFT,1,2,NULL);
// HTM_TH (Txt_Criteria,HTM_HEAD_RIGHT);
HTM_TR_End ();
/***** Write all rubrics *****/
for (NumRubric = Pagination.FirstItemVisible;
NumRubric <= Pagination.LastItemVisible;
NumRubric++)
{
/***** Get rubric data *****/
Rub_RubricConstructor (&Rubrics->Rubric);
Rubrics->Rubric.RubCod = Rubrics->Lst[NumRubric - 1];
Rub_GetRubricDataByCod (&Rubrics->Rubric);
/***** Show main data of this rubric *****/
Rub_ShowRubricMainData (Rubrics,
false); // Do not show only this rubric
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics->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);
/***** End box *****/
Box_BoxEnd ();
/***** Free list of rubrics *****/
Rub_FreeListRubrics (Rubrics);
}
/*****************************************************************************/
/************************ Check if I can edit rubrics ************************/
/*****************************************************************************/
Usr_Can_t Rub_CheckIfICanEditRubrics (void)
{
static Usr_Can_t ICanEditRubrics[Rol_NUM_ROLES] =
{
[Rol_TCH ] = Usr_CAN,
[Rol_SYS_ADM] = Usr_CAN,
};
return ICanEditRubrics[Gbl.Usrs.Me.Role.Logged];
}
/*****************************************************************************/
/*********************** Check if edition is possible ************************/
/*****************************************************************************/
bool Rub_CheckIfEditable (void)
{
if (Rub_CheckIfICanEditRubrics () == Usr_CAN)
{
/***** Rubric is editable only if ... *****/
// TODO: Change to control that a rubric is not edited in some circunstances?
/*
return Rubric->NumCriteria == 0 ||
Rubric->NumCriteria != 0;
*/
return true;
}
return false; // Questions are not editable
}
/*****************************************************************************/
/****************** Put contextual icons in list of rubrics ******************/
/*****************************************************************************/
static void Rub_PutIconsListRubrics (void *Rubrics)
{
if (Rubrics)
{
if (Rub_CheckIfICanEditRubrics () == Usr_CAN)
{
/***** Put icon to create a new rubric *****/
Rub_PutIconToCreateNewRubric ((struct Rub_Rubrics *) Rubrics);
/***** Put icon to view resource clipboard *****/
Prg_PutIconToViewResourceClipboard ();
}
/***** Link to get resource link *****/
if (Rsc_CheckIfICanGetLink () == Usr_CAN)
Ico_PutContextualIconToGetLink (ActReqLnkRub,NULL,Rub_PutPars,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_PutParsToCreateNewRubric,Rubrics);
}
/*****************************************************************************/
/******************* Put icon to view resource clipboard *********************/
/*****************************************************************************/
static void Prg_PutIconToViewResourceClipboard (void)
{
Ico_PutContextualIconToViewClipboard (ActSeeRscCli_InRub,NULL,NULL,NULL);
}
/*****************************************************************************/
/******************* Put parameters to create a new rubric *******************/
/*****************************************************************************/
static void Rub_PutParsToCreateNewRubric (void *Rubrics)
{
if (Rubrics)
Pag_PutParPagNum (Pag_RUBRICS,((struct Rub_Rubrics *) Rubrics)->CurrentPage);
}
/*****************************************************************************/
/****************************** Show one rubric ******************************/
/*****************************************************************************/
void Rub_SeeOneRubric (void)
{
struct Rub_Rubrics Rubrics;
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
Rub_RubricConstructor (&Rubrics.Rubric);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_CHECK_RUB_COD);
/***** Get rubric data *****/
Rub_GetRubricDataByCod (&Rubrics.Rubric);
/***** Show rubric *****/
Rub_ShowOnlyOneRubric (&Rubrics);
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics.Rubric);
}
/*****************************************************************************/
/******************************* Show one rubric *****************************/
/*****************************************************************************/
void Rub_ShowOnlyOneRubric (struct Rub_Rubrics *Rubrics)
{
extern const char *Hlp_ASSESSMENT_Rubrics;
extern const char *Txt_Rubric;
struct Rub_Node *TOS = NULL;
/***** Begin box *****/
Box_BoxBegin (Rubrics->Rubric.Title[0] ? Rubrics->Rubric.Title :
Txt_Rubric,
Rub_PutIconsViewingOneRubric,Rubrics,
Hlp_ASSESSMENT_Rubrics,Box_NOT_CLOSABLE);
/***** Show main data of this rubric *****/
Rub_ShowRubricMainData (Rubrics,
true); // Show only this rubric
/***** Check if rubric tree is correct *****/
if (Rub_CheckIfRecursiveTree (Rubrics->Rubric.RubCod,&TOS))
Err_RecursiveRubric ();
/***** Write criteria of this rubric *****/
RubCri_ListCriteriaForSeeing (Rubrics);
/***** End box *****/
Box_BoxEnd ();
}
/*****************************************************************************/
/********* Show a pair of rows with the main data of a given rubric **********/
/*****************************************************************************/
void Rub_ShowRubricMainData (struct Rub_Rubrics *Rubrics,
bool ShowOnlyThisRubric)
{
extern const char *Txt_View_rubric;
extern const char *Txt_Number_of_criteria;
/***** 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 ("colspan=\"2\" class=\"LT\"");
else
HTM_TD_Begin ("colspan=\"2\" class=\"LT %s\"",The_GetColorRows ());
/* Rubric title */
Frm_BeginForm (ActSeeOneRub);
Rub_PutPars (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_Unsigned (Rub_DB_GetNumCriteriaInRubric (Rubrics->Rubric.RubCod));
HTM_DIV_End ();
HTM_TD_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 ("class=\"LT\"");
else
HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ());
Rub_WriteAuthor (&Rubrics->Rubric);
HTM_TD_End ();
/***** Text of the rubric *****/
if (ShowOnlyThisRubric)
HTM_TD_Begin ("class=\"LT\"");
else
HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ());
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Rubrics->Rubric.Txt,Cns_MAX_BYTES_TEXT,
Str_DONT_REMOVE_SPACES);
ALn_InsertLinks (Rubrics->Rubric.Txt,Cns_MAX_BYTES_TEXT,60); // Insert links
HTM_DIV_Begin ("class=\"PAR DAT_%s\"",The_GetSuffix ());
HTM_Txt (Rubrics->Rubric.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 when viewing or editing one rubric ****************/
/*****************************************************************************/
static void Rub_PutIconsViewingOneRubric (void *Rubrics)
{
if (Rubrics)
Rub_PutIconsToRemEditOneRubric (Rubrics);
}
static void Rub_PutIconsEditingOneRubric (void *Rubrics)
{
if (Rubrics)
/***** Icon to view rubric *****/
Ico_PutContextualIconToView (ActSeeOneRub,NULL,Rub_PutPars,Rubrics);
}
static void Rub_PutIconsToRemEditOneRubric (struct Rub_Rubrics *Rubrics)
{
if (Rub_CheckIfICanEditRubrics () == Usr_CAN)
{
/***** Icon to remove rubric *****/
Ico_PutContextualIconToRemove (ActReqRemRub,NULL,Rub_PutPars,Rubrics);
/***** Icon to edit rubric *****/
Ico_PutContextualIconToEdit (ActEdiOneRub,NULL,Rub_PutPars,Rubrics);
/***** Link to get resource link *****/
if (Rsc_CheckIfICanGetLink () == Usr_CAN)
Ico_PutContextualIconToGetLink (ActReqLnkRub,NULL,Rub_PutPars,Rubrics);
}
}
/*****************************************************************************/
/*********************** Write the author of a rubric ************************/
/*****************************************************************************/
static void Rub_WriteAuthor (const struct Rub_Rubric *Rubric)
{
Usr_WriteAuthor1Line (Rubric->UsrCod,HidVis_VISIBLE);
}
/*****************************************************************************/
/*********************** Params used to edit a rubric ************************/
/*****************************************************************************/
void Rub_PutPars (void *Rubrics)
{
if (Rubrics)
{
ParCod_PutPar (ParCod_Rub,((struct Rub_Rubrics *) Rubrics)->Rubric.RubCod);
Pag_PutParPagNum (Pag_RUBRICS,((struct Rub_Rubrics *) Rubrics)->CurrentPage);
}
}
/*****************************************************************************/
/****************** Get parameters used to edit a rubric *********************/
/*****************************************************************************/
void Rub_GetPars (struct Rub_Rubrics *Rubrics,Rub_CheckRubCod_t CheckRubCod)
{
long (*GetExaCo[Rub_NUM_CHECK_RUB_COD]) (ParCod_Param_t ParCode) =
{
[Rub_DONT_CHECK_RUB_COD] = ParCod_GetPar,
[Rub_CHECK_RUB_COD ] = ParCod_GetAndCheckPar,
};
/***** Get other parameters *****/
Rubrics->CurrentPage = Pag_GetParPagNum (Pag_RUBRICS);
/***** Get rubric code *****/
Rubrics->Rubric.RubCod = GetExaCo[CheckRubCod] (ParCod_Rub);
}
/*****************************************************************************/
/************************* Get list of all rubrics ***************************/
/*****************************************************************************/
// Txt is not retrieved from database
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 *****/
for (NumRubric = 0;
NumRubric < Rubrics->Num;
NumRubric++)
{
/* Get row */
row = mysql_fetch_row (mysql_res);
/* Get code of the rubric (row[0]) */
Rubrics->Lst[NumRubric] = Str_ConvertStrCodToLongCod (row[0]);
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
Rubrics->LstIsRead = true;
}
/*****************************************************************************/
/*********************** Get rubric data using its code **********************/
/*****************************************************************************/
void Rub_GetRubricDataByCod (struct Rub_Rubric *Rubric)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Get data of rubric from database *****/
if (Rub_DB_GetRubricDataByCod (&mysql_res,Rubric->RubCod)) // Rubric found...
{
/* Get row */
row = mysql_fetch_row (mysql_res);
/* Get code of the rubric (row[0]), course (row[1] and author (row[2]) */
Rubric->RubCod = Str_ConvertStrCodToLongCod (row[0]);
Rubric->HieCod = Str_ConvertStrCodToLongCod (row[1]);
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 rubric text */
Rub_DB_GetRubricTxt (Rubric);
}
else
{
/***** Initialize to empty rubric *****/
Rubric->RubCod = -1L;
Rubric->HieCod = -1L;
Rubric->UsrCod = -1L;
Rubric->Title[0] = '\0';
Rubric->Txt[0] = '\0';
}
/* 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_rubric_X;
struct Rub_Rubrics Rubrics;
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
Rub_RubricConstructor (&Rubrics.Rubric);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_CHECK_RUB_COD);
/***** Get data of the rubric from database *****/
Rub_GetRubricDataByCod (&Rubrics.Rubric);
if (Rub_CheckIfICanEditRubrics () == Usr_CAN_NOT)
Err_NoPermissionExit ();
/***** Show criterion and button to remove rubric *****/
Ale_ShowAlertRemove (ActRemRub,NULL,
Rub_PutPars,&Rubrics,
Txt_Do_you_really_want_to_remove_the_rubric_X,
Rubrics.Rubric.Title);
/***** Show rubrics again *****/
Rub_ListAllRubrics (&Rubrics);
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics.Rubric);
}
/*****************************************************************************/
/****************************** Remove a rubric ******************************/
/*****************************************************************************/
void Rub_RemoveRubric (void)
{
extern const char *Txt_Rubric_X_removed;
struct Rub_Rubrics Rubrics;
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
Rub_RubricConstructor (&Rubrics.Rubric);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_CHECK_RUB_COD);
/***** Get data of the rubric from database *****/
Rub_GetRubricDataByCod (&Rubrics.Rubric);
if (Rub_CheckIfICanEditRubrics () == Usr_CAN_NOT)
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);
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics.Rubric);
}
/*****************************************************************************/
/********************** 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);
}
/*****************************************************************************/
/*************** Request the creation or edition of a rubric *****************/
/*****************************************************************************/
void Rub_ReqCreatOrEditRubric (void)
{
struct Rub_Rubrics Rubrics;
Rub_ExistingNewRubric_t ExistingNewRubric;
/***** Check if I can edit rubrics *****/
if (Rub_CheckIfICanEditRubrics () == Usr_CAN_NOT)
Err_NoPermissionExit ();
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
Rub_RubricConstructor (&Rubrics.Rubric);
RubCri_ResetCriterion (&Rubrics.Criterion);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_DONT_CHECK_RUB_COD);
Rubrics.Criterion.RubCod = Rubrics.Rubric.RubCod;
ExistingNewRubric = (Rubrics.Rubric.RubCod > 0) ? Rub_EXISTING_RUBRIC :
Rub_NEW_RUBRIC;
/***** Get rubric data *****/
switch (ExistingNewRubric)
{
case Rub_EXISTING_RUBRIC:
/* Get rubric data from database */
Rub_GetRubricDataByCod (&Rubrics.Rubric);
break;
case Rub_NEW_RUBRIC:
break;
}
/***** Put form to create/edit a rubric and show criteria *****/
Rub_PutFormsOneRubric (&Rubrics,ExistingNewRubric);
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics.Rubric);
}
/*****************************************************************************/
/******************** Put forms to create/edit a rubric **********************/
/*****************************************************************************/
void Rub_PutFormsOneRubric (struct Rub_Rubrics *Rubrics,
Rub_ExistingNewRubric_t ExistingNewRubric)
{
extern const char *Hlp_ASSESSMENT_Rubrics_new_rubric;
extern const char *Hlp_ASSESSMENT_Rubrics_edit_rubric;
extern const char *Txt_Rubric;
static void (*FunctionToDrawContextualIcons[Rub_NUM_EXISTING_NEW_RUBRIC]) (void *Args) =
{
[Rub_EXISTING_RUBRIC] = Rub_PutIconsEditingOneRubric,
[Rub_NEW_RUBRIC ] = NULL,
};
static const char **HelpLink[Rub_NUM_EXISTING_NEW_RUBRIC] =
{
[Rub_EXISTING_RUBRIC] = &Hlp_ASSESSMENT_Rubrics_edit_rubric,
[Rub_NEW_RUBRIC ] = &Hlp_ASSESSMENT_Rubrics_new_rubric,
};
struct Rub_Node *TOS = NULL;
/***** Begin box *****/
Box_BoxBegin (Rubrics->Rubric.Title[0] ? Rubrics->Rubric.Title :
Txt_Rubric,
FunctionToDrawContextualIcons[ExistingNewRubric],Rubrics,
*HelpLink[ExistingNewRubric],Box_NOT_CLOSABLE);
/***** Put form to create/edit a rubric *****/
Rub_PutFormEditionRubric (Rubrics,ExistingNewRubric);
/***** Check if rubric tree is correct *****/
if (Rub_CheckIfRecursiveTree (Rubrics->Rubric.RubCod,&TOS))
Err_RecursiveRubric ();
/***** Show list of criteria inside box *****/
if (ExistingNewRubric == Rub_EXISTING_RUBRIC)
RubCri_ListCriteriaForEdition (Rubrics);
/***** End box ****/
Box_BoxEnd ();
/***** Show rubrics again outside box *****/
if (ExistingNewRubric == Rub_NEW_RUBRIC)
{
HTM_BR ();
Rub_ListAllRubrics (Rubrics);
}
}
/*****************************************************************************/
/******************** Put a form to create/edit a rubric *********************/
/*****************************************************************************/
static void Rub_PutFormEditionRubric (struct Rub_Rubrics *Rubrics,
Rub_ExistingNewRubric_t ExistingNewRubric)
{
extern const char *Txt_Title;
extern const char *Txt_Description;
extern const char *Txt_Create;
extern const char *Txt_Save_changes;
static Act_Action_t NextAction[Rub_NUM_EXISTING_NEW_RUBRIC] =
{
[Rub_EXISTING_RUBRIC] = ActChgRub,
[Rub_NEW_RUBRIC ] = ActNewRub,
};
static Btn_Button_t Button[Rub_NUM_EXISTING_NEW_RUBRIC] =
{
[Rub_EXISTING_RUBRIC] = Btn_CONFIRM_BUTTON,
[Rub_NEW_RUBRIC ] = Btn_CREATE_BUTTON,
};
const char *TxtButton[Rub_NUM_EXISTING_NEW_RUBRIC] =
{
[Rub_EXISTING_RUBRIC] = Txt_Save_changes,
[Rub_NEW_RUBRIC ] = Txt_Create,
};
/***** Begin form *****/
Frm_BeginForm (NextAction[ExistingNewRubric]);
Rub_PutPars (Rubrics);
/***** Begin table *****/
HTM_TABLE_BeginCenterPadding (2);
/***** Rubric title *****/
HTM_TR_Begin (NULL);
/* Label */
Frm_LabelColumn ("Frm_C1 RT","Title",Txt_Title);
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
HTM_INPUT_TEXT ("Title",Rub_MAX_CHARS_TITLE,Rubrics->Rubric.Title,
HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"Title\""
" class=\"Frm_C2_INPUT INPUT_%s\""
" required=\"required\"",
The_GetSuffix ());
HTM_TD_End ();
HTM_TR_End ();
/***** Rubric text *****/
HTM_TR_Begin (NULL);
/* Label */
Frm_LabelColumn ("Frm_C1 RT","Txt",Txt_Description);
/* Data */
HTM_TD_Begin ("class=\"Frm_C2 LT\"");
HTM_TEXTAREA_Begin ("id=\"Txt\" name=\"Txt\" rows=\"5\""
" class=\"Frm_C2_INPUT INPUT_%s\"",
The_GetSuffix ());
HTM_Txt (Rubrics->Rubric.Txt);
HTM_TEXTAREA_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** End table ****/
HTM_TABLE_End ();
/***** Send button *****/
Btn_PutButton (Button[ExistingNewRubric],
TxtButton[ExistingNewRubric]);
/***** End form *****/
Frm_EndForm ();
}
/*****************************************************************************/
/********************* Receive form to create a new rubric *******************/
/*****************************************************************************/
void Rub_ReceiveRubric (void)
{
struct Rub_Rubrics Rubrics;
Rub_ExistingNewRubric_t ExistingNewRubric;
/***** Check if I can edit rubrics *****/
if (Rub_CheckIfICanEditRubrics () == Usr_CAN_NOT)
Err_NoPermissionExit ();
/***** Reset rubrics context *****/
Rub_ResetRubrics (&Rubrics);
Rub_RubricConstructor (&Rubrics.Rubric);
RubCri_ResetCriterion (&Rubrics.Criterion);
/***** Get parameters *****/
Rub_GetPars (&Rubrics,Rub_DONT_CHECK_RUB_COD);
Rubrics.Criterion.RubCod = Rubrics.Rubric.RubCod;
ExistingNewRubric = (Rubrics.Rubric.RubCod > 0) ? Rub_EXISTING_RUBRIC :
Rub_NEW_RUBRIC;
/***** Get all current rubric data from database *****/
// Some data, not received from form,
// are necessary to show rubric and criteria again
switch (ExistingNewRubric)
{
case Rub_EXISTING_RUBRIC:
Rub_GetRubricDataByCod (&Rubrics.Rubric);
break;
case Rub_NEW_RUBRIC:
break;
}
/***** Overwrite some rubric data with the data received from form *****/
Rub_ReceiveRubricFieldsFromForm (&Rubrics.Rubric);
if (Rub_CheckRubricFieldsReceivedFromForm (&Rubrics.Rubric))
/***** Create a new rubric or update an existing one *****/
switch (ExistingNewRubric)
{
case Rub_EXISTING_RUBRIC:
Rub_UpdateRubric (&Rubrics.Rubric); // Update rubric data in database
break;
case Rub_NEW_RUBRIC:
Rub_CreateRubric (&Rubrics.Rubric); // Add new rubric to database
ExistingNewRubric = Rub_EXISTING_RUBRIC;
break;
}
/***** Show pending alerts */
Ale_ShowAlerts (NULL);
/***** Show current rubric and its criteria *****/
Rub_PutFormsOneRubric (&Rubrics,ExistingNewRubric);
/***** Free memory used for rubric *****/
Rub_RubricDestructor (&Rubrics.Rubric);
}
static void Rub_ReceiveRubricFieldsFromForm (struct Rub_Rubric *Rubric)
{
/***** Get rubric title *****/
Par_GetParText ("Title",Rubric->Title,Rub_MAX_BYTES_TITLE);
/***** Get rubric text *****/
Par_GetParHTML ("Txt",Rubric->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_CreateAlert (Ale_WARNING,NULL,
Txt_Already_existed_a_game_with_the_title_X,
Rubric->Title);
}
}
else // If there is not a rubric title
{
NewRubricIsCorrect = false;
Ale_CreateAlertYouMustSpecifyTheTitle ();
}
return NewRubricIsCorrect;
}
/*****************************************************************************/
/**************************** Create a new rubric ****************************/
/*****************************************************************************/
static void Rub_CreateRubric (struct Rub_Rubric *Rubric)
{
extern const char *Txt_Created_new_rubric_X;
/***** Create a new rubric *****/
Rubric->RubCod = Rub_DB_CreateRubric (Rubric);
/***** Write success message *****/
Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_rubric_X,Rubric->Title);
}
/*****************************************************************************/
/************************* Update an existing rubric *************************/
/*****************************************************************************/
static void Rub_UpdateRubric (struct Rub_Rubric *Rubric)
{
extern const char *Txt_The_rubric_has_been_modified;
/***** Update the data of the rubric *****/
Rub_DB_UpdateRubric (Rubric);
/***** Write success message *****/
Ale_ShowAlert (Ale_SUCCESS,Txt_The_rubric_has_been_modified);
}
/*****************************************************************************/
/********** Recursive function to compute the score of a criterion ***********/
/*****************************************************************************/
// Return true if rubric tree is recursive
/* 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
*/
static bool Rub_CheckIfRecursiveTree (long RubCod,struct Rub_Node **TOS)
{
bool RecursiveTree;
MYSQL_RES *mysql_res;
unsigned NumCriteria;
unsigned NumCriterion;
struct RubCri_Criterion Criterion;
/***** Check that rubric is not yet in the stack *****/
RecursiveTree = Rub_FindRubCodInStack (*TOS,RubCod);
if (!RecursiveTree)
{
/***** Push rubric code in stack *****/
Rub_PushRubCod (TOS,RubCod);
/***** For each criteria in this rubric... *****/
NumCriteria = Rub_DB_GetCriteria (&mysql_res,RubCod);
for (NumCriterion = 0;
NumCriterion < NumCriteria;
NumCriterion++)
{
/* Get criterion data */
RubCri_GetCriterionDataFromRow (mysql_res,&Criterion);
if (Criterion.Link.Type == Rsc_RUBRIC)
if (Rub_CheckIfRecursiveTree (Criterion.Link.Cod,TOS))
{
RecursiveTree = true;
break;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Pop rubric code from stack *****/
Rub_PopRubCod (TOS);
}
return RecursiveTree;
}
/*****************************************************************************/
/************************** 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;
double NumCriteriaPerRubric;
/***** Get the number of rubrics from this location *****/
if ((NumRubrics = Rub_DB_GetNumRubrics (Gbl.Scope.Current)))
{
NumCoursesWithRubrics = Rub_DB_GetNumCoursesWithRubrics (Gbl.Scope.Current);
NumCriteriaPerRubric = Rub_DB_GetNumCriteriaPerRubric (Gbl.Scope.Current);
}
else
{
NumCoursesWithRubrics = 0;
NumCriteriaPerRubric = 0.0;
}
/***** Begin box and table *****/
Box_BoxTableBegin (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_Unsigned (NumRubrics);
HTM_TD_Unsigned (NumCoursesWithRubrics);
HTM_TD_Ratio (NumRubrics,NumCoursesWithRubrics);
HTM_TD_Double2Decimals (NumCriteriaPerRubric);
HTM_TR_End ();
/***** End table and box *****/
Box_BoxTableEnd ();
}