// swad_resource.c: resources for course program and 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 . */ /*****************************************************************************/ /********************************* Headers ***********************************/ /*****************************************************************************/ #include // For boolean type #include // For string functions #include "swad_action_list.h" #include "swad_alert.h" #include "swad_assignment_database.h" #include "swad_attendance_database.h" #include "swad_browser_resource.h" #include "swad_call_for_exam_resource.h" #include "swad_database.h" #include "swad_exam_database.h" #include "swad_forum_database.h" #include "swad_forum_resource.h" #include "swad_game_database.h" #include "swad_global.h" #include "swad_HTML.h" #include "swad_parameter.h" #include "swad_parameter_code.h" #include "swad_project_database.h" #include "swad_resource.h" #include "swad_resource_database.h" #include "swad_role.h" #include "swad_rubric_database.h" #include "swad_survey_database.h" #include "swad_theme.h" /*****************************************************************************/ /***************************** Public constants ******************************/ /*****************************************************************************/ const char *Rsc_ResourceTypesDB[Rsc_NUM_TYPES] = { [Rsc_NONE ] = "non", // gui TEACHING_GUIDE // Link to teaching guide // bib BIBLIOGRAPHY // Link to bibliography // faq FAQ // Link to FAQ // lnk LINKS // Link to links // tmt TIMETABLE // Link to timetable [Rsc_ASSIGNMENT ] = "asg", [Rsc_PROJECT ] = "prj", [Rsc_CALL_FOR_EXAM ] = "cfe", // tst TEST // User selects tags, teacher should select [Rsc_EXAM ] = "exa", [Rsc_GAME ] = "gam", [Rsc_RUBRIC ] = "rub", [Rsc_DOCUMENT ] = "doc", [Rsc_MARKS ] = "mrk", // grp GROUPS // ??? User select groups [Rsc_ATTENDANCE_EVENT] = "att", [Rsc_FORUM_THREAD ] = "for", [Rsc_SURVEY ] = "svy", }; const char *Rsc_ResourceTypesIcons[Rsc_NUM_TYPES] = { [Rsc_NONE ] = "link-slash.svg", // gui TEACHING_GUIDE // Link to teaching guide // bib BIBLIOGRAPHY // Link to bibliography // faq FAQ // Link to FAQ // lnk LINKS // Link to links // tmt TIMETABLE // Link to timetable [Rsc_ASSIGNMENT ] = "edit.svg", [Rsc_PROJECT ] = "file-invoice.svg", [Rsc_CALL_FOR_EXAM ] = "bullhorn.svg", // tst TEST // User selects tags, teacher should select [Rsc_EXAM ] = "file-signature.svg", [Rsc_GAME ] = "gamepad.svg", [Rsc_RUBRIC ] = "tasks.svg", [Rsc_DOCUMENT ] = "file.svg", [Rsc_MARKS ] = "list-alt.svg", // grp GROUPS // ??? User select groups [Rsc_ATTENDANCE_EVENT] = "calendar-check.svg", [Rsc_FORUM_THREAD ] = "comments.svg", [Rsc_SURVEY ] = "poll.svg", }; /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /************************* Show resources clipboard **************************/ /*****************************************************************************/ void Rsc_ShowClipboard (void) { MYSQL_RES *mysql_res; unsigned NumLink; unsigned NumLinks; struct Rsc_Link Link; /***** Begin list *****/ HTM_UL_Begin ("class=\"RSC_CLIPBOARD\""); /***** Get links in clipboard from database and write them *****/ NumLinks = Rsc_DB_GetClipboard (&mysql_res); for (NumLink = 1; NumLink <= NumLinks; NumLink++) { Rsc_GetLinkDataFromRow (mysql_res,&Link); HTM_LI_Begin ("class=\"PRG_RSC_%s\"",The_GetSuffix ()); Rsc_WriteLinkName (&Link,Frm_PUT_FORM); HTM_LI_End (); } DB_FreeMySQLResult (&mysql_res); /***** End list *****/ HTM_UL_End (); } /*****************************************************************************/ /***************** Show clipboard to change resource link ********************/ /*****************************************************************************/ void Rsc_ShowClipboardToChangeLink (const struct Rsc_Link *CurrentLink) { MYSQL_RES *mysql_res; unsigned NumLink; unsigned NumLinks; struct Rsc_Link Link; static const struct Rsc_Link EmptyLink = { .Type = Rsc_NONE, .Cod = -1L, }; /***** Begin list *****/ HTM_UL_Begin ("class=\"RSC_CLIPBOARD\""); if (CurrentLink) // Editing an existing element { /***** Current link (empty or not) *****/ Rsc_WriteRowClipboard (CurrentLink, HTM_DONT_SUBMIT_ON_CLICK, true); // Checked /***** Row with empty link to remove the current link *****/ if (CurrentLink->Type != Rsc_NONE) Rsc_WriteRowClipboard (&EmptyLink, HTM_SUBMIT_ON_CLICK, false); // Not checked } else // Inside form to create a new element /***** Row with empty link *****/ Rsc_WriteRowClipboard (&EmptyLink, HTM_DONT_SUBMIT_ON_CLICK, true); // Checked /***** Get links in clipboard from database and write them *****/ NumLinks = Rsc_DB_GetClipboard (&mysql_res); for (NumLink = 1; NumLink <= NumLinks; NumLink++) { Rsc_GetLinkDataFromRow (mysql_res,&Link); Rsc_WriteRowClipboard (&Link, CurrentLink ? HTM_SUBMIT_ON_CLICK : HTM_DONT_SUBMIT_ON_CLICK, false); // Checked } DB_FreeMySQLResult (&mysql_res); /***** End list *****/ HTM_UL_End (); } /*****************************************************************************/ /************************ Show one link from clipboard ***********************/ /*****************************************************************************/ void Rsc_WriteRowClipboard (const struct Rsc_Link *Link, HTM_SubmitOnClick_t SubmitOnClick, Cns_Checked_t Checked) { /***** Begin list row *****/ HTM_LI_Begin ("class=\"PRG_RSC_%s\"",The_GetSuffix ()); HTM_LABEL_Begin (NULL); /***** Radio selector *****/ HTM_INPUT_RADIO ("Link",Checked,SubmitOnClick, "value=\"%s_%ld\"", Rsc_ResourceTypesDB[Link->Type],Link->Cod); /***** Name *****/ Rsc_WriteLinkName (Link,Frm_DONT_PUT_FORM); HTM_LABEL_End (); /***** End list row *****/ HTM_LI_End (); } /*****************************************************************************/ /************* Write link name (filename, assignment title...) ***************/ /*****************************************************************************/ void Rsc_WriteLinkName (const struct Rsc_Link *Link,Frm_PutForm_t PutFormToGo) { extern const char *Txt_Actions[ActLst_NUM_ACTIONS]; extern const char *Rsc_ResourceTypesIcons[Rsc_NUM_TYPES]; extern const char *Txt_RESOURCE_TYPES[Rsc_NUM_TYPES]; static struct { void (*Set) (long Cod,char **Anchor); void (*Free) (char **Anchor); } FuncAnchor[Rsc_NUM_TYPES] = { [Rsc_NONE ] = {NULL,NULL}, [Rsc_ASSIGNMENT ] = {NULL,NULL}, [Rsc_PROJECT ] = {NULL,NULL}, [Rsc_CALL_FOR_EXAM ] = {Frm_SetAnchorStr,Frm_FreeAnchorStr}, [Rsc_EXAM ] = {NULL,NULL}, [Rsc_GAME ] = {NULL,NULL}, [Rsc_RUBRIC ] = {NULL,NULL}, [Rsc_DOCUMENT ] = {NULL,NULL}, [Rsc_MARKS ] = {NULL,NULL}, [Rsc_ATTENDANCE_EVENT] = {NULL,NULL}, [Rsc_FORUM_THREAD ] = {ForRsc_SetAnchorStr,ForRsc_FreeAnchorStr}, [Rsc_SURVEY ] = {NULL,NULL}, }; static struct { Act_Action_t IfCod; Act_Action_t IfNotCod; } NextActions[Rsc_NUM_TYPES] = { [Rsc_NONE ] = {ActUnk ,ActUnk }, [Rsc_ASSIGNMENT ] = {ActSeeOneAsg ,ActSeeAllAsg }, [Rsc_PROJECT ] = {ActSeeOnePrj ,ActSeeAllPrj }, [Rsc_CALL_FOR_EXAM ] = {ActSeeOneCfe ,ActSeeAllCfe }, [Rsc_EXAM ] = {ActSeeOneExa ,ActSeeAllExa }, [Rsc_GAME ] = {ActSeeOneGam ,ActSeeAllGam }, [Rsc_RUBRIC ] = {ActSeeOneRub ,ActSeeAllRub }, [Rsc_DOCUMENT ] = {ActReqDatSeeDocCrs ,ActSeeAdmDocCrsGrp }, [Rsc_MARKS ] = {ActReqDatSeeMrkCrs ,ActSeeAdmMrk }, [Rsc_ATTENDANCE_EVENT] = {ActSeeOneAtt ,ActSeeAllAtt }, [Rsc_FORUM_THREAD ] = {ActSeePstForCrsUsr ,ActSeeForCrsUsr }, [Rsc_SURVEY ] = {ActSeeOneSvy ,ActSeeAllSvy }, }; static ParCod_Param_t ParCod[Rsc_NUM_TYPES] = { [Rsc_NONE ] = ParCod_None, [Rsc_ASSIGNMENT ] = ParCod_Asg, [Rsc_PROJECT ] = ParCod_Prj, [Rsc_CALL_FOR_EXAM ] = ParCod_Exa, [Rsc_EXAM ] = ParCod_Exa, [Rsc_GAME ] = ParCod_Gam, [Rsc_RUBRIC ] = ParCod_Rub, [Rsc_DOCUMENT ] = ParCod_Fil, [Rsc_MARKS ] = ParCod_Fil, [Rsc_ATTENDANCE_EVENT] = ParCod_Att, [Rsc_FORUM_THREAD ] = ParCod_Thr, [Rsc_SURVEY ] = ParCod_Svy, }; Act_Action_t NextAction; char Title[Cns_MAX_BYTES_SUBJECT + 1]; char *Anchor; /***** Get resource title *****/ Rsc_GetResourceTitleFromLink (Link,Title); /***** Put icon and title of resource *****/ switch (PutFormToGo) { case Frm_DONT_PUT_FORM: /* Icon and title of resource */ Ico_PutIconOn (Rsc_ResourceTypesIcons[Link->Type],Ico_BLACK, Txt_RESOURCE_TYPES[Link->Type]); HTM_Txt (Title); break; case Frm_PUT_FORM: /* Begin form to go to resource */ NextAction = (Link->Cod > 0) ? NextActions[Link->Type].IfCod : // Resource specified NextActions[Link->Type].IfNotCod; // All resources of this type if (FuncAnchor[Link->Type].Set) { FuncAnchor[Link->Type].Set (Link->Cod,&Anchor); Frm_BeginFormAnchor (NextAction,Anchor); FuncAnchor[Link->Type].Free (&Anchor); } else Frm_BeginForm (NextAction); ParCod_PutPar (ParCod[Link->Type],Link->Cod); /* Begin link */ HTM_BUTTON_Submit_Begin (Txt_Actions[NextAction], "class=\"LM BT_LINK PRG_LNK_%s\"", The_GetSuffix ()); /* Icon and title of resource */ Ico_PutIconLink (Rsc_ResourceTypesIcons[Link->Type],Ico_BLACK, NextAction); HTM_Txt (Title); /* End link */ HTM_BUTTON_End (); Frm_EndForm (); break; } } /*****************************************************************************/ /************* Get the title for a new resource from link title **************/ /*****************************************************************************/ void Rsc_GetResourceTitleFromLink (const struct Rsc_Link *Link, char Title[Rsc_MAX_BYTES_RESOURCE_TITLE + 1]) { extern const char *Txt_Assignments; extern const char *Txt_Projects; extern const char *Txt_Calls_for_exams; extern const char *Txt_Exams; extern const char *Txt_Games; extern const char *Txt_Rubrics; extern const char *Txt_Documents; extern const char *Txt_Marks_area; extern const char *Txt_Control_of_class_attendance; extern const char *Txt_Course_forum; extern const char *Txt_Surveys; static void (*GetTitle[Rsc_NUM_TYPES]) (long Cod,char *Title,size_t TitleSize) = { [Rsc_NONE ] = NULL, [Rsc_ASSIGNMENT ] = Asg_DB_GetAssignmentTitleByCod, [Rsc_PROJECT ] = Prj_DB_GetProjectTitle, [Rsc_CALL_FOR_EXAM ] = CfeRsc_GetTitleFromExaCod, [Rsc_EXAM ] = Exa_DB_GetExamTitle, [Rsc_GAME ] = Gam_DB_GetGameTitle, [Rsc_RUBRIC ] = Rub_DB_GetRubricTitle, [Rsc_DOCUMENT ] = BrwRsc_GetTitleFromFilCod, [Rsc_MARKS ] = BrwRsc_GetTitleFromFilCod, [Rsc_ATTENDANCE_EVENT] = Att_DB_GetEventTitle, [Rsc_FORUM_THREAD ] = For_DB_GetThreadTitle, [Rsc_SURVEY ] = Svy_DB_GetSurveyTitle, }; const char *GenericTitle[Rsc_NUM_TYPES] = { [Rsc_NONE ] = NULL, [Rsc_ASSIGNMENT ] = Txt_Assignments, [Rsc_PROJECT ] = Txt_Projects, [Rsc_CALL_FOR_EXAM ] = Txt_Calls_for_exams, [Rsc_EXAM ] = Txt_Exams, [Rsc_GAME ] = Txt_Games, [Rsc_RUBRIC ] = Txt_Rubrics, [Rsc_DOCUMENT ] = Txt_Documents, [Rsc_MARKS ] = Txt_Marks_area, [Rsc_ATTENDANCE_EVENT] = Txt_Control_of_class_attendance, [Rsc_FORUM_THREAD ] = Txt_Course_forum, [Rsc_SURVEY ] = Txt_Surveys, }; /***** Reset title *****/ Title[0] = '\0'; /***** Get title *****/ if (Link->Type != Rsc_NONE) { if (Link->Cod > 0) { if (GetTitle[Link->Type]) GetTitle[Link->Type] (Link->Cod,Title,Rsc_MAX_BYTES_RESOURCE_TITLE); else Ale_ShowAlert (Ale_ERROR,"Not implemented!"); } else { if (GenericTitle[Link->Type]) Str_Copy (Title,GenericTitle[Link->Type],Rsc_MAX_BYTES_RESOURCE_TITLE); else Ale_ShowAlert (Ale_ERROR,"Not implemented!"); } } } /*****************************************************************************/ /********************** Get resource data from clipboard *********************/ /*****************************************************************************/ void Rsc_GetLinkDataFromRow (MYSQL_RES *mysql_res,struct Rsc_Link *Link) { MYSQL_ROW row; /***** Get row *****/ row = mysql_fetch_row (mysql_res); /* Type row[0] Cod row[1] */ /***** Get type (row[0]) *****/ Link->Type = Rsc_GetTypeFromString (row[0]); /***** Get code (row[1]) *****/ Link->Cod = Str_ConvertStrCodToLongCod (row[1]); } /*****************************************************************************/ /********************** Convert from string to type **************************/ /*****************************************************************************/ Rsc_Type_t Rsc_GetTypeFromString (const char *Str) { Rsc_Type_t Type; /***** Compare string with all string types *****/ for (Type = (Rsc_Type_t) 0; Type <= (Rsc_Type_t) (Rsc_NUM_TYPES - 1); Type++) if (!strcmp (Rsc_ResourceTypesDB[Type],Str)) return Type; return Rsc_NONE; } /*****************************************************************************/ /********************** Get resource data from clipboard *********************/ /*****************************************************************************/ bool Rsc_GetParLink (struct Rsc_Link *Link) { char TypeCod[3 + 1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1]; char TypeStr[3 + 1]; long Cod; /***** Get link type and code *****/ Par_GetParText ("Link",TypeCod,sizeof (TypeCod) - 1); if (sscanf (TypeCod,"%3s_%ld",TypeStr,&Cod) == 2) { /* Correct link found */ Link->Type = Rsc_GetTypeFromString (TypeStr); Link->Cod = Cod; return true; } /* No link found */ Link->Type = Rsc_NONE; Link->Cod = -1L; return false; } /*****************************************************************************/ /************************** Check if I can get link **************************/ /*****************************************************************************/ Usr_Can_t Rsc_CheckIfICanGetLink (void) { static Usr_Can_t ICanGetLink[Rol_NUM_ROLES] = { [Rol_TCH ] = Usr_CAN, [Rol_SYS_ADM] = Usr_CAN, }; return ICanGetLink[Gbl.Usrs.Me.Role.Logged]; }