// 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;
/***** Links to other actions *****/
fprintf (Gbl.F.Out,"