// 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,"