// swad_centre.c: centres /* 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-2019 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 NULL #include // For boolean type #include // For asprintf #include // For calloc #include // For string functions #include // For the macro WEXITSTATUS #include // For unlink #include "swad_box.h" #include "swad_centre.h" #include "swad_constant.h" #include "swad_database.h" #include "swad_form.h" #include "swad_global.h" #include "swad_help.h" #include "swad_hierarchy.h" #include "swad_HTML.h" #include "swad_institution.h" #include "swad_language.h" #include "swad_logo.h" #include "swad_parameter.h" #include "swad_QR.h" #include "swad_string.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ // Centre 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 512 #define Ctr_PHOTO_SAVED_QUALITY 75 // 1 to 100 /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ static struct Centre *Ctr_EditingCtr = NULL; // Static variable to keep the centre being edited /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Ctr_Configuration (bool PrintView); static void Ctr_PutIconsCtrConfig (void); static void Ctr_PutIconToChangePhoto (void); static void Ctr_ShowNumUsrsInCrssOfCtr (Rol_Role_t Role); static void Ctr_ListCentres (void); static bool Ctr_CheckIfICanCreateCentres (void); static void Ctr_PutIconsListingCentres (void); static void Ctr_PutIconToEditCentres (void); static void Ctr_ListOneCentreForSeeing (struct Centre *Ctr,unsigned NumCtr); static void Ctr_GetParamCtrOrder (void); static void Ctr_EditCentresInternal (void); static void Ctr_PutIconsEditingCentres (void); static void Ctr_GetPhotoAttribution (long CtrCod,char **PhotoAttribution); static void Ctr_FreePhotoAttribution (char **PhotoAttribution); static void Ctr_ListCentresForEdition (void); static bool Ctr_CheckIfICanEditACentre (struct Centre *Ctr); static Ctr_StatusTxt_t Ctr_GetStatusTxtFromStatusBits (Ctr_Status_t Status); static Ctr_Status_t Ctr_GetStatusBitsFromStatusTxt (Ctr_StatusTxt_t StatusTxt); static void Ctr_PutParamOtherCtrCod (long CtrCod); static void Ctr_UpdateCtrInsDB (long CtrCod,long InsCod); static void Ctr_UpdateCtrPlcDB (long CtrCod,long NewPlcCod); static void Ctr_RenameCentre (struct Centre *Ctr,Cns_ShrtOrFullName_t ShrtOrFullName); static bool Ctr_CheckIfCtrNameExistsInIns (const char *FieldName,const char *Name,long CtrCod,long InsCod); static void Ctr_UpdateInsNameDB (long CtrCod,const char *FieldName,const char *NewCtrName); static void Ctr_UpdateCtrWWWDB (long CtrCod, const char NewWWW[Cns_MAX_BYTES_WWW + 1]); static void Ctr_ShowAlertAndButtonToGoToCtr (void); static void Ctr_PutParamGoToCtr (void); static void Ctr_PutFormToCreateCentre (void); static void Ctr_PutHeadCentresForSeeing (bool OrderSelectable); static void Ctr_PutHeadCentresForEdition (void); static void Ctr_RecFormRequestOrCreateCtr (unsigned Status); static void Ctr_CreateCentre (unsigned Status); static void Ctr_EditingCentreConstructor (void); static void Ctr_EditingCentreDestructor (void); /*****************************************************************************/ /******************* List centres with pending degrees ***********************/ /*****************************************************************************/ void Ctr_SeeCtrWithPendingDegs (void) { extern const char *Hlp_SYSTEM_Hierarchy_pending; extern const char *Txt_Centres_with_pending_degrees; extern const char *Txt_Centre; extern const char *Txt_Degrees_ABBREVIATION; extern const char *Txt_There_are_no_centres_with_requests_for_degrees_to_be_confirmed; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumCtrs; unsigned NumCtr; struct Centre Ctr; const char *BgColor; /***** Get centres with pending degrees *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_CTR_ADM: NumCtrs = (unsigned) DB_QuerySELECT (&mysql_res,"can not get centres" " with pending degrees", "SELECT degrees.CtrCod,COUNT(*)" " FROM degrees,ctr_admin,centres" " WHERE (degrees.Status & %u)<>0" " AND degrees.CtrCod=ctr_admin.CtrCod" " AND ctr_admin.UsrCod=%ld" " AND degrees.CtrCod=centres.CtrCod" " GROUP BY degrees.CtrCod ORDER BY centres.ShortName", (unsigned) Deg_STATUS_BIT_PENDING, Gbl.Usrs.Me.UsrDat.UsrCod); break; case Rol_SYS_ADM: NumCtrs = (unsigned) DB_QuerySELECT (&mysql_res,"can not get centres" " with pending degrees", "SELECT degrees.CtrCod,COUNT(*)" " FROM degrees,centres" " WHERE (degrees.Status & %u)<>0" " AND degrees.CtrCod=centres.CtrCod" " GROUP BY degrees.CtrCod ORDER BY centres.ShortName", (unsigned) Deg_STATUS_BIT_PENDING); break; default: // Forbidden for other users return; } if (NumCtrs) { /***** Begin box and table *****/ Box_StartBoxTable (NULL,Txt_Centres_with_pending_degrees,NULL, Hlp_SYSTEM_Hierarchy_pending,Box_NOT_CLOSABLE,2); /***** Wrtie heading *****/ HTM_TR_Begin (NULL); HTM_TH (1,1,"LM",Txt_Centre); HTM_TH (1,1,"RM",Txt_Degrees_ABBREVIATION); HTM_TR_End (); /***** List the centres *****/ for (NumCtr = 0; NumCtr < NumCtrs; NumCtr++) { /* Get next centre */ row = mysql_fetch_row (mysql_res); /* Get centre code (row[0]) */ Ctr.CtrCod = Str_ConvertStrCodToLongCod (row[0]); BgColor = (Ctr.CtrCod == Gbl.Hierarchy.Ctr.CtrCod) ? "LIGHT_BLUE" : Gbl.ColorRows[Gbl.RowEvenOdd]; /* Get data of centre */ Ctr_GetDataOfCentreByCod (&Ctr); /* Centre logo and full name */ HTM_TR_Begin (NULL); HTM_TD_Begin ("class=\"LM %s\"",BgColor); Ctr_DrawCentreLogoAndNameWithLink (&Ctr,ActSeeDeg, "DAT_NOBR","CM"); HTM_TD_End (); /* Number of pending degrees (row[1]) */ HTM_TD_Begin ("class=\"DAT RM %s\"",BgColor); fprintf (Gbl.F.Out,"%s",row[1]); HTM_TD_End (); Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; HTM_TR_End (); } /***** End table and box *****/ Box_EndBoxTable (); } else Ale_ShowAlert (Ale_INFO,Txt_There_are_no_centres_with_requests_for_degrees_to_be_confirmed); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /******************** Draw centre logo and name with link ********************/ /*****************************************************************************/ void Ctr_DrawCentreLogoAndNameWithLink (struct Centre *Ctr,Act_Action_t Action, const char *ClassLink,const char *ClassLogo) { extern const char *Txt_Go_to_X; /***** Begin form *****/ Frm_StartFormGoTo (Action); Ctr_PutParamCtrCod (Ctr->CtrCod); /***** Link to action *****/ snprintf (Gbl.Title,sizeof (Gbl.Title), Txt_Go_to_X, Ctr->FullName); Frm_LinkFormSubmit (Gbl.Title,ClassLink,NULL); /***** Centre logo and name *****/ Log_DrawLogo (Hie_CTR,Ctr->CtrCod,Ctr->ShrtName,16,ClassLogo,true); fprintf (Gbl.F.Out," %s",Ctr->FullName); /***** End link *****/ Frm_LinkFormEnd (); /***** End form *****/ Frm_EndForm (); } /*****************************************************************************/ /****************** Show information of the current centre *******************/ /*****************************************************************************/ void Ctr_ShowConfiguration (void) { Ctr_Configuration (false); /***** Show help to enrol me *****/ Hlp_ShowHelpWhatWouldYouLikeToDo (); } /*****************************************************************************/ /****************** Print information of the current centre ******************/ /*****************************************************************************/ void Ctr_PrintConfiguration (void) { Ctr_Configuration (true); } /*****************************************************************************/ /******************* Information of the current centre ***********************/ /*****************************************************************************/ static void Ctr_Configuration (bool PrintView) { extern const char *Hlp_CENTRE_Information; extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_Institution; extern const char *Txt_Centre; extern const char *Txt_Short_name; extern const char *Txt_Another_place; extern const char *Txt_Web; extern const char *Txt_Shortcut; extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; extern const char *Txt_QR_code; extern const char *Txt_Users_of_the_centre; extern const char *Txt_Place; extern const char *Txt_Degrees; extern const char *Txt_Degrees_of_CENTRE_X; extern const char *Txt_Courses; unsigned NumIns; unsigned NumPlc; struct Place Plc; char PathPhoto[PATH_MAX + 1]; bool PhotoExists; char *PhotoAttribution = NULL; bool PutLink; char *URL; char *Icon; /***** Trivial check *****/ if (Gbl.Hierarchy.Ctr.CtrCod <= 0) // No centre selected return; /***** Path to photo *****/ snprintf (PathPhoto,sizeof (PathPhoto), "%s/%02u/%u/%u.jpg", Cfg_PATH_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Ctr.CtrCod % 100), (unsigned) Gbl.Hierarchy.Ctr.CtrCod, (unsigned) Gbl.Hierarchy.Ctr.CtrCod); PhotoExists = Fil_CheckIfPathExists (PathPhoto); /***** Begin box *****/ if (PrintView) Box_BoxBegin (NULL,NULL,NULL, NULL,Box_NOT_CLOSABLE); else Box_BoxBegin (NULL,NULL,Ctr_PutIconsCtrConfig, Hlp_CENTRE_Information,Box_NOT_CLOSABLE); /***** Title *****/ PutLink = !PrintView && Gbl.Hierarchy.Ctr.WWW[0]; HTM_DIV_Begin ("class=\"FRAME_TITLE FRAME_TITLE_BIG\""); if (PutLink) HTM_A_Begin ("href=\"%s\" target=\"_blank\"" " class=\"FRAME_TITLE_BIG\" title=\"%s\"", Gbl.Hierarchy.Ctr.WWW, Gbl.Hierarchy.Ctr.FullName); Log_DrawLogo (Hie_CTR,Gbl.Hierarchy.Ctr.CtrCod, Gbl.Hierarchy.Ctr.ShrtName,64,NULL,true); fprintf (Gbl.F.Out,"
%s",Gbl.Hierarchy.Ctr.FullName); if (PutLink) HTM_A_End (); HTM_DIV_End (); /***** Centre photo *****/ if (PhotoExists) { /* Get photo attribution */ Ctr_GetPhotoAttribution (Gbl.Hierarchy.Ctr.CtrCod,&PhotoAttribution); /* Photo image */ HTM_DIV_Begin ("class=\"DAT_SMALL CM\""); if (PutLink) HTM_A_Begin ("href=\"%s\" target=\"_blank\" class=\"DAT_N\"", Gbl.Hierarchy.Ctr.WWW); if (asprintf (&URL,"%s/%02u/%u", Cfg_URL_CTR_PUBLIC, (unsigned) (Gbl.Hierarchy.Ctr.CtrCod % 100), (unsigned) Gbl.Hierarchy.Ctr.CtrCod) < 0) Lay_NotEnoughMemoryExit (); if (asprintf (&Icon,"%u.jpg", (unsigned) Gbl.Hierarchy.Ctr.CtrCod) < 0) Lay_NotEnoughMemoryExit (); HTM_IMG (URL,Icon,Gbl.Hierarchy.Ctr.FullName, "class=\"%s\"",PrintView ? "CENTRE_PHOTO_PRINT" : "CENTRE_PHOTO_SHOW"); free ((void *) Icon); free ((void *) URL); if (PutLink) HTM_A_End (); HTM_DIV_End (); /* Photo attribution */ if (!PrintView && Gbl.Usrs.Me.Role.Logged >= Rol_CTR_ADM) // Only centre admins, institution admins and centre admins // have permission to edit photo attribution { HTM_DIV_Begin ("class=\"CM\""); Frm_StartForm (ActChgCtrPhoAtt); HTM_TEXTAREA_Begin ("id=\"AttributionArea\" name=\"Attribution\" rows=\"2\"" " onchange=\"document.getElementById('%s').submit();\"", Gbl.Form.Id); if (PhotoAttribution) fprintf (Gbl.F.Out,"%s",PhotoAttribution); HTM_TEXTAREA_End (); Frm_EndForm (); HTM_DIV_End (); } else if (PhotoAttribution) { HTM_DIV_Begin ("class=\"ATTRIBUTION\""); fprintf (Gbl.F.Out,"%s",PhotoAttribution); HTM_DIV_End (); } /* Free memory used for photo attribution */ Ctr_FreePhotoAttribution (&PhotoAttribution); } /***** Begin table *****/ HTM_TABLE_BeginWidePadding (2); /***** Institution *****/ HTM_TR_Begin (NULL); HTM_TD_Begin ("class=\"RM\""); fprintf (Gbl.F.Out,"