// swad_institution.c: institutions /* 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 ***********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // For boolean type #include // For NULL #include // For asprintf #include // For free #include "swad_action_list.h" #include "swad_alert.h" #include "swad_box.h" #include "swad_center_database.h" #include "swad_database.h" #include "swad_department_database.h" #include "swad_error.h" #include "swad_figure_cache.h" #include "swad_form.h" #include "swad_global.h" #include "swad_help.h" #include "swad_hierarchy.h" #include "swad_hierarchy_config.h" #include "swad_hierarchy_type.h" #include "swad_HTML.h" #include "swad_institution.h" #include "swad_institution_database.h" #include "swad_logo.h" #include "swad_parameter.h" #include "swad_place.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void InsCfg_Configuration (Vie_ViewType_t ViewType); static void InsCfg_PutIconsToPrintAndUpload (__attribute__((unused)) void *Args); static void InsCfg_Map (void); static void InsCfg_Country (Vie_ViewType_t ViewType,Frm_PutForm_t PutForm); static void InsCfg_NumUsrs (void); static void InsCfg_NumDegs (void); static void InsCfg_NumCrss (void); static void InsCfg_NumDpts (void); /*****************************************************************************/ /*************** Show information of the current institution *****************/ /*****************************************************************************/ void InsCfg_ShowConfiguration (void) { InsCfg_Configuration (Vie_VIEW); /***** Show help to enrol me *****/ Hlp_ShowHelpWhatWouldYouLikeToDo (); } /*****************************************************************************/ /*************** Print information of the current institution ****************/ /*****************************************************************************/ void InsCfg_PrintConfiguration (void) { InsCfg_Configuration (Vie_PRINT); } /*****************************************************************************/ /***************** Information of the current institution ********************/ /*****************************************************************************/ static void InsCfg_Configuration (Vie_ViewType_t ViewType) { extern const char *Hlp_INSTITUTION_Information; Hie_PutLink_t PutLink; Frm_PutForm_t PutFormCty; Frm_PutForm_t PutFormName; Frm_PutForm_t PutFormWWW; unsigned NumCtrs; unsigned NumCtrsWithMap; /***** Trivial check *****/ if (Gbl.Hierarchy.Node[Hie_INS].HieCod <= 0) // No institution selected return; /***** Initializations *****/ PutLink = (ViewType == Vie_VIEW && Gbl.Hierarchy.Node[Hie_INS].WWW[0]) ? Hie_PUT_LINK : Hie_DONT_PUT_LINK; PutFormCty = PutFormName = (ViewType == Vie_VIEW && Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) ? Frm_PUT_FORM : Frm_DONT_PUT_FORM; PutFormWWW = (ViewType == Vie_VIEW && Gbl.Usrs.Me.Role.Logged >= Rol_INS_ADM) ? Frm_PUT_FORM : Frm_DONT_PUT_FORM; /***** Begin box *****/ Box_BoxBegin (NULL, ViewType == Vie_VIEW ? InsCfg_PutIconsToPrintAndUpload : NULL,NULL, ViewType == Vie_VIEW ? Hlp_INSTITUTION_Information : NULL,Box_NOT_CLOSABLE); /***** Title *****/ HieCfg_Title (PutLink,Hie_INS); /**************************** Left part ***********************************/ HTM_DIV_Begin ("class=\"HIE_CFG_LEFT\""); /***** Begin table *****/ HTM_TABLE_BeginPadding (2); /***** Country *****/ InsCfg_Country (ViewType,PutFormCty); /***** Institution name *****/ HieCfg_Name (PutFormName,Hie_INS,Nam_FULL_NAME); HieCfg_Name (PutFormName,Hie_INS,Nam_SHRT_NAME); /***** Institution WWW *****/ HieCfg_WWW (ViewType,PutFormWWW,ActChgInsWWWCfg,Gbl.Hierarchy.Node[Hie_INS].WWW); /***** Shortcut to the institution *****/ HieCfg_Shortcut (ViewType,ParCod_Ins,Gbl.Hierarchy.Node[Hie_INS].HieCod); NumCtrsWithMap = Ctr_GetCachedNumCtrsWithMapInIns (Gbl.Hierarchy.Node[Hie_INS].HieCod); switch (ViewType) { case Vie_VIEW: NumCtrs = Hie_GetCachedNumNodesInHieLvl (Hie_CTR, // Number of centers... Hie_INS, // ...in institution Gbl.Hierarchy.Node[Hie_INS].HieCod); /***** Number of users who claim to belong to this institution, number of centers, number of degrees, number of courses, number of departments *****/ InsCfg_NumUsrs (); HieCfg_NumCtrs (NumCtrs,Frm_PUT_FORM); HieCfg_NumCtrsWithMap (NumCtrs,NumCtrsWithMap); InsCfg_NumDegs (); InsCfg_NumCrss (); InsCfg_NumDpts (); /***** Number of users in courses of this institution *****/ HieCfg_NumUsrsInCrss (Hie_INS,Gbl.Hierarchy.Node[Hie_INS].HieCod,Rol_TCH); HieCfg_NumUsrsInCrss (Hie_INS,Gbl.Hierarchy.Node[Hie_INS].HieCod,Rol_NET); HieCfg_NumUsrsInCrss (Hie_INS,Gbl.Hierarchy.Node[Hie_INS].HieCod,Rol_STD); HieCfg_NumUsrsInCrss (Hie_INS,Gbl.Hierarchy.Node[Hie_INS].HieCod,Rol_UNK); break; case Vie_PRINT: /***** QR code with link to the institution *****/ HieCfg_QR (ParCod_Ins,Gbl.Hierarchy.Node[Hie_INS].HieCod); break; default: Err_WrongTypeExit (); break; } /***** End table *****/ HTM_TABLE_End (); /***** End of left part *****/ HTM_DIV_End (); /**************************** Right part **********************************/ if (NumCtrsWithMap) { HTM_DIV_Begin ("class=\"HIE_CFG_RIGHT\""); /***** Institution map *****/ InsCfg_Map (); HTM_DIV_End (); } /***** End box *****/ Box_BoxEnd (); } /*****************************************************************************/ /********* Put contextual icons in configuration of an institution ***********/ /*****************************************************************************/ static void InsCfg_PutIconsToPrintAndUpload (__attribute__((unused)) void *Args) { /***** Icon to print info about institution *****/ Ico_PutContextualIconToPrint (ActPrnInsInf,NULL,NULL); if (Gbl.Usrs.Me.Role.Logged >= Rol_INS_ADM) /***** Icon to upload logo of institution *****/ Lgo_PutIconToChangeLogo (Hie_INS); /***** Put icon to view places *****/ Plc_PutIconToViewPlaces (); } /*****************************************************************************/ /*************************** Draw institution map ****************************/ /*****************************************************************************/ #define InsCfg_MAP_CONTAINER_ID "ins_mapid" static void InsCfg_Map (void) { extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node); MYSQL_RES *mysql_res; unsigned Zoom; unsigned NumCtrs; unsigned NumCtr; struct Hie_Node Ctr; struct Map_Coordinates Coord; struct Map_Coordinates InsAvgCoord; /***** Leaflet CSS *****/ Map_LeafletCSS (); /***** Leaflet script *****/ Map_LeafletScript (); /***** Container for the map *****/ HTM_DIV_Begin ("id=\"%s\"",InsCfg_MAP_CONTAINER_ID); HTM_DIV_End (); /***** Script to draw the map *****/ HTM_SCRIPT_Begin (NULL,NULL); /* Let's create a map with pretty Mapbox Streets tiles */ Ctr_DB_GetAvgCoordAndZoomInCurrentIns (&InsAvgCoord,&Zoom); Map_CreateMap (InsCfg_MAP_CONTAINER_ID,&InsAvgCoord,Zoom); /* Add Mapbox Streets tile layer to our map */ Map_AddTileLayer (); /* Get centers with coordinates */ NumCtrs = Ctr_DB_GetCtrsWithCoordsInCurrentIns (&mysql_res); /* Add a marker and a popup for each center */ for (NumCtr = 0; NumCtr < NumCtrs; NumCtr++) { /* Get next center */ Ctr.HieCod = DB_GetNextCode (mysql_res); /* Get data of center */ Hie_GetDataByCod[Hie_CTR] (&Ctr); /* Get coordinates of center */ Ctr_GetCoordByCod (Ctr.HieCod,&Coord); /* Add marker */ Map_AddMarker (&Coord); /* Add popup */ Map_AddPopup (Ctr.ShrtName,Gbl.Hierarchy.Node[Hie_INS].ShrtName, false); // Closed } /* Free structure that stores the query result */ DB_FreeMySQLResult (&mysql_res); HTM_SCRIPT_End (); } /*****************************************************************************/ /***************** Show country in institution configuration *****************/ /*****************************************************************************/ static void InsCfg_Country (Vie_ViewType_t ViewType,Frm_PutForm_t PutForm) { extern const char *Par_CodeStr[Par_NUM_PAR_COD]; extern const char *Txt_HIERARCHY_SINGUL_Abc[Hie_NUM_LEVELS]; unsigned NumCty; const struct Hie_Node *Cty; const char *Id[Frm_NUM_PUT_FORM] = { [Frm_DONT_PUT_FORM] = NULL, [Frm_PUT_FORM ] = Par_CodeStr[ParCod_OthCty], }; /***** Get list of countries *****/ Cty_GetBasicListOfCountries (); /***** Country *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",Id[PutForm],Txt_HIERARCHY_SINGUL_Abc[Hie_CTY]); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LT DAT_%s\"",The_GetSuffix ()); switch (PutForm) { case Frm_DONT_PUT_FORM: // I can not move institution to another country if (ViewType == Vie_VIEW) { Frm_BeginFormGoTo (ActSeeCtyInf); ParCod_PutPar (ParCod_Cty,Gbl.Hierarchy.Node[Hie_CTY].HieCod); HTM_BUTTON_Submit_Begin (Str_BuildGoToTitle (Gbl.Hierarchy.Node[Hie_CTY].FullName), "class=\"BT_LINK\""); Str_FreeGoToTitle (); } Cty_DrawCountryMap (&Gbl.Hierarchy.Node[Hie_CTY],"COUNTRY_MAP_TINY"); HTM_NBSP (); HTM_Txt (Gbl.Hierarchy.Node[Hie_CTY].FullName); if (ViewType == Vie_VIEW) { HTM_BUTTON_End (); Frm_EndForm (); } break; case Frm_PUT_FORM: /* Put form to select country */ Frm_BeginForm (ActChgInsCtyCfg); HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,NULL, "id=\"OthCtyCod\" name=\"OthCtyCod\"" " class=\"Frm_C2_INPUT INPUT_%s\"", The_GetSuffix ()); for (NumCty = 0; NumCty < Gbl.Hierarchy.List[Hie_SYS].Num; NumCty++) { Cty = &Gbl.Hierarchy.List[Hie_SYS].Lst[NumCty]; HTM_OPTION (HTM_Type_LONG,&Cty->HieCod, Cty->HieCod == Gbl.Hierarchy.Node[Hie_CTY].HieCod ? HTM_OPTION_SELECTED : HTM_OPTION_UNSELECTED, HTM_OPTION_ENABLED, "%s",Cty->FullName); } HTM_SELECT_End (); Frm_EndForm (); break; } HTM_TD_End (); HTM_TR_End (); // Do not free list of countries here, because it can be reused } /*****************************************************************************/ /** Show number of users who claim to belong to instit. in instit. config. ***/ /*****************************************************************************/ static void InsCfg_NumUsrs (void) { extern const char *Txt_Users_of_the_institution; /***** Number of users *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",NULL,Txt_Users_of_the_institution); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); HTM_Unsigned (Hie_GetCachedNumUsrsWhoClaimToBelongTo (Hie_INS, &Gbl.Hierarchy.Node[Hie_INS])); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /*********** Show number of degrees in institution configuration *************/ /*****************************************************************************/ static void InsCfg_NumDegs (void) { extern const char *Txt_HIERARCHY_PLURAL_Abc[Hie_NUM_LEVELS]; /***** Number of degrees *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",NULL,Txt_HIERARCHY_PLURAL_Abc[Hie_DEG]); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); HTM_Unsigned (Hie_GetCachedNumNodesInHieLvl (Hie_DEG, // Number of degrees... Hie_INS, // ...in institution Gbl.Hierarchy.Node[Hie_INS].HieCod)); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /************ Show number of courses in institution configuration ************/ /*****************************************************************************/ static void InsCfg_NumCrss (void) { extern const char *Txt_HIERARCHY_PLURAL_Abc[Hie_NUM_LEVELS]; /***** Number of courses *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",NULL,Txt_HIERARCHY_PLURAL_Abc[Hie_CRS]); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); HTM_Unsigned (Hie_GetCachedNumNodesInHieLvl (Hie_CRS, // Number of courses... Hie_INS, // ...in institution Gbl.Hierarchy.Node[Hie_INS].HieCod)); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /********** Show number of departments in institution configuration **********/ /*****************************************************************************/ static void InsCfg_NumDpts (void) { extern const char *Txt_Departments; /***** Number of departments *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",NULL,Txt_Departments); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); HTM_Unsigned (Dpt_GetNumDptsInIns (Gbl.Hierarchy.Node[Hie_INS].HieCod)); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /******** Show a form for sending a logo of the current institution **********/ /*****************************************************************************/ void InsCfg_ReqLogo (void) { Lgo_RequestLogo (Hie_INS); } /*****************************************************************************/ /************** Receive the logo of the current institution ******************/ /*****************************************************************************/ void InsCfg_ReceiveLogo (void) { Lgo_ReceiveLogo (Hie_INS); } /*****************************************************************************/ /*************** Remove the logo of the current institution ******************/ /*****************************************************************************/ void InsCfg_RemoveLogo (void) { Lgo_RemoveLogo (Hie_INS); } /*****************************************************************************/ /******************* Change the country of a institution *********************/ /*****************************************************************************/ void InsCfg_ChangeInsCty (void) { extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node); extern const char *Txt_The_country_of_the_institution_X_has_changed_to_Y; struct Hie_Node NewCty; const char *Names[Nam_NUM_SHRT_FULL_NAMES]; /***** Get the new country code for the institution *****/ NewCty.HieCod = ParCod_GetAndCheckPar (ParCod_OthCty); /***** Check if country has changed *****/ if (NewCty.HieCod != Gbl.Hierarchy.Node[Hie_INS].PrtCod) { /***** Get data of the country from database *****/ Hie_GetDataByCod[Hie_CTY] (&NewCty); /***** Check if it already exists an institution with the same name in the new country *****/ Names[Nam_SHRT_NAME] = Gbl.Hierarchy.Node[Hie_INS].ShrtName; Names[Nam_FULL_NAME] = Gbl.Hierarchy.Node[Hie_INS].FullName; if (!Nam_CheckIfNameExists (Ins_DB_CheckIfInsNameExistsInCty, Names, -1L, NewCty.HieCod, 0)) // Unused { /***** Update the table changing the country of the institution *****/ Ins_DB_UpdateInsCty (Gbl.Hierarchy.Node[Hie_INS].HieCod,NewCty.HieCod); Gbl.Hierarchy.Node[Hie_INS].PrtCod = Gbl.Hierarchy.Node[Hie_CTY].HieCod = NewCty.HieCod; /***** Initialize again current course, degree, center... *****/ Hie_InitHierarchy (); /***** Write message to show the change made *****/ Ale_CreateAlert (Ale_SUCCESS,NULL, Txt_The_country_of_the_institution_X_has_changed_to_Y, Names[Nam_FULL_NAME],NewCty.FullName); } } } /*****************************************************************************/ /************ Change the name of an institution in configuration *************/ /*****************************************************************************/ void InsCfg_RenameInsShort (void) { /***** Rename institution *****/ Ins_RenameInstitution (&Gbl.Hierarchy.Node[Hie_INS],Nam_SHRT_NAME); } void InsCfg_RenameInsFull (void) { /***** Rename institution *****/ Ins_RenameInstitution (&Gbl.Hierarchy.Node[Hie_INS],Nam_FULL_NAME); } /*****************************************************************************/ /********************** Change the URL of a institution **********************/ /*****************************************************************************/ void InsCfg_ChangeInsWWW (void) { extern const char *Txt_The_new_web_address_is_X; char NewWWW[Cns_MAX_BYTES_WWW + 1]; /***** Get parameters from form *****/ /* Get the new WWW for the institution */ Par_GetParText ("WWW",NewWWW,Cns_MAX_BYTES_WWW); /***** Check if new WWW is empty *****/ if (NewWWW[0]) { /***** Update database changing old WWW by new WWW *****/ Ins_DB_UpdateInsWWW (Gbl.Hierarchy.Node[Hie_INS].HieCod,NewWWW); Str_Copy (Gbl.Hierarchy.Node[Hie_INS].WWW,NewWWW, sizeof (Gbl.Hierarchy.Node[Hie_INS].WWW) - 1); /***** Write message to show the change made *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_The_new_web_address_is_X, NewWWW); } else Ale_ShowAlertYouCanNotLeaveFieldEmpty (); /***** Show the form again *****/ InsCfg_ShowConfiguration (); } /*****************************************************************************/ /*** Show msg. of success after changing an institution in instit. config. ***/ /*****************************************************************************/ void InsCfg_ContEditAfterChgIns (void) { /***** Write success / warning message *****/ Ale_ShowAlerts (NULL); /***** Show the form again *****/ InsCfg_ShowConfiguration (); }