// swad_user.c: users /* 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 3 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 isalnum, isdigit, etc. #include // For maximum values #include // For PATH_MAX #include // For NULL #include // For exit, system, malloc, free, rand, etc. #include // For string functions #include // For the macro WEXITSTATUS #include // For access, lstat, getpid, chdir, symlink, unlink #include "swad_account.h" #include "swad_announcement.h" #include "swad_box.h" #include "swad_calendar.h" #include "swad_config.h" #include "swad_connected.h" #include "swad_course.h" #include "swad_database.h" #include "swad_duplicate.h" #include "swad_enrolment.h" #include "swad_follow.h" #include "swad_form.h" #include "swad_global.h" #include "swad_group.h" #include "swad_help.h" #include "swad_hierarchy.h" #include "swad_HTML.h" #include "swad_ID.h" #include "swad_language.h" #include "swad_MFU.h" #include "swad_nickname.h" #include "swad_notification.h" #include "swad_parameter.h" #include "swad_password.h" #include "swad_privacy.h" #include "swad_QR.h" #include "swad_record.h" #include "swad_role.h" #include "swad_setting.h" #include "swad_tab.h" #include "swad_user.h" /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ const char *Usr_StringsSexIcons[Usr_NUM_SEXS] = { "?", // Usr_SEX_UNKNOWN "♀", // Usr_SEX_FEMALE "♂", // Usr_SEX_MALE "*", // Usr_SEX_ALL }; const char *Usr_StringsSexDB[Usr_NUM_SEXS] = { "unknown", // Usr_SEX_UNKNOWN "female", // Usr_SEX_FEMALE "male", // Usr_SEX_MALE "all", // Usr_SEX_ALL }; const char *Usr_StringsUsrListTypeInDB[Usr_NUM_USR_LIST_TYPES] = { "", // Usr_LIST_UNKNOWN "classphoto", // Usr_LIST_AS_CLASS_PHOTO "list", // Usr_LIST_AS_LISTING }; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ static const char *Usr_IconsClassPhotoOrList[Usr_NUM_USR_LIST_TYPES] = { "", // Usr_LIST_UNKNOWN "th.svg", // Usr_LIST_AS_CLASS_PHOTO "list-ol.svg", // Usr_LIST_AS_LISTING }; static const char *Usr_NameSelUnsel[Rol_NUM_ROLES] = { NULL, // Rol_UNK "SEL_UNSEL_GSTS", // Rol_GST NULL, // Rol_USR "SEL_UNSEL_STDS", // Rol_STD "SEL_UNSEL_NETS", // Rol_NET "SEL_UNSEL_TCHS", // Rol_TCH NULL, // Rol_DEG_ADM NULL, // Rol_CTR_ADM NULL, // Rol_INS_ADM NULL, // Rol_SYS_ADM }; static const char *Usr_ParamUsrCod[Rol_NUM_ROLES] = { "UsrCodAll", // Rol_UNK (here means all users) "UsrCodGst", // Rol_GST NULL, // Rol_USR "UsrCodStd", // Rol_STD "UsrCodNET", // Rol_NET "UsrCodTch", // Rol_TCH NULL, // Rol_DEG_ADM NULL, // Rol_CTR_ADM NULL, // Rol_INS_ADM NULL, // Rol_SYS_ADM }; #define Usr_NUM_MAIN_FIELDS_DATA_ADM 7 #define Usr_NUM_ALL_FIELDS_DATA_GST 17 #define Usr_NUM_ALL_FIELDS_DATA_STD 13 #define Usr_NUM_ALL_FIELDS_DATA_TCH 11 const char *Usr_UsrDatMainFieldNames[Usr_NUM_MAIN_FIELDS_DATA_USR]; #define Usr_MAX_BYTES_QUERY_GET_LIST_USRS (16 * 1024 - 1) /*****************************************************************************/ /****************************** Internal types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /****************************** Private variables ****************************/ /*****************************************************************************/ static void (*Usr_FuncParamsBigList) (); // Used to pass pointer to function /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Usr_GetMyLastData (void); static void Usr_GetUsrCommentsFromString (char *Str,struct UsrData *UsrDat); static Usr_Sex_t Usr_GetSexFromStr (const char *Str); static bool Usr_CheckIfMyBirthdayHasNotBeenCongratulated (void); static void Usr_InsertMyBirthday (void); static void Usr_RemoveTemporaryTableMyCourses (void); static void Usr_GetParamOtherUsrIDNickOrEMail (void); static bool Usr_ChkUsrAndGetUsrDataFromDirectLogin (void); static bool Usr_ChkUsrAndGetUsrDataFromSession (void); static void Usr_ShowAlertUsrDoesNotExistsOrWrongPassword (void); static void Usr_ShowAlertThereAreMoreThanOneUsr (void); static void Usr_SetMyPrefsAndRoles (void); static void Usr_PutLinkToLogOut (void); static void Usr_InsertMyLastData (void); static void Usr_WriteRowGstAllData (struct UsrData *UsrDat); static void Usr_WriteRowStdAllData (struct UsrData *UsrDat,char *GroupNames); static void Usr_WriteRowTchAllData (struct UsrData *UsrDat); static void Usr_WriteRowAdmData (unsigned NumUsr,struct UsrData *UsrDat); static void Usr_WriteMainUsrDataExceptUsrID (struct UsrData *UsrDat, const char *BgColor); static void Usr_WriteEmail (struct UsrData *UsrDat,const char *BgColor); static void Usr_WriteUsrData (const char *BgColor, const char *Data,const char *Link, bool NonBreak,bool Accepted); static void Usr_BuildQueryToGetUsrsLstCrs (char **Query,Rol_Role_t Role); static void Usr_GetAdmsLst (Hie_Level_t Scope); static void Usr_GetGstsLst (Hie_Level_t Scope); static void Usr_GetListUsrsFromQuery (char *Query,Rol_Role_t Role,Hie_Level_t Scope); static void Usr_AllocateUsrsList (Rol_Role_t Role); static void Usr_PutButtonToConfirmIWantToSeeBigList (unsigned NumUsrs, void (*FuncParams) (void), const char *OnSubmit); static void Usr_PutParamsConfirmIWantToSeeBigList (void); static void Usr_AllocateListSelectedUsrCod (Rol_Role_t Role); static void Usr_AllocateListOtherRecipients (void); static void Usr_FormToSelectUsrListType (void (*FuncParams) (void), Usr_ShowUsrsType_t ListType); static Usr_Sex_t Usr_GetSexOfUsrsLst (Rol_Role_t Role); static void Usr_PutCheckboxToSelectUser (Rol_Role_t Role, const char *EncryptedUsrCod, bool UsrIsTheMsgSender); static void Usr_PutCheckboxListWithPhotos (void); static void Usr_ListMainDataGsts (bool PutCheckBoxToSelectUsr); static void Usr_ListMainDataStds (bool PutCheckBoxToSelectUsr); static void Usr_ListMainDataTchs (Rol_Role_t Role,bool PutCheckBoxToSelectUsr); static void Usr_ListUsrsForSelection (Rol_Role_t Role); static void Usr_ListRowsAllDataTchs (Rol_Role_t Role, const char *FieldNames[Usr_NUM_ALL_FIELDS_DATA_TCH], unsigned NumColumns); static void Usr_GetAndUpdateUsrListType (void); static void Usr_GetUsrListTypeFromForm (void); static void Usr_GetMyUsrListTypeFromDB (void); static void Usr_UpdateMyUsrListTypeInDB (void); static void Usr_GetParamColsClassPhotoFromForm (void); static void Usr_GetMyColsClassPhotoFromDB (void); static void Usr_UpdateMyColsClassPhotoInDB (void); static void Usr_GetAndUpdatePrefAboutListWithPhotos (void); static bool Usr_GetParamListWithPhotosFromForm (void); static void Usr_UpdateMyPrefAboutListWithPhotosPhotoInDB (void); static void Usr_PutLinkToSeeAdmins (void); static void Usr_PutLinkToSeeGuests (void); static bool Usr_SetOptionsListUsrsAllowed (Rol_Role_t UsrsRole, bool ICanChooseOption[Usr_LIST_USRS_NUM_OPTIONS]); static void Usr_PutOptionsListUsrs (const bool ICanChooseOption[Usr_LIST_USRS_NUM_OPTIONS]); static void Usr_ShowOneListUsrsOption (Usr_ListUsrsOption_t ListUsrsAction, const char *Label); static Usr_ListUsrsOption_t Usr_GetListUsrsOption (Usr_ListUsrsOption_t DefaultAction); static void Usr_PutIconsListGsts (void); static void Usr_PutIconsListStds (void); static void Usr_PutIconsListTchs (void); static void Usr_PutIconToPrintGsts (void); static void Usr_PutIconToPrintStds (void); static void Usr_PutIconToPrintTchs (void); static void Usr_PutIconToShowGstsAllData (void); static void Usr_PutIconToShowStdsAllData (void); static void Usr_PutIconToShowTchsAllData (void); static void Usr_ShowGstsAllDataParams (void); static void Usr_ShowStdsAllDataParams (void); static void Usr_ShowTchsAllDataParams (void); static void Usr_DrawClassPhoto (Usr_ClassPhotoType_t ClassPhotoType, Rol_Role_t Role,bool PutCheckBoxToSelectUsr); /*****************************************************************************/ /**** Show alert about number of clicks remaining before sending my photo ****/ /*****************************************************************************/ void Usr_InformAboutNumClicksBeforePhoto (void) { extern const char *Txt_You_must_send_your_photo_because_; extern const char *Txt_You_can_only_perform_X_further_actions_; extern const char *Txt_Upload_photo; if (Gbl.Usrs.Me.NumAccWithoutPhoto) { if (Gbl.Usrs.Me.NumAccWithoutPhoto >= Pho_MAX_CLICKS_WITHOUT_PHOTO) Ale_ShowAlert (Ale_WARNING,Txt_You_must_send_your_photo_because_); else if (Act_GetBrowserTab (Gbl.Action.Act) == Act_BRW_1ST_TAB) Ale_ShowAlertAndButton (ActReqMyPho,NULL,NULL,NULL, Btn_CONFIRM_BUTTON,Txt_Upload_photo, Ale_WARNING,Txt_You_can_only_perform_X_further_actions_, Pho_MAX_CLICKS_WITHOUT_PHOTO - Gbl.Usrs.Me.NumAccWithoutPhoto); } } /*****************************************************************************/ /************************** Create data for a user ***************************/ /*****************************************************************************/ void Usr_UsrDataConstructor (struct UsrData *UsrDat) { /***** Allocate memory for the comments *****/ if ((UsrDat->Comments = (char *) malloc (Cns_MAX_BYTES_TEXT + 1)) == NULL) Lay_NotEnoughMemoryExit (); /***** Initialize to zero the data of the user *****/ Usr_ResetUsrDataExceptUsrCodAndIDs (UsrDat); UsrDat->IDs.Num = 0; UsrDat->IDs.List = NULL; } /*****************************************************************************/ /****************** Reset user's data except UsrCod and ID *******************/ /*****************************************************************************/ // UsrCod and ID are not changed void Usr_ResetUsrDataExceptUsrCodAndIDs (struct UsrData *UsrDat) { UsrDat->EncryptedUsrCod[0] = '\0'; UsrDat->Nickname[0] = '\0'; UsrDat->Password[0] = '\0'; UsrDat->Roles.InCurrentCrs.Role = Rol_UNK; UsrDat->Roles.InCurrentCrs.Valid = false; UsrDat->Roles.InCrss = -1; // < 0 ==> not yet got from database UsrDat->Accepted = false; UsrDat->Sex = Usr_SEX_UNKNOWN; UsrDat->Surname1[0] = '\0'; UsrDat->Surname2[0] = '\0'; UsrDat->FirstName[0] = '\0'; UsrDat->FullName[0] = '\0'; UsrDat->Email[0] = '\0'; UsrDat->EmailConfirmed = false; UsrDat->Photo[0] = '\0'; UsrDat->PhotoVisibility = Pri_PHOTO_VIS_DEFAULT; UsrDat->BaPrfVisibility = Pri_BASIC_PROFILE_VIS_DEFAULT; UsrDat->ExPrfVisibility = Pri_EXTENDED_PROFILE_VIS_DEFAULT; UsrDat->CtyCod = -1L; UsrDat->OriginPlace[0] = '\0'; UsrDat->StrBirthday[0] = '\0'; UsrDat->Birthday.Day = 0; UsrDat->Birthday.Month = 0; UsrDat->Birthday.Year = 0; UsrDat->LocalAddress[0] = '\0'; UsrDat->LocalPhone[0] = '\0'; UsrDat->FamilyAddress[0] = '\0'; UsrDat->FamilyPhone[0] = '\0'; if (UsrDat->Comments) UsrDat->Comments[0] = '\0'; UsrDat->InsCtyCod = -1L; UsrDat->InsCod = -1L; UsrDat->Tch.CtrCod = -1L; UsrDat->Tch.DptCod = -1L; UsrDat->Tch.Office[0] = '\0'; UsrDat->Tch.OfficePhone[0] = '\0'; UsrDat->Prefs.Language = Lan_LANGUAGE_UNKNOWN; // Language unknown UsrDat->Prefs.FirstDayOfWeek = Cal_FIRST_DAY_OF_WEEK_DEFAULT; // Default first day of week UsrDat->Prefs.DateFormat = Dat_FORMAT_DEFAULT ; // Default date format UsrDat->Prefs.Theme = The_THEME_DEFAULT; UsrDat->Prefs.IconSet = Ico_ICON_SET_DEFAULT; UsrDat->Prefs.Menu = Mnu_MENU_DEFAULT; UsrDat->Prefs.SideCols = Cfg_DEFAULT_COLUMNS; UsrDat->Prefs.AcceptThirdPartyCookies = false; // By default, don't accept third party cookies UsrDat->NtfEvents.SendEmail = 0; // By default, don't notify anything } /*****************************************************************************/ /**************************** Reset my last data *****************************/ /*****************************************************************************/ void Usr_ResetMyLastData (void) { Gbl.Usrs.Me.UsrLast.WhatToSearch = Sch_WHAT_TO_SEARCH_DEFAULT; Gbl.Usrs.Me.UsrLast.LastHie.Scope = Hie_UNK; Gbl.Usrs.Me.UsrLast.LastHie.Cod = -1L; Gbl.Usrs.Me.UsrLast.LastAct = ActUnk; Gbl.Usrs.Me.UsrLast.LastRole = Rol_UNK; Gbl.Usrs.Me.UsrLast.LastTime = 0; Gbl.Usrs.Me.UsrLast.LastAccNotif = 0; } /*****************************************************************************/ /**************** Free memory used to store the data of a user ***************/ /*****************************************************************************/ void Usr_UsrDataDestructor (struct UsrData *UsrDat) { /***** Free memory allocated for comments *****/ if (UsrDat->Comments) { free ((void *) UsrDat->Comments); UsrDat->Comments = NULL; } /***** Free memory allocated for list of IDs *****/ ID_FreeListIDs (UsrDat); } /*****************************************************************************/ /************* Get all the user's data from a given user's code **************/ /*****************************************************************************/ // Input: UsrDat->UsrCod must hold user's code void Usr_GetAllUsrDataFromUsrCod (struct UsrData *UsrDat,Usr_GetPrefs_t GetPrefs) { ID_GetListIDsFromUsrCod (UsrDat); Usr_GetUsrDataFromUsrCod (UsrDat,GetPrefs); } /*****************************************************************************/ /**************** Allocate memory for the list of users' codes ***************/ /*****************************************************************************/ void Usr_AllocateListUsrCods (struct ListUsrCods *ListUsrCods) { if ((ListUsrCods->Lst = (long *) malloc (ListUsrCods->NumUsrs * sizeof (long))) == NULL) Lay_NotEnoughMemoryExit (); } /*****************************************************************************/ /****************** Free memory for the list of users' codes *****************/ /*****************************************************************************/ void Usr_FreeListUsrCods (struct ListUsrCods *ListUsrCods) { if (ListUsrCods->NumUsrs && ListUsrCods->Lst) { free ((void *) ListUsrCods->Lst); ListUsrCods->Lst = NULL; ListUsrCods->NumUsrs = 0; } } /*****************************************************************************/ /************************ Check if I am a given user *************************/ /*****************************************************************************/ bool Usr_ItsMe (long UsrCod) { return Gbl.Usrs.Me.Logged && (UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod); } /*****************************************************************************/ /******** Get user's code from database using encrypted user's code **********/ /*****************************************************************************/ // Input: UsrDat->EncryptedUsrCod must hold user's encrypted code void Usr_GetUsrCodFromEncryptedUsrCod (struct UsrData *UsrDat) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; if (UsrDat->EncryptedUsrCod[0]) { /***** Get user's code from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get user's code", "SELECT UsrCod FROM usr_data" " WHERE EncryptedUsrCod='%s'", UsrDat->EncryptedUsrCod); if (NumRows != 1) Lay_ShowErrorAndExit ("Error when getting user's code."); /***** Get user's code *****/ row = mysql_fetch_row (mysql_res); UsrDat->UsrCod = Str_ConvertStrCodToLongCod (row[0]); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } else UsrDat->UsrCod = -1L; } /*****************************************************************************/ /************ Get user's data from database giving a user's code *************/ /*****************************************************************************/ // UsrDat->UsrCod must contain an existing user's code void Usr_GetUsrDataFromUsrCod (struct UsrData *UsrDat,Usr_GetPrefs_t GetPrefs) { extern const char *Ico_IconSetId[Ico_NUM_ICON_SETS]; extern const char *The_ThemeId[The_NUM_THEMES]; extern const char *Txt_The_user_does_not_exist; extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; The_Theme_t Theme; Ico_IconSet_t IconSet; Lan_Language_t Lan; /***** Get user's data from database *****/ switch (GetPrefs) { case Usr_DONT_GET_PREFS: NumRows = DB_QuerySELECT (&mysql_res,"can not get user's data", "SELECT EncryptedUsrCod," // row[ 0] "Password," // row[ 1] "Surname1," // row[ 2] "Surname2," // row[ 3] "FirstName," // row[ 4] "Sex," // row[ 5] "Photo," // row[ 6] "PhotoVisibility," // row[ 7] "BaPrfVisibility," // row[ 8] "ExPrfVisibility," // row[ 9] "CtyCod," // row[10] "InsCtyCod," // row[11] "InsCod," // row[12] "DptCod," // row[13] "CtrCod," // row[14] "Office," // row[15] "OfficePhone," // row[16] "LocalAddress," // row[17] "LocalPhone," // row[18] "FamilyAddress," // row[19] "FamilyPhone," // row[20] "OriginPlace," // row[21] "DATE_FORMAT(Birthday," "'%%Y%%m%%d')," // row[22] "Comments," // row[23] "NotifNtfEvents," // row[24] "EmailNtfEvents" // row[25] " FROM usr_data" " WHERE UsrCod=%ld", UsrDat->UsrCod); break; case Usr_GET_PREFS: default: NumRows = DB_QuerySELECT (&mysql_res,"can not get user's data", "SELECT EncryptedUsrCod," // row[ 0] "Password," // row[ 1] "Surname1," // row[ 2] "Surname2," // row[ 3] "FirstName," // row[ 4] "Sex," // row[ 5] "Photo," // row[ 6] "PhotoVisibility," // row[ 7] "BaPrfVisibility," // row[ 8] "ExPrfVisibility," // row[ 9] "CtyCod," // row[10] "InsCtyCod," // row[11] "InsCod," // row[12] "DptCod," // row[13] "CtrCod," // row[14] "Office," // row[15] "OfficePhone," // row[16] "LocalAddress," // row[17] "LocalPhone," // row[18] "FamilyAddress," // row[19] "FamilyPhone," // row[20] "OriginPlace," // row[21] "DATE_FORMAT(Birthday," "'%%Y%%m%%d')," // row[22] "Comments," // row[23] "NotifNtfEvents," // row[24] "EmailNtfEvents," // row[25] // Settings (usually not necessary // when getting another user's data) "Language," // row[26] "FirstDayOfWeek," // row[27] "DateFormat," // row[28] "Theme," // row[29] "IconSet," // row[30] "Menu," // row[31] "SideCols," // row[32] "ThirdPartyCookies" // row[33] " FROM usr_data" " WHERE UsrCod=%ld", UsrDat->UsrCod); break; } if (NumRows != 1) Lay_ShowErrorAndExit (Txt_The_user_does_not_exist); /***** Read user's data *****/ row = mysql_fetch_row (mysql_res); /* Get encrypted user's code (row[0]) */ Str_Copy (UsrDat->EncryptedUsrCod,row[0], Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64); /* Get encrypted password (row[1]) */ Str_Copy (UsrDat->Password,row[1], Pwd_BYTES_ENCRYPTED_PASSWORD); /* Get roles */ UsrDat->Roles.InCurrentCrs.Role = Rol_GetRoleUsrInCrs (UsrDat->UsrCod, Gbl.Hierarchy.Crs.CrsCod); UsrDat->Roles.InCurrentCrs.Valid = true; UsrDat->Roles.InCrss = -1; // Force roles to be got from database Rol_GetRolesInAllCrssIfNotYetGot (UsrDat); /* Get name (row[2], row[3], row[4]) */ Str_Copy (UsrDat->Surname1,row[2], Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME); Str_Copy (UsrDat->Surname2,row[3], Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME); Str_Copy (UsrDat->FirstName,row[4], Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME); Str_ConvertToTitleType (UsrDat->Surname1 ); Str_ConvertToTitleType (UsrDat->Surname2 ); Str_ConvertToTitleType (UsrDat->FirstName); Usr_BuildFullName (UsrDat); // Create full name using FirstName, Surname1 and Surname2 /* Get sex (row[5]) */ UsrDat->Sex = Usr_GetSexFromStr (row[5]); /* Get photo (row[6]) */ Str_Copy (UsrDat->Photo,row[6], Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64); /* Get photo visibility (row[7]) */ UsrDat->PhotoVisibility = Pri_GetVisibilityFromStr (row[7]); /* Get profile visibility (row[8], row[9]) */ UsrDat->BaPrfVisibility = Pri_GetVisibilityFromStr (row[8]); UsrDat->ExPrfVisibility = Pri_GetVisibilityFromStr (row[9]); /* Get country (row[10]) */ UsrDat->CtyCod = Str_ConvertStrCodToLongCod (row[10]); /* Get institution country (row[11]) and institution (row[12]) */ UsrDat->InsCtyCod = Str_ConvertStrCodToLongCod (row[11]); UsrDat->InsCod = Str_ConvertStrCodToLongCod (row[12]); /* Get department (row[13]) */ UsrDat->Tch.DptCod = Str_ConvertStrCodToLongCod (row[13]); /* Get centre (row[14]) */ UsrDat->Tch.CtrCod = Str_ConvertStrCodToLongCod (row[14]); /* Get office (row[15]) and office phone (row[16]) */ Str_Copy (UsrDat->Tch.Office,row[15], Usr_MAX_BYTES_ADDRESS); Str_Copy (UsrDat->Tch.OfficePhone,row[16], Usr_MAX_BYTES_PHONE); /* Get local address (row[17]) and local phone (row[18]) */ Str_Copy (UsrDat->LocalAddress,row[17], Usr_MAX_BYTES_ADDRESS); Str_Copy (UsrDat->LocalPhone,row[18], Usr_MAX_BYTES_PHONE); /* Get local address (row[19]) and local phone (row[20]) */ Str_Copy (UsrDat->FamilyAddress,row[19], Usr_MAX_BYTES_ADDRESS); Str_Copy (UsrDat->FamilyPhone,row[20], Usr_MAX_BYTES_PHONE); /* Get origin place (row[21]) */ Str_Copy (UsrDat->OriginPlace,row[21], Usr_MAX_BYTES_ADDRESS); /* Get birthday (row[22]) */ Dat_GetDateFromYYYYMMDD (&(UsrDat->Birthday),row[22]); Dat_ConvDateToDateStr (&(UsrDat->Birthday),UsrDat->StrBirthday); /* Get comments (row[23]) */ Usr_GetUsrCommentsFromString (row[23] ? row[23] : "", UsrDat); /* Get on which events the user wants to be notified inside the platform (row[24]) */ if (sscanf (row[24],"%u",&UsrDat->NtfEvents.CreateNotif) != 1) UsrDat->NtfEvents.CreateNotif = (unsigned) -1; // 0xFF..FF /* Get on which events the user wants to be notified by email (row[25]) */ if (sscanf (row[25],"%u",&UsrDat->NtfEvents.SendEmail) != 1) UsrDat->NtfEvents.SendEmail = 0; if (UsrDat->NtfEvents.SendEmail >= (1 << Ntf_NUM_NOTIFY_EVENTS)) // Maximum binary value for NotifyEvents is 000...0011...11 UsrDat->NtfEvents.SendEmail = 0; /***** Get user's settings *****/ if (GetPrefs == Usr_GET_PREFS) { /* Get language (row[26]) */ UsrDat->Prefs.Language = Lan_LANGUAGE_UNKNOWN; // Language unknown for (Lan = (Lan_Language_t) 1; Lan <= Lan_NUM_LANGUAGES; Lan++) if (!strcasecmp (row[26],Lan_STR_LANG_ID[Lan])) { UsrDat->Prefs.Language = Lan; break; } /* Get first day of week (row[27]) */ UsrDat->Prefs.FirstDayOfWeek = Cal_GetFirstDayOfWeekFromStr (row[27]); /* Get date format (row[28]) */ UsrDat->Prefs.DateFormat = Dat_GetDateFormatFromStr (row[28]); /* Get theme (row[29]) */ UsrDat->Prefs.Theme = The_THEME_DEFAULT; for (Theme = (The_Theme_t) 0; Theme < The_NUM_THEMES; Theme++) if (!strcasecmp (row[29],The_ThemeId[Theme])) { UsrDat->Prefs.Theme = Theme; break; } /* Get icon set (row[30]) */ UsrDat->Prefs.IconSet = Ico_ICON_SET_DEFAULT; for (IconSet = (Ico_IconSet_t) 0; IconSet < Ico_NUM_ICON_SETS; IconSet++) if (!strcasecmp (row[30],Ico_IconSetId[IconSet])) { UsrDat->Prefs.IconSet = IconSet; break; } /* Get menu (row[31]) */ UsrDat->Prefs.Menu = Mnu_GetMenuFromStr (row[31]); /* Get if user wants to show side columns (row[32]) */ if (sscanf (row[32],"%u",&UsrDat->Prefs.SideCols) == 1) { if (UsrDat->Prefs.SideCols > Lay_SHOW_BOTH_COLUMNS) UsrDat->Prefs.SideCols = Cfg_DEFAULT_COLUMNS; } else UsrDat->Prefs.SideCols = Cfg_DEFAULT_COLUMNS; /* Get if user accepts third party cookies (row[33]) */ UsrDat->Prefs.AcceptThirdPartyCookies = (row[33][0] == 'Y'); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Get nickname and email *****/ Nck_GetNicknameFromUsrCod (UsrDat->UsrCod,UsrDat->Nickname); Mai_GetEmailFromUsrCod (UsrDat); } /*****************************************************************************/ /********* Get the comments in the record of a user from a string ************/ /*****************************************************************************/ static void Usr_GetUsrCommentsFromString (char *Str,struct UsrData *UsrDat) { /***** Check that memory for comments is allocated *****/ if (UsrDat->Comments) /***** Copy comments from Str to Comments *****/ Str_Copy (UsrDat->Comments,Str, Cns_MAX_BYTES_TEXT); } /*****************************************************************************/ /********** Get user's last data from database giving a user's code **********/ /*****************************************************************************/ static void Usr_GetMyLastData (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; unsigned UnsignedNum; long ActCod; /***** Get user's last data from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get user's last data", "SELECT WhatToSearch," // row[0] "LastSco," // row[1] "LastCod," // row[2] "LastAct," // row[3] "LastRole," // row[4] "UNIX_TIMESTAMP(LastTime)," // row[5] "UNIX_TIMESTAMP(LastAccNotif)" // row[6] " FROM usr_last WHERE UsrCod=%ld", Gbl.Usrs.Me.UsrDat.UsrCod); if (NumRows == 0) { /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Create entry for me in table of user's last data *****/ Usr_ResetMyLastData (); Usr_InsertMyLastData (); } else if (NumRows == 1) { row = mysql_fetch_row (mysql_res); /* Get last type of search (row[0]) */ Gbl.Usrs.Me.UsrLast.WhatToSearch = Sch_SEARCH_UNKNOWN; if (sscanf (row[0],"%u",&UnsignedNum) == 1) if (UnsignedNum < Sch_NUM_WHAT_TO_SEARCH) Gbl.Usrs.Me.UsrLast.WhatToSearch = (Sch_WhatToSearch_t) UnsignedNum; if (Gbl.Usrs.Me.UsrLast.WhatToSearch == Sch_SEARCH_UNKNOWN) Gbl.Usrs.Me.UsrLast.WhatToSearch = Sch_WHAT_TO_SEARCH_DEFAULT; /* Get last hierarchy: scope (row[1]) and code (row[2]) */ Gbl.Usrs.Me.UsrLast.LastHie.Scope = Sco_GetScopeFromDBStr (row[1]); switch (Gbl.Usrs.Me.UsrLast.LastHie.Scope) { case Hie_SYS: // System Gbl.Usrs.Me.UsrLast.LastHie.Cod = -1L; break; case Hie_CTY: // Country case Hie_INS: // Institution case Hie_CTR: // Centre case Hie_DEG: // Degree case Hie_CRS: // Course Gbl.Usrs.Me.UsrLast.LastHie.Cod = Str_ConvertStrCodToLongCod (row[2]); if (Gbl.Usrs.Me.UsrLast.LastHie.Cod <= 0) { Gbl.Usrs.Me.UsrLast.LastHie.Scope = Hie_UNK; Gbl.Usrs.Me.UsrLast.LastHie.Cod = -1L; } break; default: Gbl.Usrs.Me.UsrLast.LastHie.Scope = Hie_UNK; Gbl.Usrs.Me.UsrLast.LastHie.Cod = -1L; break; } /* Get last action (row[3]) */ ActCod = Str_ConvertStrCodToLongCod (row[3]); Gbl.Usrs.Me.UsrLast.LastAct = Act_GetActionFromActCod (ActCod); /* Get last role (row[4]) */ Gbl.Usrs.Me.UsrLast.LastRole = Rol_ConvertUnsignedStrToRole (row[4]); /* Get last access to platform (row[5]) */ Gbl.Usrs.Me.UsrLast.LastTime = 0L; if (row[5]) sscanf (row[5],"%ld",&(Gbl.Usrs.Me.UsrLast.LastTime)); /* Get last access to notifications (row[6]) */ Gbl.Usrs.Me.UsrLast.LastAccNotif = 0L; if (row[6]) sscanf (row[6],"%ld",&(Gbl.Usrs.Me.UsrLast.LastAccNotif)); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } else Lay_ShowErrorAndExit ("Error when getting user's last data."); } /*****************************************************************************/ /****************************** Get sex from string **************************/ /*****************************************************************************/ static Usr_Sex_t Usr_GetSexFromStr (const char *Str) { Usr_Sex_t Sex; for (Sex = (Usr_Sex_t) 0; Sex < Usr_NUM_SEXS; Sex++) if (!strcasecmp (Str,Usr_StringsSexDB[Sex])) return Sex; return Usr_SEX_UNKNOWN; } /*****************************************************************************/ /********** Build full name using FirstName, Surname1 and Surname2 ***********/ /*****************************************************************************/ void Usr_BuildFullName (struct UsrData *UsrDat) { Str_Copy (UsrDat->FullName,UsrDat->FirstName, Usr_MAX_BYTES_FULL_NAME); if (UsrDat->Surname1[0]) { Str_Concat (UsrDat->FullName," ", Usr_MAX_BYTES_FULL_NAME); Str_Concat (UsrDat->FullName,UsrDat->Surname1, Usr_MAX_BYTES_FULL_NAME); } if (UsrDat->Surname2[0]) { Str_Concat (UsrDat->FullName," ", Usr_MAX_BYTES_FULL_NAME); Str_Concat (UsrDat->FullName,UsrDat->Surname2, Usr_MAX_BYTES_FULL_NAME); } } /*****************************************************************************/ /********* Write user name in two lines. 1: first name, 2: surnames **********/ /*****************************************************************************/ void Usr_WriteFirstNameBRSurnames (const struct UsrData *UsrDat) { /***** Write first name and surname 1 *****/ fprintf (Gbl.F.Out,"%s
%s",UsrDat->FirstName,UsrDat->Surname1); /***** Write surname2 if exists *****/ if (UsrDat->Surname2[0]) fprintf (Gbl.F.Out," %s",UsrDat->Surname2); } /*****************************************************************************/ /********************* Flush all caches related to users *********************/ /*****************************************************************************/ void Usr_FlushCachesUsr (void) { Usr_FlushCacheUsrBelongsToIns (); Usr_FlushCacheUsrBelongsToCtr (); Usr_FlushCacheUsrBelongsToDeg (); Usr_FlushCacheUsrBelongsToCrs (); Usr_FlushCacheUsrBelongsToCurrentCrs (); Usr_FlushCacheUsrHasAcceptedInCurrentCrs (); Usr_FlushCacheUsrSharesAnyOfMyCrs (); Rol_FlushCacheRoleUsrInCrs (); Grp_FlushCacheUsrSharesAnyOfMyGrpsInCurrentCrs (); Grp_FlushCacheIBelongToGrp (); Fol_FlushCacheFollow (); } /*****************************************************************************/ /***** Check if a user is an administrator of a degree/centre/institution ****/ /*****************************************************************************/ bool Usr_CheckIfUsrIsAdm (long UsrCod,Hie_Level_t Scope,long Cod) { /***** Get if a user is administrator of a degree from database *****/ return (DB_QueryCOUNT ("can not check if a user is administrator", "SELECT COUNT(*) FROM admin" " WHERE UsrCod=%ld AND Scope='%s' AND Cod=%ld", UsrCod,Sco_GetDBStrFromScope (Scope),Cod) != 0); } /*****************************************************************************/ /********************* Check if a user is a superuser ************************/ /*****************************************************************************/ void Usr_FlushCacheUsrIsSuperuser (void) { Gbl.Cache.UsrIsSuperuser.UsrCod = -1L; Gbl.Cache.UsrIsSuperuser.IsSuperuser = false; } bool Usr_CheckIfUsrIsSuperuser (long UsrCod) { /***** 1. Fast check: Trivial case *****/ if (UsrCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrCod == Gbl.Cache.UsrIsSuperuser.UsrCod) return Gbl.Cache.UsrIsSuperuser.IsSuperuser; /***** 3. Slow check: If not cached, get if a user is superuser from database *****/ Gbl.Cache.UsrIsSuperuser.UsrCod = UsrCod; Gbl.Cache.UsrIsSuperuser.IsSuperuser = (DB_QueryCOUNT ("can not check if a user is superuser", "SELECT COUNT(*) FROM admin" " WHERE UsrCod=%ld AND Scope='%s'", UsrCod,Sco_GetDBStrFromScope (Hie_SYS)) != 0); return Gbl.Cache.UsrIsSuperuser.IsSuperuser; } /*****************************************************************************/ /**************** Check if I can change another user's data ******************/ /*****************************************************************************/ bool Usr_ICanChangeOtherUsrData (const struct UsrData *UsrDat) { bool ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** Check if I have permission to see another user's IDs *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_TCH: /* Check 1: I can change data of users who do not exist in database */ if (UsrDat->UsrCod <= 0) // User does not exist (when creating a new user) return true; /* Check 2: I change data of users without password */ if (!UsrDat->Password[0]) // User has no password (never logged) return true; return false; case Rol_DEG_ADM: case Rol_CTR_ADM: case Rol_INS_ADM: case Rol_SYS_ADM: return Usr_ICanEditOtherUsr (UsrDat); default: return false; } } /*****************************************************************************/ /***************** Check if I can edit another user's data *******************/ /*****************************************************************************/ bool Usr_ICanEditOtherUsr (const struct UsrData *UsrDat) { bool ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; switch (Gbl.Usrs.Me.Role.Logged) { case Rol_DEG_ADM: /* If I am an administrator of current degree, I only can edit users from current degree who have accepted */ if (Usr_CheckIfUsrBelongsToDeg (UsrDat->UsrCod,Gbl.Hierarchy.Deg.DegCod)) // Degree admins can't edit superusers' data if (!Usr_CheckIfUsrIsSuperuser (UsrDat->UsrCod)) return true; return false; case Rol_CTR_ADM: /* If I am an administrator of current centre, I only can edit from current centre who have accepted */ if (Usr_CheckIfUsrBelongsToCtr (UsrDat->UsrCod,Gbl.Hierarchy.Ctr.CtrCod)) // Centre admins can't edit superusers' data if (!Usr_CheckIfUsrIsSuperuser (UsrDat->UsrCod)) return true; return false; case Rol_INS_ADM: /* If I am an administrator of current institution, I only can edit from current institution who have accepted */ if (Usr_CheckIfUsrBelongsToIns (UsrDat->UsrCod,Gbl.Hierarchy.Ins.InsCod)) // Institution admins can't edit superusers' data if (!Usr_CheckIfUsrIsSuperuser (UsrDat->UsrCod)) return true; return false; case Rol_SYS_ADM: return true; default: return false; } } /*****************************************************************************/ /********************* Get number of courses of a user ***********************/ /*****************************************************************************/ unsigned Usr_GetNumCrssOfUsr (long UsrCod) { /***** Get the number of courses of a user from database ******/ return (unsigned) DB_QueryCOUNT ("can not get the number of courses of a user", "SELECT COUNT(*) FROM crs_usr" " WHERE UsrCod=%ld", UsrCod); } /*****************************************************************************/ /*************** Get number of courses of a user not accepted ****************/ /*****************************************************************************/ unsigned Usr_GetNumCrssOfUsrNotAccepted (long UsrCod) { /***** Get the number of courses of a user not accepted from database ******/ return (unsigned) DB_QueryCOUNT ("can not get the number of courses of a user", "SELECT COUNT(*) FROM crs_usr" " WHERE UsrCod=%ld AND Accepted='N'", UsrCod); } /*****************************************************************************/ /********* Get number of courses in with a user have a given role ************/ /*****************************************************************************/ unsigned Usr_GetNumCrssOfUsrWithARole (long UsrCod,Rol_Role_t Role) { /***** Get the number of courses of a user with a role from database ******/ return (unsigned) DB_QueryCOUNT ("can not get the number of courses of a user" " with a role", "SELECT COUNT(*) FROM crs_usr" " WHERE UsrCod=%ld AND Role=%u", UsrCod,(unsigned) Role); } /*****************************************************************************/ /********* Get number of courses in with a user have a given role ************/ /*****************************************************************************/ unsigned Usr_GetNumCrssOfUsrWithARoleNotAccepted (long UsrCod,Rol_Role_t Role) { /***** Get the number of courses of a user with a role from database ******/ return (unsigned) DB_QueryCOUNT ("can not get the number of courses of a user" " with a role", "SELECT COUNT(*) FROM crs_usr" " WHERE UsrCod=%ld AND Role=%u AND Accepted='N'", UsrCod,(unsigned) Role); } /*****************************************************************************/ /****** Get number of users with some given roles in courses of a user *******/ /*****************************************************************************/ #define Usr_MAX_BYTES_ROLES_STR (Rol_NUM_ROLES * (10 + 1)) unsigned Usr_GetNumUsrsInCrssOfAUsr (long UsrCod,Rol_Role_t UsrRole, unsigned OthersRoles) { Rol_Role_t Role; char UnsignedStr[10 + 1]; char OthersRolesStr[Usr_MAX_BYTES_ROLES_STR + 1]; char SubQueryRole[64]; unsigned NumUsrs; // This query can be made in a unique, but slower, query // The temporary table achieves speedup from ~2s to few ms /***** Remove temporary table if exists *****/ DB_Query ("can not remove temporary tables", "DROP TEMPORARY TABLE IF EXISTS usr_courses_tmp"); /***** Create temporary table with all user's courses as student/non-editing teacher/teacher *****/ switch (UsrRole) { case Rol_STD: // Student sprintf (SubQueryRole," AND Role=%u", (unsigned) Rol_STD); break; case Rol_NET: // Non-editing teacher sprintf (SubQueryRole," AND Role=%u", (unsigned) Rol_NET); break; case Rol_TCH: // or teacher sprintf (SubQueryRole," AND Role=%u", (unsigned) Rol_TCH); break; default: SubQueryRole[0] = '\0'; Rol_WrongRoleExit (); break; } DB_Query ("can not create temporary table", "CREATE TEMPORARY TABLE IF NOT EXISTS usr_courses_tmp" " (CrsCod INT NOT NULL,UNIQUE INDEX (CrsCod))" " ENGINE=MEMORY" " SELECT CrsCod FROM crs_usr" " WHERE UsrCod=%ld" "%s", UsrCod,SubQueryRole); /***** Get the number of students/teachers in a course from database ******/ OthersRolesStr[0] = '\0'; for (Role = Rol_STD; // First possible role in a course Role <= Rol_TCH; // Last possible role in a course Role++) if ((OthersRoles & (1 << Role))) { sprintf (UnsignedStr,"%u",(unsigned) Role); if (OthersRolesStr[0]) // Not empty Str_Concat (OthersRolesStr,",", Usr_MAX_BYTES_ROLES_STR); Str_Concat (OthersRolesStr,UnsignedStr, Usr_MAX_BYTES_ROLES_STR); } NumUsrs = (unsigned) DB_QueryCOUNT ("can not get the number of users", "SELECT COUNT(DISTINCT crs_usr.UsrCod)" " FROM crs_usr,usr_courses_tmp" " WHERE crs_usr.CrsCod=usr_courses_tmp.CrsCod" " AND crs_usr.Role IN (%s)", OthersRolesStr); /***** Remove temporary table *****/ DB_Query ("can not remove temporary tables", "DROP TEMPORARY TABLE IF EXISTS usr_courses_tmp"); return NumUsrs; } /*****************************************************************************/ /************ Check if I can view the record card of a student ***************/ /*****************************************************************************/ bool Usr_CheckIfICanViewRecordStd (const struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Is he/she a student? *****/ if (UsrDat->Roles.InCurrentCrs.Role != Rol_STD) return false; /***** 5. Fast check: Am I a system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 6. Fast check: Do I belong to the current course? *****/ if (!Gbl.Usrs.Me.IBelongToCurrentCrs) return false; /***** 7. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 8. Fast / slow check: Does he/she belong to the current course? *****/ if (!Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat)) return false; /***** 9. Fast / slow check depending on roles *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_STD: case Rol_NET: return Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (UsrDat); case Rol_TCH: return true; default: return false; } } /*****************************************************************************/ /************ Check if I can view the record card of a teacher ***************/ /*****************************************************************************/ // Teacher here is intended as: // - a non-editing teacher // - or a teacher bool Usr_CheckIfICanViewRecordTch (struct UsrData *UsrDat) { /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Is he/she a non-editing teacher or a teacher? *****/ return (UsrDat->Roles.InCurrentCrs.Role == Rol_NET || UsrDat->Roles.InCurrentCrs.Role == Rol_TCH); } /*****************************************************************************/ /************ Check if I can view test results of another user ***************/ /*****************************************************************************/ bool Usr_CheckIfICanViewTst (const struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Am I a system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 5. Fast check: Do I belong to the current course? *****/ if (!Gbl.Usrs.Me.IBelongToCurrentCrs) return false; /***** 6. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 7. Fast check: Does he/she belong to the current course? *****/ if (!Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat)) return false; /***** 8. Fast / slow check depending on roles *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_NET: return Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (UsrDat); case Rol_TCH: return true; default: return false; } } /*****************************************************************************/ /*********** Check if I can view matches results of another user *************/ /*****************************************************************************/ bool Usr_CheckIfICanViewMch (const struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Am I a system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 5. Fast check: Do I belong to the current course? *****/ if (!Gbl.Usrs.Me.IBelongToCurrentCrs) return false; /***** 6. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 7. Fast check: Does he/she belong to the current course? *****/ if (!Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat)) return false; /***** 8. Fast / slow check depending on roles *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_NET: return Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (UsrDat); case Rol_TCH: return true; default: return false; } } /*****************************************************************************/ /********** Check if I can view assigments / works of another user ***********/ /*****************************************************************************/ bool Usr_CheckIfICanViewAsgWrk (const struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Does he/she belong to the current course? *****/ // Only users beloging to course can have files in assignments/works if (!Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat)) return false; /***** 5. Fast check: Am I a system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 6. Fast check: Do I belong to the current course? *****/ if (!Gbl.Usrs.Me.IBelongToCurrentCrs) return false; /***** 7. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 8. Fast / slow check depending on roles *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_NET: return Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (UsrDat); case Rol_TCH: return true; default: return false; } } /*****************************************************************************/ /************** Check if I can view attendance of another user ***************/ /*****************************************************************************/ bool Usr_CheckIfICanViewAtt (const struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: Is it a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: Is it a course selected? *****/ if (Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 4. Fast check: Am I a system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 5. Fast check: Do I belong to the current course? *****/ if (!Gbl.Usrs.Me.IBelongToCurrentCrs) return false; /***** 6. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 7. Fast / slow check depending on roles *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_NET: return Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (UsrDat); case Rol_TCH: return true; default: return false; } } /*****************************************************************************/ /******************* Check if I can view a user's agenda *********************/ /*****************************************************************************/ bool Usr_CheckIfICanViewUsrAgenda (struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 3. Fast check: Am I logged as system admin? *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) return true; /***** 4. Slow check: Get if user shares any course with me from database *****/ return Usr_CheckIfUsrSharesAnyOfMyCrs (UsrDat); } /*****************************************************************************/ /*************** Check if a user belongs to any of my courses ****************/ /*****************************************************************************/ void Usr_FlushCacheUsrSharesAnyOfMyCrs (void) { Gbl.Cache.UsrSharesAnyOfMyCrs.UsrCod = -1L; Gbl.Cache.UsrSharesAnyOfMyCrs.SharesAnyOfMyCrs = false; } bool Usr_CheckIfUsrSharesAnyOfMyCrs (struct UsrData *UsrDat) { bool ItsMe; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Fast check: It is a valid user code? *****/ if (UsrDat->UsrCod <= 0) return false; /***** 3. Fast check: It's me? *****/ ItsMe = Usr_ItsMe (UsrDat->UsrCod); if (ItsMe) return true; /***** 4. Fast check: Is already calculated if user shares any course with me? *****/ if (UsrDat->UsrCod == Gbl.Cache.UsrSharesAnyOfMyCrs.UsrCod) return Gbl.Cache.UsrSharesAnyOfMyCrs.SharesAnyOfMyCrs; /***** 5. Fast check: Is course selected and we both belong to it? *****/ if (Gbl.Usrs.Me.IBelongToCurrentCrs) if (Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat)) // Course selected and we both belong to it return true; /***** 6. Fast/slow check: Does he/she belong to any course? *****/ Rol_GetRolesInAllCrssIfNotYetGot (UsrDat); if (!(UsrDat->Roles.InCrss & ((1 << Rol_STD) | // Any of his/her roles is student (1 << Rol_NET) | // or non-editing teacher (1 << Rol_TCH)))) // or teacher? return false; /***** 7. Slow check: Get if user shares any course with me from database *****/ /* Fill the list with the courses I belong to (if not already filled) */ Usr_GetMyCourses (); /* Check if user shares any course with me */ Gbl.Cache.UsrSharesAnyOfMyCrs.UsrCod = UsrDat->UsrCod; Gbl.Cache.UsrSharesAnyOfMyCrs.SharesAnyOfMyCrs = (DB_QueryCOUNT ("can not check if a user shares any course with you", "SELECT COUNT(*) FROM crs_usr" " WHERE UsrCod=%ld" " AND CrsCod IN (SELECT CrsCod FROM my_courses_tmp)", UsrDat->UsrCod) != 0); return Gbl.Cache.UsrSharesAnyOfMyCrs.SharesAnyOfMyCrs; } /*****************************************************************************/ /*** Check if a user belongs to any of my courses but has a different role ***/ /*****************************************************************************/ bool Usr_CheckIfUsrSharesAnyOfMyCrsWithDifferentRole (long UsrCod) { bool UsrSharesAnyOfMyCrsWithDifferentRole; /***** 1. Fast check: Am I logged? *****/ if (!Gbl.Usrs.Me.Logged) return false; /***** 2. Slow check: Get if user shares any course with me with a different role, from database *****/ /* Fill the list with the courses I belong to (if not already filled) */ Usr_GetMyCourses (); /* Remove temporary table if exists */ DB_Query ("can not remove temporary tables", "DROP TEMPORARY TABLE IF EXISTS usr_courses_tmp"); /* Create temporary table with all user's courses for a role */ DB_Query ("can not create temporary table", "CREATE TEMPORARY TABLE IF NOT EXISTS usr_courses_tmp " "(CrsCod INT NOT NULL,Role TINYINT NOT NULL," "UNIQUE INDEX(CrsCod,Role)) ENGINE=MEMORY" " SELECT CrsCod,Role FROM crs_usr WHERE UsrCod=%ld", UsrCod); /* Get if a user shares any course with me from database */ UsrSharesAnyOfMyCrsWithDifferentRole = (DB_QueryCOUNT ("can not check if a user shares any course with you", "SELECT COUNT(*) FROM my_courses_tmp,usr_courses_tmp" " WHERE my_courses_tmp.CrsCod=usr_courses_tmp.CrsCod" " AND my_courses_tmp.Role<>usr_courses_tmp.Role") != 0); /* Remove temporary table if exists */ DB_Query ("can not remove temporary tables", "DROP TEMPORARY TABLE IF EXISTS usr_courses_tmp"); return UsrSharesAnyOfMyCrsWithDifferentRole; } /*****************************************************************************/ /**** Get all my countries (those of my courses) and store them in a list ****/ /*****************************************************************************/ void Usr_GetMyCountrs (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumCty; unsigned NumCtys; long CtyCod; /***** If my countries are yet filled, there's nothing to do *****/ if (!Gbl.Usrs.Me.MyCtys.Filled) { Gbl.Usrs.Me.MyCtys.Num = 0; /***** Get my institutions from database *****/ if ((NumCtys = (unsigned) Usr_GetCtysFromUsr (Gbl.Usrs.Me.UsrDat.UsrCod,&mysql_res)) > 0) // Countries found for (NumCty = 0; NumCty < NumCtys; NumCty++) { /* Get next country */ row = mysql_fetch_row (mysql_res); /* Get country code */ if ((CtyCod = Str_ConvertStrCodToLongCod (row[0])) > 0) { if (Gbl.Usrs.Me.MyCtys.Num == Cty_MAX_COUNTRS_PER_USR) Lay_ShowErrorAndExit ("Maximum number of countries of a user exceeded."); Gbl.Usrs.Me.MyCtys.Ctys[Gbl.Usrs.Me.MyCtys.Num].CtyCod = CtyCod; Gbl.Usrs.Me.MyCtys.Ctys[Gbl.Usrs.Me.MyCtys.Num].MaxRole = Rol_ConvertUnsignedStrToRole (row[1]); Gbl.Usrs.Me.MyCtys.Num++; } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Set boolean that indicates that my institutions are yet filled *****/ Gbl.Usrs.Me.MyCtys.Filled = true; } } /*****************************************************************************/ /** Get all my institutions (those of my courses) and store them in a list ***/ /*****************************************************************************/ void Usr_GetMyInstits (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumIns; unsigned NumInss; long InsCod; /***** If my institutions are yet filled, there's nothing to do *****/ if (!Gbl.Usrs.Me.MyInss.Filled) { Gbl.Usrs.Me.MyInss.Num = 0; /***** Get my institutions from database *****/ if ((NumInss = (unsigned) Usr_GetInssFromUsr (Gbl.Usrs.Me.UsrDat.UsrCod,-1L,&mysql_res)) > 0) // Institutions found for (NumIns = 0; NumIns < NumInss; NumIns++) { /* Get next institution */ row = mysql_fetch_row (mysql_res); /* Get institution code */ if ((InsCod = Str_ConvertStrCodToLongCod (row[0])) > 0) { if (Gbl.Usrs.Me.MyInss.Num == Ins_MAX_INSTITS_PER_USR) Lay_ShowErrorAndExit ("Maximum number of institutions of a user exceeded."); Gbl.Usrs.Me.MyInss.Inss[Gbl.Usrs.Me.MyInss.Num].InsCod = InsCod; Gbl.Usrs.Me.MyInss.Inss[Gbl.Usrs.Me.MyInss.Num].MaxRole = Rol_ConvertUnsignedStrToRole (row[1]); Gbl.Usrs.Me.MyInss.Num++; } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Set boolean that indicates that my institutions are yet filled *****/ Gbl.Usrs.Me.MyInss.Filled = true; } } /*****************************************************************************/ /***** Get all my centres (those of my courses) and store them in a list *****/ /*****************************************************************************/ void Usr_GetMyCentres (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumCtr; unsigned NumCtrs; long CtrCod; /***** If my centres are yet filled, there's nothing to do *****/ if (!Gbl.Usrs.Me.MyCtrs.Filled) { Gbl.Usrs.Me.MyCtrs.Num = 0; /***** Get my centres from database *****/ if ((NumCtrs = (unsigned) Usr_GetCtrsFromUsr (Gbl.Usrs.Me.UsrDat.UsrCod,-1L,&mysql_res)) > 0) // Centres found for (NumCtr = 0; NumCtr < NumCtrs; NumCtr++) { /* Get next centre */ row = mysql_fetch_row (mysql_res); /* Get centre code */ if ((CtrCod = Str_ConvertStrCodToLongCod (row[0])) > 0) { if (Gbl.Usrs.Me.MyCtrs.Num == Ctr_MAX_CENTRES_PER_USR) Lay_ShowErrorAndExit ("Maximum number of centres of a user exceeded."); Gbl.Usrs.Me.MyCtrs.Ctrs[Gbl.Usrs.Me.MyCtrs.Num].CtrCod = CtrCod; Gbl.Usrs.Me.MyCtrs.Ctrs[Gbl.Usrs.Me.MyCtrs.Num].MaxRole = Rol_ConvertUnsignedStrToRole (row[1]); Gbl.Usrs.Me.MyCtrs.Num++; } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Set boolean that indicates that my centres are yet filled *****/ Gbl.Usrs.Me.MyCtrs.Filled = true; } } /*****************************************************************************/ /***** Get all my degrees (those of my courses) and store them in a list *****/ /*****************************************************************************/ void Usr_GetMyDegrees (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumDeg; unsigned NumDegs; long DegCod; /***** If my degrees are yet filled, there's nothing to do *****/ if (!Gbl.Usrs.Me.MyDegs.Filled) { Gbl.Usrs.Me.MyDegs.Num = 0; /***** Get my degrees from database *****/ if ((NumDegs = (unsigned) Usr_GetDegsFromUsr (Gbl.Usrs.Me.UsrDat.UsrCod,-1L,&mysql_res)) > 0) // Degrees found for (NumDeg = 0; NumDeg < NumDegs; NumDeg++) { /* Get next degree */ row = mysql_fetch_row (mysql_res); /* Get degree code */ if ((DegCod = Str_ConvertStrCodToLongCod (row[0])) > 0) { if (Gbl.Usrs.Me.MyDegs.Num == Deg_MAX_DEGREES_PER_USR) Lay_ShowErrorAndExit ("Maximum number of degrees of a user exceeded."); Gbl.Usrs.Me.MyDegs.Degs[Gbl.Usrs.Me.MyDegs.Num].DegCod = DegCod; Gbl.Usrs.Me.MyDegs.Degs[Gbl.Usrs.Me.MyDegs.Num].MaxRole = Rol_ConvertUnsignedStrToRole (row[1]); Gbl.Usrs.Me.MyDegs.Num++; } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); /***** Set boolean that indicates that my degrees are yet filled *****/ Gbl.Usrs.Me.MyDegs.Filled = true; } } /*****************************************************************************/ /*************** Get all my courses and store them in a list *****************/ /*****************************************************************************/ void Usr_GetMyCourses (void) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumCrs; unsigned NumCrss; long CrsCod; /***** If my courses are yet filled, there's nothing to do *****/ if (!Gbl.Usrs.Me.MyCrss.Filled) { Gbl.Usrs.Me.MyCrss.Num = 0; if (Gbl.Usrs.Me.Logged) { /***** Remove temporary table with my courses *****/ Usr_RemoveTemporaryTableMyCourses (); /***** Create temporary table with my courses *****/ DB_Query ("can not create temporary table", "CREATE TEMPORARY TABLE IF NOT EXISTS my_courses_tmp " "(CrsCod INT NOT NULL," "Role TINYINT NOT NULL," "DegCod INT NOT NULL," "UNIQUE INDEX(CrsCod,Role,DegCod)) ENGINE=MEMORY" " SELECT crs_usr.CrsCod,crs_usr.Role,courses.DegCod" " FROM crs_usr,courses,degrees" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " ORDER BY degrees.ShortName,courses.ShortName", Gbl.Usrs.Me.UsrDat.UsrCod); /***** Get my courses from database *****/ NumCrss = (unsigned) DB_QuerySELECT (&mysql_res,"can not get which courses" " you belong to", "SELECT CrsCod,Role,DegCod" " FROM my_courses_tmp"); for (NumCrs = 0; NumCrs < NumCrss; NumCrs++) { /* Get next course */ row = mysql_fetch_row (mysql_res); /* Get course code */ if ((CrsCod = Str_ConvertStrCodToLongCod (row[0])) > 0) { if (Gbl.Usrs.Me.MyCrss.Num == Crs_MAX_COURSES_PER_USR) Lay_ShowErrorAndExit ("Maximum number of courses of a user exceeded."); Gbl.Usrs.Me.MyCrss.Crss[Gbl.Usrs.Me.MyCrss.Num].CrsCod = CrsCod; Gbl.Usrs.Me.MyCrss.Crss[Gbl.Usrs.Me.MyCrss.Num].Role = Rol_ConvertUnsignedStrToRole (row[1]); Gbl.Usrs.Me.MyCrss.Crss[Gbl.Usrs.Me.MyCrss.Num].DegCod = Str_ConvertStrCodToLongCod (row[2]); Gbl.Usrs.Me.MyCrss.Num++; } } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /***** Set boolean that indicates that my courses are yet filled *****/ Gbl.Usrs.Me.MyCrss.Filled = true; } } /*****************************************************************************/ /************************ Free the list of my countries ************************/ /*****************************************************************************/ void Usr_FreeMyCountrs (void) { if (Gbl.Usrs.Me.MyCtys.Filled) { /***** Reset list *****/ Gbl.Usrs.Me.MyCtys.Filled = false; Gbl.Usrs.Me.MyCtys.Num = 0; } } /*****************************************************************************/ /********************* Free the list of my institutions **********************/ /*****************************************************************************/ void Usr_FreeMyInstits (void) { if (Gbl.Usrs.Me.MyInss.Filled) { /***** Reset list *****/ Gbl.Usrs.Me.MyInss.Filled = false; Gbl.Usrs.Me.MyInss.Num = 0; } } /*****************************************************************************/ /************************ Free the list of my centres ************************/ /*****************************************************************************/ void Usr_FreeMyCentres (void) { if (Gbl.Usrs.Me.MyCtrs.Filled) { /***** Reset list *****/ Gbl.Usrs.Me.MyCtrs.Filled = false; Gbl.Usrs.Me.MyCtrs.Num = 0; } } /*****************************************************************************/ /************************ Free the list of my degrees ************************/ /*****************************************************************************/ void Usr_FreeMyDegrees (void) { if (Gbl.Usrs.Me.MyDegs.Filled) { /***** Reset list *****/ Gbl.Usrs.Me.MyDegs.Filled = false; Gbl.Usrs.Me.MyDegs.Num = 0; } } /*****************************************************************************/ /************************ Free the list of my courses ************************/ /*****************************************************************************/ void Usr_FreeMyCourses (void) { if (Gbl.Usrs.Me.MyCrss.Filled) { /***** Reset list *****/ Gbl.Usrs.Me.MyCrss.Filled = false; Gbl.Usrs.Me.MyCrss.Num = 0; /***** Remove temporary table with my courses *****/ Usr_RemoveTemporaryTableMyCourses (); } } /*****************************************************************************/ /************************ Free the list of my courses ************************/ /*****************************************************************************/ static void Usr_RemoveTemporaryTableMyCourses (void) { char Query[128]; /***** Remove temporary table with my courses *****/ sprintf (Query,"DROP TEMPORARY TABLE IF EXISTS my_courses_tmp"); if (mysql_query (&Gbl.mysql,Query)) DB_ExitOnMySQLError ("can not remove temporary table"); } /*****************************************************************************/ /**************** Check if a user belongs to an institution ******************/ /*****************************************************************************/ void Usr_FlushCacheUsrBelongsToIns (void) { Gbl.Cache.UsrBelongsToIns.UsrCod = -1L; Gbl.Cache.UsrBelongsToIns.InsCod = -1L; Gbl.Cache.UsrBelongsToIns.Belongs = false; } bool Usr_CheckIfUsrBelongsToIns (long UsrCod,long InsCod) { /***** 1. Fast check: Trivial case *****/ if (UsrCod <= 0 || InsCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrCod == Gbl.Cache.UsrBelongsToIns.UsrCod && InsCod != Gbl.Cache.UsrBelongsToIns.InsCod) return Gbl.Cache.UsrBelongsToIns.Belongs; /***** 3. Slow check: Get is user belongs to institution from database *****/ Gbl.Cache.UsrBelongsToIns.UsrCod = UsrCod; Gbl.Cache.UsrBelongsToIns.InsCod = InsCod; Gbl.Cache.UsrBelongsToIns.Belongs = (DB_QueryCOUNT ("can not check if a user belongs to an institution", "SELECT COUNT(DISTINCT centres.InsCod)" " FROM crs_usr,courses,degrees,centres" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.Accepted='Y'" // Only if user accepted " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " AND centres.InsCod=%ld", UsrCod,InsCod) != 0); return Gbl.Cache.UsrBelongsToIns.Belongs; } /*****************************************************************************/ /******************* Check if a user belongs to a centre *********************/ /*****************************************************************************/ void Usr_FlushCacheUsrBelongsToCtr (void) { Gbl.Cache.UsrBelongsToCtr.UsrCod = -1L; Gbl.Cache.UsrBelongsToCtr.CtrCod = -1L; Gbl.Cache.UsrBelongsToCtr.Belongs = false; } bool Usr_CheckIfUsrBelongsToCtr (long UsrCod,long CtrCod) { /***** 1. Fast check: Trivial case *****/ if (UsrCod <= 0 || CtrCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrCod == Gbl.Cache.UsrBelongsToCtr.UsrCod && CtrCod == Gbl.Cache.UsrBelongsToCtr.CtrCod) return Gbl.Cache.UsrBelongsToCtr.Belongs; /***** 3. Slow check: Get is user belongs to centre from database *****/ Gbl.Cache.UsrBelongsToCtr.UsrCod = UsrCod; Gbl.Cache.UsrBelongsToCtr.CtrCod = CtrCod; Gbl.Cache.UsrBelongsToCtr.Belongs = (DB_QueryCOUNT ("can not check if a user belongs to a centre", "SELECT COUNT(DISTINCT degrees.CtrCod)" " FROM crs_usr,courses,degrees" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.Accepted='Y'" // Only if user accepted " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=%ld", UsrCod,CtrCod) != 0); return Gbl.Cache.UsrBelongsToCtr.Belongs; } /*****************************************************************************/ /******************* Check if a user belongs to a degree *********************/ /*****************************************************************************/ void Usr_FlushCacheUsrBelongsToDeg (void) { Gbl.Cache.UsrBelongsToDeg.UsrCod = -1L; Gbl.Cache.UsrBelongsToDeg.DegCod = -1L; Gbl.Cache.UsrBelongsToDeg.Belongs = false; } bool Usr_CheckIfUsrBelongsToDeg (long UsrCod,long DegCod) { /***** 1. Fast check: Trivial case *****/ if (UsrCod <= 0 || DegCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrCod == Gbl.Cache.UsrBelongsToDeg.UsrCod && DegCod == Gbl.Cache.UsrBelongsToDeg.DegCod) return Gbl.Cache.UsrBelongsToDeg.Belongs; /***** 3. Slow check: Get if user belongs to degree from database *****/ Gbl.Cache.UsrBelongsToDeg.UsrCod = UsrCod; Gbl.Cache.UsrBelongsToDeg.DegCod = DegCod; Gbl.Cache.UsrBelongsToDeg.Belongs = (DB_QueryCOUNT ("can not check if a user belongs to a degree", "SELECT COUNT(DISTINCT courses.DegCod)" " FROM crs_usr,courses" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.Accepted='Y'" // Only if user accepted " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=%ld", UsrCod,DegCod) != 0); return Gbl.Cache.UsrBelongsToDeg.Belongs; } /*****************************************************************************/ /******************** Check if a user belongs to a course ********************/ /*****************************************************************************/ void Usr_FlushCacheUsrBelongsToCrs (void) { Gbl.Cache.UsrBelongsToCrs.UsrCod = -1L; Gbl.Cache.UsrBelongsToCrs.CrsCod = -1L; Gbl.Cache.UsrBelongsToCrs.CountOnlyAcceptedCourses = false; Gbl.Cache.UsrBelongsToCrs.Belongs = false; } bool Usr_CheckIfUsrBelongsToCrs (long UsrCod,long CrsCod, bool CountOnlyAcceptedCourses) { const char *SubQuery; /***** 1. Fast check: Trivial cases *****/ if (UsrCod <= 0 || CrsCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrCod == Gbl.Cache.UsrBelongsToCrs.UsrCod && CrsCod == Gbl.Cache.UsrBelongsToCrs.CrsCod && CountOnlyAcceptedCourses == Gbl.Cache.UsrBelongsToCrs.CountOnlyAcceptedCourses) return Gbl.Cache.UsrBelongsToCrs.Belongs; /***** 3. Slow check: Get if user belongs to course from database *****/ SubQuery = (CountOnlyAcceptedCourses ? " AND crs_usr.Accepted='Y'" : // Only if user accepted ""); Gbl.Cache.UsrBelongsToCrs.UsrCod = UsrCod; Gbl.Cache.UsrBelongsToCrs.CrsCod = CrsCod; Gbl.Cache.UsrBelongsToCrs.CountOnlyAcceptedCourses = CountOnlyAcceptedCourses; Gbl.Cache.UsrBelongsToCrs.Belongs = (DB_QueryCOUNT ("can not check if a user belongs to a course", "SELECT COUNT(*) FROM crs_usr" " WHERE CrsCod=%ld AND UsrCod=%ld%s", CrsCod,UsrCod,SubQuery) != 0); return Gbl.Cache.UsrBelongsToCrs.Belongs; } /*****************************************************************************/ /***** Check if user belongs (no matter if he/she has accepted or not) *******/ /***** to the current course *******/ /*****************************************************************************/ void Usr_FlushCacheUsrBelongsToCurrentCrs (void) { Gbl.Cache.UsrBelongsToCurrentCrs.UsrCod = -1L; Gbl.Cache.UsrBelongsToCurrentCrs.Belongs = false; } bool Usr_CheckIfUsrBelongsToCurrentCrs (const struct UsrData *UsrDat) { /***** 1. Fast check: Trivial cases *****/ if (UsrDat->UsrCod <= 0 || Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrDat->UsrCod == Gbl.Cache.UsrBelongsToCurrentCrs.UsrCod) return Gbl.Cache.UsrBelongsToCurrentCrs.Belongs; /***** 3. Fast check: If we know role of user in the current course *****/ if (UsrDat->Roles.InCurrentCrs.Valid) { Gbl.Cache.UsrBelongsToCurrentCrs.UsrCod = UsrDat->UsrCod; Gbl.Cache.UsrBelongsToCurrentCrs.Belongs = UsrDat->Roles.InCurrentCrs.Role == Rol_STD || UsrDat->Roles.InCurrentCrs.Role == Rol_NET || UsrDat->Roles.InCurrentCrs.Role == Rol_TCH; return Gbl.Cache.UsrBelongsToCurrentCrs.Belongs; } /***** 4. Fast / slow check: Get if user belongs to current course *****/ Gbl.Cache.UsrBelongsToCurrentCrs.UsrCod = UsrDat->UsrCod; Gbl.Cache.UsrBelongsToCurrentCrs.Belongs = Usr_CheckIfUsrBelongsToCrs (UsrDat->UsrCod, Gbl.Hierarchy.Crs.CrsCod, false); return Gbl.Cache.UsrBelongsToCurrentCrs.Belongs; } /*****************************************************************************/ /***** Check if user belongs (no matter if he/she has accepted or not) *******/ /***** to the current course *******/ /*****************************************************************************/ void Usr_FlushCacheUsrHasAcceptedInCurrentCrs (void) { Gbl.Cache.UsrHasAcceptedInCurrentCrs.UsrCod = -1L; Gbl.Cache.UsrHasAcceptedInCurrentCrs.Accepted = false; } bool Usr_CheckIfUsrHasAcceptedInCurrentCrs (const struct UsrData *UsrDat) { /***** 1. Fast check: Trivial cases *****/ if (UsrDat->UsrCod <= 0 || Gbl.Hierarchy.Crs.CrsCod <= 0) return false; /***** 2. Fast check: If cached... *****/ if (UsrDat->UsrCod == Gbl.Cache.UsrHasAcceptedInCurrentCrs.UsrCod) return Gbl.Cache.UsrHasAcceptedInCurrentCrs.Accepted; /***** 3. Fast / slow check: Get if user belongs to current course and has accepted *****/ Gbl.Cache.UsrHasAcceptedInCurrentCrs.UsrCod = UsrDat->UsrCod; Gbl.Cache.UsrHasAcceptedInCurrentCrs.Accepted = Usr_CheckIfUsrBelongsToCrs (UsrDat->UsrCod, Gbl.Hierarchy.Crs.CrsCod, true); return Gbl.Cache.UsrHasAcceptedInCurrentCrs.Accepted; } /*****************************************************************************/ /********************** Check if I belong to a country **********************/ /*****************************************************************************/ bool Usr_CheckIfIBelongToCty (long CtyCod) { unsigned NumMyCty; /***** Fill the list with the institutions I belong to *****/ Usr_GetMyCountrs (); /***** Check if the country passed as parameter is any of my countries *****/ for (NumMyCty = 0; NumMyCty < Gbl.Usrs.Me.MyCtys.Num; NumMyCty++) if (Gbl.Usrs.Me.MyCtys.Ctys[NumMyCty].CtyCod == CtyCod) return true; return false; } /*****************************************************************************/ /******************** Check if I belong to an institution ********************/ /*****************************************************************************/ bool Usr_CheckIfIBelongToIns (long InsCod) { unsigned NumMyIns; /***** Fill the list with the institutions I belong to *****/ Usr_GetMyInstits (); /***** Check if the institution passed as parameter is any of my institutions *****/ for (NumMyIns = 0; NumMyIns < Gbl.Usrs.Me.MyInss.Num; NumMyIns++) if (Gbl.Usrs.Me.MyInss.Inss[NumMyIns].InsCod == InsCod) return true; return false; } /*****************************************************************************/ /*********************** Check if I belong to a centre ***********************/ /*****************************************************************************/ bool Usr_CheckIfIBelongToCtr (long CtrCod) { unsigned NumMyCtr; /***** Fill the list with the centres I belong to *****/ Usr_GetMyCentres (); /***** Check if the centre passed as parameter is any of my centres *****/ for (NumMyCtr = 0; NumMyCtr < Gbl.Usrs.Me.MyCtrs.Num; NumMyCtr++) if (Gbl.Usrs.Me.MyCtrs.Ctrs[NumMyCtr].CtrCod == CtrCod) return true; return false; } /*****************************************************************************/ /*********************** Check if I belong to a degree ***********************/ /*****************************************************************************/ bool Usr_CheckIfIBelongToDeg (long DegCod) { unsigned NumMyDeg; /***** Fill the list with the degrees I belong to *****/ Usr_GetMyDegrees (); /***** Check if the degree passed as parameter is any of my degrees *****/ for (NumMyDeg = 0; NumMyDeg < Gbl.Usrs.Me.MyDegs.Num; NumMyDeg++) if (Gbl.Usrs.Me.MyDegs.Degs[NumMyDeg].DegCod == DegCod) return true; return false; } /*****************************************************************************/ /*********************** Check if I belong to a course ***********************/ /*****************************************************************************/ bool Usr_CheckIfIBelongToCrs (long CrsCod) { unsigned NumMyCrs; /***** Fill the list with the courses I belong to *****/ Usr_GetMyCourses (); /***** Check if the course passed as parameter is any of my courses *****/ for (NumMyCrs = 0; NumMyCrs < Gbl.Usrs.Me.MyCrss.Num; NumMyCrs++) if (Gbl.Usrs.Me.MyCrss.Crss[NumMyCrs].CrsCod == CrsCod) return true; return false; } /*****************************************************************************/ /**************** Get the countries of a user from database ******************/ /*****************************************************************************/ // Returns the number of rows of the result unsigned Usr_GetCtysFromUsr (long UsrCod,MYSQL_RES **mysql_res) { extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES]; /***** Get the institutions a user belongs to from database *****/ return (unsigned) DB_QuerySELECT (mysql_res,"can not get the countries" " a user belongs to", "SELECT countries.CtyCod,MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees," "centres," "institutions," "countries" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " AND centres.InsCod=institutions.InsCod" " AND institutions.CtyCod=countries.CtyCod" " GROUP BY countries.CtyCod" " ORDER BY countries.Name_%s", UsrCod,Lan_STR_LANG_ID[Gbl.Prefs.Language]); } /*****************************************************************************/ /************** Get the institutions of a user from database *****************/ /*****************************************************************************/ // Returns the number of rows of the result unsigned long Usr_GetInssFromUsr (long UsrCod,long CtyCod,MYSQL_RES **mysql_res) { /***** Get the institutions a user belongs to from database *****/ if (CtyCod > 0) return DB_QuerySELECT (mysql_res,"can not get the institutions" " a user belongs to", "SELECT institutions.InsCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees," "centres," "institutions" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " AND centres.InsCod=institutions.InsCod" " AND institutions.CtyCod=%ld" " GROUP BY institutions.InsCod" " ORDER BY institutions.ShortName", UsrCod,CtyCod); else return DB_QuerySELECT (mysql_res,"can not get the institutions" " a user belongs to", "SELECT institutions.InsCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees," "centres," "institutions" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " AND centres.InsCod=institutions.InsCod" " GROUP BY institutions.InsCod" " ORDER BY institutions.ShortName", UsrCod); } /*****************************************************************************/ /***************** Get the centres of a user from database *******************/ /*****************************************************************************/ // Returns the number of rows of the result unsigned long Usr_GetCtrsFromUsr (long UsrCod,long InsCod,MYSQL_RES **mysql_res) { /***** Get from database the centres a user belongs to *****/ if (InsCod > 0) return DB_QuerySELECT (mysql_res,"can not check the centres" " a user belongs to", "SELECT centres.CtrCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees," "centres" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " AND centres.InsCod=%ld" " GROUP BY centres.CtrCod" " ORDER BY centres.ShortName", UsrCod,InsCod); else return DB_QuerySELECT (mysql_res,"can not check the centres" " a user belongs to", "SELECT degrees.CtrCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees," "centres" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=centres.CtrCod" " GROUP BY centres.CtrCod" " ORDER BY centres.ShortName", UsrCod); } /*****************************************************************************/ /***************** Get the degrees of a user from database *******************/ /*****************************************************************************/ // Returns the number of rows of the result unsigned long Usr_GetDegsFromUsr (long UsrCod,long CtrCod,MYSQL_RES **mysql_res) { /***** Get from database the degrees a user belongs to *****/ if (CtrCod > 0) return DB_QuerySELECT (mysql_res,"can not check the degrees" " a user belongs to", "SELECT degrees.DegCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " AND degrees.CtrCod=%ld" " GROUP BY degrees.DegCod" " ORDER BY degrees.ShortName", UsrCod,CtrCod); else return DB_QuerySELECT (mysql_res,"can not check the degrees" " a user belongs to", "SELECT degrees.DegCod," "MAX(crs_usr.Role)" " FROM crs_usr," "courses," "degrees" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " GROUP BY degrees.DegCod" " ORDER BY degrees.ShortName", UsrCod); } /*****************************************************************************/ /************** Get all the courses of a user from database ******************/ /*****************************************************************************/ // Returns the number of rows of the result unsigned long Usr_GetCrssFromUsr (long UsrCod,long DegCod,MYSQL_RES **mysql_res) { /***** Get from database the courses a user belongs to *****/ if (DegCod > 0) // Courses in a degree return DB_QuerySELECT (mysql_res,"can not get the courses" " a user belongs to", "SELECT crs_usr.CrsCod," "crs_usr.Role," "courses.DegCod" " FROM crs_usr," "courses" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=%ld" " ORDER BY courses.ShortName", UsrCod,DegCod); else // All the courses return DB_QuerySELECT (mysql_res,"can not get the courses" " a user belongs to", "SELECT crs_usr.CrsCod," "crs_usr.Role," "courses.DegCod" " FROM crs_usr," "courses," "degrees" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " AND courses.DegCod=degrees.DegCod" " ORDER BY degrees.ShortName,courses.ShortName", UsrCod); } /*****************************************************************************/ /********* Get the degree in which a user is enroled in more courses *********/ /*****************************************************************************/ void Usr_GetMainDeg (long UsrCod, char ShrtName[Hie_MAX_BYTES_SHRT_NAME + 1], Rol_Role_t *MaxRole) { MYSQL_RES *mysql_res; MYSQL_ROW row; /***** Get a random student from current course from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get user's main degree", "SELECT degrees.ShortName," // row[0] "main_degree.MaxRole" // row[1] " FROM degrees," // The second table contain only one row with the main degree " (SELECT courses.DegCod AS DegCod," "MAX(crs_usr.Role) AS MaxRole," "COUNT(*) AS N" " FROM crs_usr,courses" " WHERE crs_usr.UsrCod=%ld" " AND crs_usr.CrsCod=courses.CrsCod" " GROUP BY courses.DegCod" " ORDER BY N DESC" // Ordered by number of courses in which user is enroled " LIMIT 1)" // We need only the main degree " AS main_degree" " WHERE degrees.DegCod=main_degree.DegCod", UsrCod)) { row = mysql_fetch_row (mysql_res); /* Get degree name (row[0]) */ Str_Copy (ShrtName,row[0], Hie_MAX_BYTES_SHRT_NAME); /* Get maximum role (row[1]) */ *MaxRole = Rol_ConvertUnsignedStrToRole (row[1]); } else // User is not enroled in any course { ShrtName[0] = '\0'; *MaxRole = Rol_UNK; } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /******** Check if a user exists with a given encrypted user's code **********/ /*****************************************************************************/ bool Usr_ChkIfEncryptedUsrCodExists (const char EncryptedUsrCod[Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64]) { /***** Get if an encrypted user's code already existed in database *****/ return (DB_QueryCOUNT ("can not check if an encrypted user's code" " already existed", "SELECT COUNT(*) FROM usr_data" " WHERE EncryptedUsrCod='%s'", EncryptedUsrCod) != 0); } /*****************************************************************************/ /***************************** Write landing page ****************************/ /*****************************************************************************/ void Usr_WriteLandingPage (void) { /***** Form to log in *****/ Usr_WriteFormLogin (ActLogIn,NULL); /***** Form to go to request the creation of a new account *****/ Acc_ShowFormGoToRequestNewAccount (); } /*****************************************************************************/ /************************ Write form for user log out ************************/ /*****************************************************************************/ void Usr_WriteFormLogout (void) { /***** Form to change my role *****/ Usr_ShowFormsLogoutAndRole (); /***** Show help to enrol me *****/ Hlp_ShowHelpWhatWouldYouLikeToDo (); } /*****************************************************************************/ /********************* Message and form shown after log out ******************/ /*****************************************************************************/ void Usr_Logout (void) { // extern const char *Txt_The_session_has_been_closed; /***** Confirmation message *****/ // Ale_ShowFixedAlert (Ale_INFO,Txt_The_session_has_been_closed); /***** Form to log in *****/ Usr_WriteFormLogin (ActLogIn,NULL); /***** Advertisement about mobile app *****/ Lay_AdvertisementMobile (); } /*****************************************************************************/ /*************************** Put link to log in ******************************/ /*****************************************************************************/ void Usr_PutLinkToLogin (void) { extern const char *Txt_Log_in; Lay_PutContextualLinkIconText (ActFrmLogIn,NULL,NULL, "sign-in-alt-green.svg", Txt_Log_in); } /*****************************************************************************/ /************************ Write form for user log in *************************/ /*****************************************************************************/ void Usr_WriteFormLogin (Act_Action_t NextAction,void (*FuncParams) (void)) { extern const char *Hlp_PROFILE_LogIn; extern const char *Txt_Log_in; extern const char *Txt_User[Usr_NUM_SEXS]; extern const char *Txt_nick_email_or_ID; extern const char *Txt_Password; extern const char *Txt_password; /***** Contextual menu *****/ Mnu_ContextMenuBegin (); Acc_PutLinkToCreateAccount (); // Create account Pwd_PutLinkToSendNewPasswd (); // Send new password Lan_PutLinkToChangeLanguage (); // Change language Mnu_ContextMenuEnd (); HTM_DIV_Begin ("class=\"CM\""); /***** Begin form *****/ Frm_StartForm (NextAction); if (FuncParams) FuncParams (); /***** Begin box and table *****/ Box_StartBoxTable (NULL,Txt_Log_in,NULL, Hlp_PROFILE_LogIn,Box_NOT_CLOSABLE,2); /***** User's ID/nickname *****/ HTM_DIV_Begin ("class=\"LM\""); fprintf (Gbl.F.Out,"