// swad_center_config.c: configuration of current center /* 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 // For string functions #include // For unlink #include "swad_action_list.h" #include "swad_alert.h" #include "swad_box.h" #include "swad_center.h" #include "swad_center_database.h" #include "swad_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_logo.h" #include "swad_parameter.h" #include "swad_place.h" #include "swad_www.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ // Center photo will be saved with: // - maximum width of Ctr_PHOTO_SAVED_MAX_HEIGHT // - maximum height of Ctr_PHOTO_SAVED_MAX_HEIGHT // - maintaining the original aspect ratio (aspect ratio recommended: 3:2) #define Ctr_RECOMMENDED_ASPECT_RATIO "3:2" #define Ctr_PHOTO_SAVED_MAX_WIDTH 768 #define Ctr_PHOTO_SAVED_MAX_HEIGHT 768 #define Ctr_PHOTO_SAVED_QUALITY 90 // 1 to 100 /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void CtrCfg_Configuration (Vie_ViewType_t ViewType); static void CtrCfg_PutIconsCtrConfig (__attribute__((unused)) void *Args); static void CtrCfg_PutIconToChangePhoto (void); static void CtrCfg_Map (const struct Map_Coordinates *Coord); static void CtrCfg_Latitude (double Latitude); static void CtrCfg_Longitude (double Longitude); static void CtrCfg_Altitude (double Altitude); static void CtrCfg_Photo (Vie_ViewType_t ViewType, Frm_PutForm_t PutForm,Hie_PutLink_t PutLink, const char PathPhoto[PATH_MAX + 1]); static void CtrCfg_GetPhotoAttr (long CtrCod,char **PhotoAttribution); static void CtrCfg_FreePhotoAttr (char **PhotoAttribution); static void CtrCfg_Institution (Vie_ViewType_t ViewType,Frm_PutForm_t PutForm); static void CtrCfg_Place (Frm_PutForm_t PutForm); static void CtrCfg_NumUsrs (void); static void CtrCfg_NumDegs (void); static void CtrCfg_NumCrss (void); /*****************************************************************************/ /****************** Show information of the current center *******************/ /*****************************************************************************/ void CtrCfg_ShowConfiguration (void) { CtrCfg_Configuration (Vie_VIEW); /***** Show help to enrol me *****/ Hlp_ShowHelpWhatWouldYouLikeToDo (); } /*****************************************************************************/ /****************** Print information of the current center ******************/ /*****************************************************************************/ void CtrCfg_PrintConfiguration (void) { CtrCfg_Configuration (Vie_PRINT); } /*****************************************************************************/ /******************* Information of the current center ***********************/ /*****************************************************************************/ static void CtrCfg_Configuration (Vie_ViewType_t ViewType) { extern const char *Hlp_CENTER_Information; struct Map_Coordinates Coord; Hie_PutLink_t PutLink; Frm_PutForm_t PutFormIns; Frm_PutForm_t PutFormName; Frm_PutForm_t PutFormPlc; Frm_PutForm_t PutFormCoor; Frm_PutForm_t PutFormWWW; Frm_PutForm_t PutFormPhoto; bool MapIsAvailable; char PathPhoto[PATH_MAX + 1]; bool PhotoExists; /***** Trivial check *****/ if (Gbl.Hierarchy.Node[Hie_CTR].HieCod <= 0) // No center selected return; /***** Get coordinates of center *****/ Ctr_GetCoordByCod (Gbl.Hierarchy.Node[Hie_CTR].HieCod,&Coord); /***** Initializations *****/ PutLink = (ViewType == Vie_VIEW && Gbl.Hierarchy.Node[Hie_CTR].WWW[0]) ? Hie_PUT_LINK : Hie_DONT_PUT_LINK; PutFormIns = (ViewType == Vie_VIEW && Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) ? Frm_PUT_FORM : Frm_DONT_PUT_FORM; PutFormName = (ViewType == Vie_VIEW && Gbl.Usrs.Me.Role.Logged >= Rol_INS_ADM) ? Frm_PUT_FORM : Frm_DONT_PUT_FORM; PutFormPlc = PutFormCoor = PutFormWWW = PutFormPhoto = (ViewType == Vie_VIEW && Gbl.Usrs.Me.Role.Logged >= Rol_CTR_ADM) ? Frm_PUT_FORM : Frm_DONT_PUT_FORM; /***** Begin box *****/ Box_BoxBegin (NULL, ViewType == Vie_VIEW ? CtrCfg_PutIconsCtrConfig : NULL,NULL, ViewType == Vie_VIEW ? Hlp_CENTER_Information : NULL,Box_NOT_CLOSABLE); /***** Title *****/ HieCfg_Title (PutLink,Hie_CTR); /**************************** Left part ***********************************/ HTM_DIV_Begin ("class=\"HIE_CFG_LEFT\""); /***** Begin table *****/ HTM_TABLE_BeginPadding (2); /***** Institution *****/ CtrCfg_Institution (ViewType,PutFormIns); /***** Center name *****/ HieCfg_Name (PutFormName,Hie_CTR,Nam_FULL_NAME); HieCfg_Name (PutFormName,Hie_CTR,Nam_SHRT_NAME); /***** Place *****/ CtrCfg_Place (PutFormPlc); /***** Coordinates *****/ if (PutFormCoor == Frm_PUT_FORM) { CtrCfg_Latitude (Coord.Latitude ); CtrCfg_Longitude (Coord.Longitude); CtrCfg_Altitude (Coord.Altitude ); } /***** Center WWW *****/ HieCfg_WWW (ViewType,PutFormWWW,ActChgCtrWWWCfg,Gbl.Hierarchy.Node[Hie_CTR].WWW); /***** Shortcut to the center *****/ HieCfg_Shortcut (ViewType,ParCod_Ctr,Gbl.Hierarchy.Node[Hie_CTR].HieCod); switch (ViewType) { case Vie_VIEW: /***** Number of users who claim to belong to this center, number of degrees, number of courses *****/ CtrCfg_NumUsrs (); CtrCfg_NumDegs (); CtrCfg_NumCrss (); /***** Number of users in courses of this center *****/ HieCfg_NumUsrsInCrss (Hie_CTR,Gbl.Hierarchy.Node[Hie_CTR].HieCod,Rol_TCH); HieCfg_NumUsrsInCrss (Hie_CTR,Gbl.Hierarchy.Node[Hie_CTR].HieCod,Rol_NET); HieCfg_NumUsrsInCrss (Hie_CTR,Gbl.Hierarchy.Node[Hie_CTR].HieCod,Rol_STD); HieCfg_NumUsrsInCrss (Hie_CTR,Gbl.Hierarchy.Node[Hie_CTR].HieCod,Rol_UNK); break; case Vie_PRINT: /***** QR code with link to the center *****/ HieCfg_QR (ParCod_Ctr,Gbl.Hierarchy.Node[Hie_CTR].HieCod); break; default: Err_WrongTypeExit (); break; } /***** End table *****/ HTM_TABLE_End (); /***** End of left part *****/ HTM_DIV_End (); /**************************** Right part **********************************/ /***** Check map *****/ MapIsAvailable = Map_CheckIfCoordAreAvailable (&Coord); /***** Check photo *****/ snprintf (PathPhoto,sizeof (PathPhoto),"%s/%02u/%u/%u.jpg", Cfg_PATH_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Node[Hie_CTR].HieCod % 100), (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod, (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod); PhotoExists = Fil_CheckIfPathExists (PathPhoto); if (MapIsAvailable || PhotoExists) { HTM_DIV_Begin ("class=\"HIE_CFG_RIGHT\""); /***** Center map *****/ if (MapIsAvailable) CtrCfg_Map (&Coord); /***** Center photo *****/ if (PhotoExists) CtrCfg_Photo (ViewType,PutFormPhoto,PutLink,PathPhoto); HTM_DIV_End (); } /***** End box *****/ Box_BoxEnd (); } /*****************************************************************************/ /************ Put contextual icons in configuration of a center **************/ /*****************************************************************************/ static void CtrCfg_PutIconsCtrConfig (__attribute__((unused)) void *Args) { /***** Put icon to print info about center *****/ Ico_PutContextualIconToPrint (ActPrnCtrInf,NULL,NULL); /***** Put icon to view places *****/ Plc_PutIconToViewPlaces (); if (Gbl.Usrs.Me.Role.Logged >= Rol_CTR_ADM) // Only center admins, institution admins and system admins // have permission to upload logo and photo of the center { /***** Put icon to upload logo of center *****/ Lgo_PutIconToChangeLogo (Hie_CTR); /***** Put icon to upload photo of center *****/ CtrCfg_PutIconToChangePhoto (); } } /*****************************************************************************/ /************* Put contextual icons to upload photo of center ****************/ /*****************************************************************************/ static void CtrCfg_PutIconToChangePhoto (void) { Lay_PutContextualLinkOnlyIcon (ActReqCtrPho,NULL, NULL,NULL, "camera.svg",Ico_BLACK); } /*****************************************************************************/ /****************************** Draw center map ******************************/ /*****************************************************************************/ #define CtrCfg_MAP_CONTAINER_ID "ctr_mapid" static void CtrCfg_Map (const struct Map_Coordinates *Coord) { /***** Leaflet CSS *****/ Map_LeafletCSS (); /***** Leaflet script *****/ Map_LeafletScript (); /***** Container for the map *****/ HTM_DIV_Begin ("id=\"%s\"",CtrCfg_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 */ Map_CreateMap (CtrCfg_MAP_CONTAINER_ID,Coord,16); /* Add Mapbox Streets tile layer to our map */ Map_AddTileLayer (); /* Add marker */ Map_AddMarker (Coord); /* Add popup */ Map_AddPopup (Gbl.Hierarchy.Node[Hie_CTR].ShrtName, Gbl.Hierarchy.Node[Hie_INS].ShrtName, CloOpe_OPEN); HTM_SCRIPT_End (); } /*****************************************************************************/ /************************** Edit center coordinates **************************/ /*****************************************************************************/ static void CtrCfg_Latitude (double Latitude) { extern const char *Txt_Latitude; /***** Latitude *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT","Latitude",Txt_Latitude); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB\""); Frm_BeginForm (ActChgCtrLatCfg); HTM_INPUT_FLOAT ("Latitude", -90.0, // South Pole 90.0, // North Pole 0.0, // step="any" Latitude, HTM_SUBMIT_ON_CHANGE,false, "class=\"Frm_C2_INPUT INPUT_%s\"" " required=\"required\"", The_GetSuffix ()); Frm_EndForm (); HTM_TD_End (); HTM_TR_End (); } static void CtrCfg_Longitude (double Longitude) { extern const char *Txt_Longitude; /***** Longitude *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT","Longitude",Txt_Longitude); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB\""); Frm_BeginForm (ActChgCtrLgtCfg); HTM_INPUT_FLOAT ("Longitude", -180.0, // West 180.0, // East 0.0, // step="any" Longitude, HTM_SUBMIT_ON_CHANGE,false, "class=\"Frm_C2_INPUT INPUT_%s\"" " required=\"required\"", The_GetSuffix ()); Frm_EndForm (); HTM_TD_End (); HTM_TR_End (); } static void CtrCfg_Altitude (double Altitude) { extern const char *Txt_Altitude; /***** Altitude *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT","Altitude",Txt_Altitude); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB\""); Frm_BeginForm (ActChgCtrAltCfg); HTM_INPUT_FLOAT ("Altitude", -413.0, // Dead Sea shore 8848.0, // Mount Everest 0.0, // step="any" Altitude, HTM_SUBMIT_ON_CHANGE,false, "class=\"Frm_C2_INPUT INPUT_%s\"" " required=\"required\"", The_GetSuffix ()); Frm_EndForm (); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /***************************** Draw center photo *****************************/ /*****************************************************************************/ static void CtrCfg_Photo (Vie_ViewType_t ViewType, Frm_PutForm_t PutForm,Hie_PutLink_t PutLink, const char PathPhoto[PATH_MAX + 1]) { char *PhotoAttribution = NULL; char *URL; char *Icon; /***** Trivial checks *****/ if (!PathPhoto) return; if (!PathPhoto[0]) return; /***** Get photo attribution *****/ CtrCfg_GetPhotoAttr (Gbl.Hierarchy.Node[Hie_CTR].HieCod,&PhotoAttribution); /***** Photo image *****/ HTM_DIV_Begin ("class=\"CM\""); if (PutLink == Hie_PUT_LINK) HTM_A_Begin ("href=\"%s\" target=\"_blank\"", Gbl.Hierarchy.Node[Hie_CTR].WWW); if (asprintf (&URL,"%s/%02u/%u", Cfg_URL_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Node[Hie_CTR].HieCod % 100), (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod) < 0) Err_NotEnoughMemoryExit (); if (asprintf (&Icon,"%u.jpg", (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod) < 0) Err_NotEnoughMemoryExit (); HTM_IMG (URL,Icon,Gbl.Hierarchy.Node[Hie_CTR].FullName, "class=\"%s\"",ViewType == Vie_VIEW ? "CENTER_PHOTO_SHOW CENTER_PHOTO_WIDTH" : "CENTER_PHOTO_PRINT CENTER_PHOTO_WIDTH"); free (Icon); free (URL); if (PutLink == Hie_PUT_LINK) HTM_A_End (); HTM_DIV_End (); /****** Photo attribution ******/ switch (PutForm) { case Frm_DONT_PUT_FORM: if (PhotoAttribution) { HTM_DIV_Begin ("class=\"ATTRIBUTION\""); HTM_Txt (PhotoAttribution); HTM_DIV_End (); } break; case Frm_PUT_FORM: HTM_DIV_Begin ("class=\"CM\""); Frm_BeginForm (ActChgCtrPhoAtt); HTM_TEXTAREA_Begin ("id=\"AttributionArea\" name=\"Attribution\" rows=\"3\"" " onchange=\"this.form.submit();return false;\""); if (PhotoAttribution) HTM_Txt (PhotoAttribution); HTM_TEXTAREA_End (); Frm_EndForm (); HTM_DIV_End (); break; } /****** Free memory used for photo attribution ******/ CtrCfg_FreePhotoAttr (&PhotoAttribution); } /*****************************************************************************/ /******************* Get photo attribution from database *********************/ /*****************************************************************************/ static void CtrCfg_GetPhotoAttr (long CtrCod,char **PhotoAttribution) { MYSQL_RES *mysql_res; MYSQL_ROW row; size_t Length; /***** Free possible former photo attribution *****/ CtrCfg_FreePhotoAttr (PhotoAttribution); /***** Get photo attribution from database *****/ if (Ctr_DB_GetPhotoAttribution (&mysql_res,CtrCod)) { /* Get row */ row = mysql_fetch_row (mysql_res); /* Get the attribution of the photo of the center (row[0]) */ if (row[0]) if (row[0][0]) { Length = strlen (row[0]); if (((*PhotoAttribution) = malloc (Length + 1)) == NULL) Err_NotEnoughMemoryExit (); Str_Copy (*PhotoAttribution,row[0],Length); } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /****************** Free memory used for photo attribution *******************/ /*****************************************************************************/ static void CtrCfg_FreePhotoAttr (char **PhotoAttribution) { if (*PhotoAttribution) { free (*PhotoAttribution); *PhotoAttribution = NULL; } } /*****************************************************************************/ /***************** Show institution in center configuration ******************/ /*****************************************************************************/ static void CtrCfg_Institution (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 NumIns; const struct Hie_Node *Ins; const char *Id[Frm_NUM_PUT_FORM] = { [Frm_DONT_PUT_FORM] = NULL, [Frm_PUT_FORM ] = Par_CodeStr[ParCod_OthIns], }; /***** Institution *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",Id[PutForm],Txt_HIERARCHY_SINGUL_Abc[Hie_INS]); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LT DAT_%s\"",The_GetSuffix ()); switch (PutForm) { case Frm_DONT_PUT_FORM: if (ViewType == Vie_VIEW) { Frm_BeginFormGoTo (ActSeeInsInf); ParCod_PutPar (ParCod_Ins,Gbl.Hierarchy.Node[Hie_INS].HieCod); HTM_BUTTON_Submit_Begin (Str_BuildGoToTitle (Gbl.Hierarchy.Node[Hie_INS].ShrtName), "class=\"LT BT_LINK\""); Str_FreeGoToTitle (); } Lgo_DrawLogo (Hie_INS,&Gbl.Hierarchy.Node[Hie_INS],"LM ICO20x20"); HTM_NBSP (); HTM_Txt (Gbl.Hierarchy.Node[Hie_INS].FullName); if (ViewType == Vie_VIEW) { HTM_BUTTON_End (); Frm_EndForm (); } break; case Frm_PUT_FORM: /* Get list of institutions of the current country */ Ins_GetBasicListOfInstitutions (Gbl.Hierarchy.Node[Hie_CTY].HieCod); /* Put form to select institution */ Frm_BeginForm (ActChgCtrInsCfg); HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,NULL, "id=\"OthInsCod\" name=\"OthInsCod\"" " class=\"Frm_C2_INPUT INPUT_%s\"", The_GetSuffix ()); for (NumIns = 0; NumIns < Gbl.Hierarchy.List[Hie_CTY].Num; NumIns++) { Ins = &Gbl.Hierarchy.List[Hie_CTY].Lst[NumIns]; HTM_OPTION (HTM_Type_LONG,&Ins->HieCod, Ins->HieCod == Gbl.Hierarchy.Node[Hie_INS].HieCod ? HTM_OPTION_SELECTED : HTM_OPTION_UNSELECTED, HTM_OPTION_ENABLED, "%s",Ins->ShrtName); } HTM_SELECT_End (); Frm_EndForm (); /* Free list of institutions */ Hie_FreeList (Hie_CTY); break; } HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /**************** Show center place in center configuration ******************/ /*****************************************************************************/ static void CtrCfg_Place (Frm_PutForm_t PutForm) { extern const char *Par_CodeStr[Par_NUM_PAR_COD]; extern const char *Txt_Place; extern const char *Txt_Another_place; struct Plc_Places Places; struct Plc_Place Plc; unsigned NumPlc; const char *Id[Frm_NUM_PUT_FORM] = { [Frm_DONT_PUT_FORM] = NULL, [Frm_PUT_FORM ] = Par_CodeStr[ParCod_Plc], }; /***** Reset places context *****/ Plc_ResetPlaces (&Places); /***** Place *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",Id[PutForm],Txt_Place); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); switch (PutForm) { case Frm_DONT_PUT_FORM: // I can not change center place /* Text with the place name */ Plc.PlcCod = Gbl.Hierarchy.Node[Hie_CTR].Specific.PlcCod; Plc_GetPlaceDataByCod (&Plc); HTM_Txt (Plc.FullName); break; case Frm_PUT_FORM: /* Get list of places of the current institution */ Places.SelectedOrder = Plc_ORDER_BY_PLACE; Plc_GetListPlaces (&Places); /* Put form to select place */ Frm_BeginForm (ActChgCtrPlcCfg); HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,NULL, "name=\"PlcCod\"" " class=\"Frm_C2_INPUT INPUT_%s\"", The_GetSuffix ()); HTM_OPTION (HTM_Type_STRING,"0", Gbl.Hierarchy.Node[Hie_CTR].Specific.PlcCod == 0 ? HTM_OPTION_SELECTED : HTM_OPTION_UNSELECTED, HTM_OPTION_ENABLED, "%s",Txt_Another_place); for (NumPlc = 0; NumPlc < Places.Num; NumPlc++) HTM_OPTION (HTM_Type_LONG,&Places.Lst[NumPlc].PlcCod, Places.Lst[NumPlc].PlcCod == Gbl.Hierarchy.Node[Hie_CTR].Specific.PlcCod ? HTM_OPTION_SELECTED : HTM_OPTION_UNSELECTED, HTM_OPTION_ENABLED, "%s",Places.Lst[NumPlc].ShrtName); HTM_SELECT_End (); Frm_EndForm (); /* Free list of places */ Plc_FreeListPlaces (&Places); break; } HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /*** Show number of users who claim to belong to center in center config. ****/ /*****************************************************************************/ static void CtrCfg_NumUsrs (void) { extern const char *Txt_Users_of_the_center; /***** Number of users *****/ HTM_TR_Begin (NULL); /* Label */ Frm_LabelColumn ("Frm_C1 RT",NULL,Txt_Users_of_the_center); /* Data */ HTM_TD_Begin ("class=\"Frm_C2 LB DAT_%s\"",The_GetSuffix ()); HTM_Unsigned (Hie_GetCachedNumUsrsWhoClaimToBelongTo (Hie_CTR, &Gbl.Hierarchy.Node[Hie_CTR])); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /************** Show number of degrees in center configuration ***************/ /*****************************************************************************/ static void CtrCfg_NumDegs (void) { extern const char *Txt_HIERARCHY_PLURAL_Abc[Hie_NUM_LEVELS]; extern const char *Txt_Degrees_of_CENTER_X; char *Title; /***** 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 ()); Frm_BeginFormGoTo (ActSeeDeg); ParCod_PutPar (ParCod_Ctr,Gbl.Hierarchy.Node[Hie_CTR].HieCod); if (asprintf (&Title,Txt_Degrees_of_CENTER_X, Gbl.Hierarchy.Node[Hie_CTR].ShrtName) < 0) Err_NotEnoughMemoryExit (); HTM_BUTTON_Submit_Begin (Title,"class=\"LB BT_LINK\""); free (Title); HTM_Unsigned (Hie_GetCachedNumNodesInHieLvl (Hie_DEG, // Number of degrees... Hie_CTR, // ...in center Gbl.Hierarchy.Node[Hie_CTR].HieCod)); HTM_BUTTON_End (); Frm_EndForm (); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /************** Show number of courses in center configuration ***************/ /*****************************************************************************/ static void CtrCfg_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_CTR, // ...in center Gbl.Hierarchy.Node[Hie_CTR].HieCod)); HTM_TD_End (); HTM_TR_End (); } /*****************************************************************************/ /*********** Show a form for sending a logo of the current center ************/ /*****************************************************************************/ void CtrCfg_ReqLogo (void) { Lgo_RequestLogo (Hie_CTR); } /*****************************************************************************/ /***************** Receive the logo of the current center ********************/ /*****************************************************************************/ void CtrCfg_ReceiveLogo (void) { Lgo_ReceiveLogo (Hie_CTR); } /*****************************************************************************/ /****************** Remove the logo of the current center ********************/ /*****************************************************************************/ void CtrCfg_RemoveLogo (void) { Lgo_RemoveLogo (Hie_CTR); } /*****************************************************************************/ /*********** Show a form for sending a photo of the current center ***********/ /*****************************************************************************/ void CtrCfg_ReqPhoto (void) { extern const char *Txt_Photo; extern const char *Txt_Recommended_aspect_ratio; extern const char *Txt_Recommended_resolution; extern const char *Txt_XxY_pixels_or_higher; extern const char *Txt_File_with_the_photo; /***** Begin form to upload photo *****/ Frm_BeginForm (ActRecCtrPho); /***** Begin box *****/ Box_BoxBegin (Txt_Photo,NULL,NULL,NULL,Box_NOT_CLOSABLE); /***** Write help message *****/ Ale_ShowAlert (Ale_INFO,"%s: %s
" "%s: %u×%u %s", Txt_Recommended_aspect_ratio, Ctr_RECOMMENDED_ASPECT_RATIO, Txt_Recommended_resolution, Ctr_PHOTO_SAVED_MAX_WIDTH, Ctr_PHOTO_SAVED_MAX_HEIGHT, Txt_XxY_pixels_or_higher); /***** Upload photo *****/ HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ()); HTM_TxtColonNBSP (Txt_File_with_the_photo); HTM_INPUT_FILE (Fil_NAME_OF_PARAM_FILENAME_ORG,"image/*", HTM_SUBMIT_ON_CHANGE, NULL); HTM_LABEL_End (); /***** End box *****/ Box_BoxEnd (); /***** End form *****/ Frm_EndForm (); } /*****************************************************************************/ /****************** Receive a photo of the current center ********************/ /*****************************************************************************/ void CtrCfg_ReceivePhoto (void) { extern const char *Txt_Wrong_file_type; char Path[PATH_MAX + 1]; struct Par_Param *Par; char FileNameImgSrc[PATH_MAX + 1]; char *PtrExtension; size_t LengthExtension; char MIMEType[Brw_MAX_BYTES_MIME_TYPE + 1]; char PathFileImgTmp[PATH_MAX + 1]; // Full name (including path and .jpg) of the destination temporary file char PathFileImg[PATH_MAX + 1]; // Full name (including path and .jpg) of the destination file bool WrongType = false; char Command[1024 + PATH_MAX * 2]; int ReturnCode; char ErrorMsg[256]; /***** Copy in disk the file received *****/ Par = Fil_StartReceptionOfFile (Fil_NAME_OF_PARAM_FILENAME_ORG, FileNameImgSrc,MIMEType); /* Check if the file type is image/ or application/octet-stream */ if (strncmp (MIMEType,"image/",strlen ("image/"))) if (strcmp (MIMEType,"application/octet-stream")) if (strcmp (MIMEType,"application/octetstream")) if (strcmp (MIMEType,"application/octet")) WrongType = true; if (WrongType) { Ale_ShowAlert (Ale_WARNING,Txt_Wrong_file_type); return; } /***** Create private directories if not exist *****/ /* Create private directory for images if it does not exist */ Fil_CreateDirIfNotExists (Cfg_PATH_MEDIA_PRIVATE); /* Create temporary private directory for images if it does not exist */ Fil_CreateDirIfNotExists (Cfg_PATH_MEDIA_TMP_PRIVATE); /* Get filename extension */ if ((PtrExtension = strrchr (FileNameImgSrc,(int) '.')) == NULL) { Ale_ShowAlert (Ale_WARNING,Txt_Wrong_file_type); return; } LengthExtension = strlen (PtrExtension); if (LengthExtension < Fil_MIN_BYTES_FILE_EXTENSION || LengthExtension > Fil_MAX_BYTES_FILE_EXTENSION) { Ale_ShowAlert (Ale_WARNING,Txt_Wrong_file_type); return; } /* End the reception of image in a temporary file */ snprintf (PathFileImgTmp,sizeof (PathFileImgTmp),"%s/%s.%s", Cfg_PATH_MEDIA_TMP_PRIVATE,Cry_GetUniqueNameEncrypted (),PtrExtension); if (!Fil_EndReceptionOfFile (PathFileImgTmp,Par)) { Ale_ShowAlert (Ale_WARNING,"Error copying file."); return; } /***** Creates public directories if not exist *****/ Fil_CreateDirIfNotExists (Cfg_PATH_CTR_PUBLIC); snprintf (Path,sizeof (Path),"%s/%02u", Cfg_PATH_CTR_PUBLIC,(unsigned) (Gbl.Hierarchy.Node[Hie_CTR].HieCod % 100)); Fil_CreateDirIfNotExists (Path); snprintf (Path,sizeof (Path),"%s/%02u/%u", Cfg_PATH_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Node[Hie_CTR].HieCod % 100), (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod); Fil_CreateDirIfNotExists (Path); /***** Convert temporary file to public JPEG file *****/ snprintf (PathFileImg,sizeof (PathFileImg),"%s/%02u/%u/%u.jpg", Cfg_PATH_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Node[Hie_CTR].HieCod % 100), (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod, (unsigned) Gbl.Hierarchy.Node[Hie_CTR].HieCod); /* Call to program that makes the conversion */ snprintf (Command,sizeof (Command), "convert %s -resize '%ux%u>' -quality %u %s", PathFileImgTmp, Ctr_PHOTO_SAVED_MAX_WIDTH, Ctr_PHOTO_SAVED_MAX_HEIGHT, Ctr_PHOTO_SAVED_QUALITY, PathFileImg); ReturnCode = system (Command); if (ReturnCode == -1) Err_ShowErrorAndExit ("Error when running command to process image."); /***** Write message depending on return code *****/ ReturnCode = WEXITSTATUS(ReturnCode); if (ReturnCode != 0) { snprintf (ErrorMsg,sizeof (ErrorMsg), "Image could not be processed successfully.
" "Error code returned by the program of processing: %d", ReturnCode); Err_ShowErrorAndExit (ErrorMsg); } /***** Remove temporary file *****/ unlink (PathFileImgTmp); /***** Show the center information again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /**************** Change the attribution of a center photo *******************/ /*****************************************************************************/ void CtrCfg_ChangeCtrPhotoAttr (void) { char NewPhotoAttribution[Med_MAX_BYTES_ATTRIBUTION + 1]; /***** Get parameters from form *****/ /* Get the new photo attribution for the center */ Par_GetParText ("Attribution",NewPhotoAttribution,Med_MAX_BYTES_ATTRIBUTION); /***** Update the table changing old attribution by new attribution *****/ Ctr_DB_UpdateCtrPhotoAttribution (Gbl.Hierarchy.Node[Hie_CTR].HieCod, NewPhotoAttribution); /***** Show the center information again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /********************* Change the institution of a center ********************/ /*****************************************************************************/ void CtrCfg_ChangeCtrIns (void) { extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node); extern const char *Txt_The_center_X_has_been_moved_to_the_institution_Y; struct Hie_Node NewIns; const char *Names[Nam_NUM_SHRT_FULL_NAMES]; /***** Get parameter with institution code *****/ NewIns.HieCod = ParCod_GetAndCheckPar (ParCod_OthIns); /***** Check if institution has changed *****/ if (NewIns.HieCod != Gbl.Hierarchy.Node[Hie_CTR].PrtCod) { /***** Get data of new institution *****/ Hie_GetDataByCod[Hie_INS] (&NewIns); /***** Check if it already exists a center with the same name in the new institution *****/ Names[Nam_SHRT_NAME] = Gbl.Hierarchy.Node[Hie_CTR].ShrtName; Names[Nam_FULL_NAME] = Gbl.Hierarchy.Node[Hie_CTR].FullName; if (!Nam_CheckIfNameExists (Ctr_DB_CheckIfCtrNameExistsInIns, Names, Gbl.Hierarchy.Node[Hie_CTR].HieCod, NewIns.HieCod, 0)) // Unused { /***** Update institution in table of centers *****/ Ctr_DB_UpdateCtrIns (Gbl.Hierarchy.Node[Hie_CTR].HieCod,NewIns.HieCod); Gbl.Hierarchy.Node[Hie_CTR].PrtCod = Gbl.Hierarchy.Node[Hie_INS].HieCod = NewIns.HieCod; /***** Initialize again current course, degree, center... *****/ Hie_InitHierarchy (); /***** Create message to show the change made *****/ Ale_CreateAlert (Ale_SUCCESS,NULL, Txt_The_center_X_has_been_moved_to_the_institution_Y, Gbl.Hierarchy.Node[Hie_CTR].FullName,NewIns.FullName); } } } /*****************************************************************************/ /************************ Change the place of a center ***********************/ /*****************************************************************************/ void CtrCfg_ChangeCtrPlc (void) { extern const char *Txt_The_place_of_the_center_has_changed; long NewPlcCod; /***** Get parameter with place code *****/ NewPlcCod = ParCod_GetAndCheckParMin (ParCod_Plc,0); // 0 (another place) is allowed here /***** Update place in table of centers *****/ Ctr_DB_UpdateCtrPlc (Gbl.Hierarchy.Node[Hie_CTR].HieCod,NewPlcCod); Gbl.Hierarchy.Node[Hie_CTR].Specific.PlcCod = NewPlcCod; /***** Write message to show the change made *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_The_place_of_the_center_has_changed); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /*************** Change the name of a center in configuration ****************/ /*****************************************************************************/ void CtrCfg_RenameCenterShrt (void) { Ctr_RenameCenter (&Gbl.Hierarchy.Node[Hie_CTR],Nam_SHRT_NAME); } void CtrCfg_RenameCenterFull (void) { Ctr_RenameCenter (&Gbl.Hierarchy.Node[Hie_CTR],Nam_FULL_NAME); } /*****************************************************************************/ /********************** Change the latitude of a center **********************/ /*****************************************************************************/ void CtrCfg_ChangeCtrLatitude (void) { char LatitudeStr[64]; double NewLatitude; /***** Get latitude *****/ Par_GetParText ("Latitude",LatitudeStr,sizeof (LatitudeStr) - 1); NewLatitude = Map_GetLatitudeFromStr (LatitudeStr); /***** Update database changing old latitude by new latitude *****/ Ctr_DB_UpdateCtrCoordinate (Gbl.Hierarchy.Node[Hie_CTR].HieCod, "Latitude",NewLatitude); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /********************** Change the longitude of a center **********************/ /*****************************************************************************/ void CtrCfg_ChangeCtrLongitude (void) { char LongitudeStr[64]; double NewLongitude; /***** Get longitude *****/ Par_GetParText ("Longitude",LongitudeStr,sizeof (LongitudeStr) - 1); NewLongitude = Map_GetLongitudeFromStr (LongitudeStr); /***** Update database changing old longitude by new longitude *****/ Ctr_DB_UpdateCtrCoordinate (Gbl.Hierarchy.Node[Hie_CTR].HieCod, "Longitude",NewLongitude); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /********************** Change the latitude of a center **********************/ /*****************************************************************************/ void CtrCfg_ChangeCtrAltitude (void) { char AltitudeStr[64]; double NewAltitude; /***** Get altitude *****/ Par_GetParText ("Altitude",AltitudeStr,sizeof (AltitudeStr) - 1); NewAltitude = Map_GetAltitudeFromStr (AltitudeStr); /***** Update database changing old altitude by new altitude *****/ Ctr_DB_UpdateCtrCoordinate (Gbl.Hierarchy.Node[Hie_CTR].HieCod, "Altitude",NewAltitude); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /************************* Change the URL of a center ************************/ /*****************************************************************************/ void CtrCfg_ChangeCtrWWW (void) { extern const char *Txt_The_new_web_address_is_X; char NewWWW[WWW_MAX_BYTES_WWW + 1]; /***** Get parameters from form *****/ /* Get the new WWW for the center */ Par_GetParText ("WWW",NewWWW,WWW_MAX_BYTES_WWW); /***** Check if new WWW is empty *****/ if (NewWWW[0]) { /***** Update database changing old WWW by new WWW *****/ Ctr_DB_UpdateCtrWWW (Gbl.Hierarchy.Node[Hie_CTR].HieCod,NewWWW); Str_Copy (Gbl.Hierarchy.Node[Hie_CTR].WWW,NewWWW, sizeof (Gbl.Hierarchy.Node[Hie_CTR].WWW) - 1); /***** Write message to show the change made *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_The_new_web_address_is_X, NewWWW); } else Ale_CreateAlertYouCanNotLeaveFieldEmpty (); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); } /*****************************************************************************/ /** Show message of success after changing a center in center configuration **/ /*****************************************************************************/ void CtrCfg_ContEditAfterChgCtr (void) { /***** Write error/success message *****/ Ale_ShowAlerts (NULL); /***** Show the form again *****/ CtrCfg_ShowConfiguration (); }