swad-core/swad_photo.c

2595 lines
93 KiB
C
Raw Normal View History

2014-12-01 23:55:08 +01:00
// swad_photo.c: Users' photos management
/*
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.
2019-01-07 21:52:19 +01:00
Copyright (C) 1999-2019 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <linux/limits.h> // For PATH_MAX
#include <linux/stddef.h> // For NULL
#include <math.h> // For log10, floor, ceil, modf, sqrt...
#include <stdlib.h> // For system, getenv, etc.
#include <string.h> // For string functions
#include <sys/wait.h> // For the macro WEXITSTATUS
#include <unistd.h> // For unlink
#include "swad_action.h"
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2014-12-01 23:55:08 +01:00
#include "swad_config.h"
#include "swad_database.h"
2017-03-30 11:20:06 +02:00
#include "swad_enrolment.h"
2014-12-01 23:55:08 +01:00
#include "swad_file.h"
#include "swad_file_browser.h"
2019-02-22 14:04:54 +01:00
#include "swad_follow.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
2019-10-23 19:05:05 +02:00
#include "swad_HTML.h"
2015-01-17 20:06:25 +01:00
#include "swad_logo.h"
2014-12-01 23:55:08 +01:00
#include "swad_parameter.h"
#include "swad_photo.h"
2015-03-06 22:12:10 +01:00
#include "swad_privacy.h"
2019-03-26 11:53:21 +01:00
#include "swad_setting.h"
2014-12-01 23:55:08 +01:00
#include "swad_theme.h"
#include "swad_user.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
2015-03-06 14:11:11 +01:00
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
const char *Pho_StrAvgPhotoDirs[Pho_NUM_AVERAGE_PHOTO_TYPES] =
{
Cfg_FOLDER_DEGREE_PHOTO_MEDIAN,
Cfg_FOLDER_DEGREE_PHOTO_AVERAGE,
};
const char *Pho_StrAvgPhotoPrograms[Pho_NUM_AVERAGE_PHOTO_TYPES] =
{
Cfg_COMMAND_DEGREE_PHOTO_MEDIAN,
Cfg_COMMAND_DEGREE_PHOTO_AVERAGE,
};
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private variables *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
static void Pho_PutIconToRequestRemoveMyPhoto (void);
static void Pho_PutIconToRequestRemoveOtherUsrPhoto (void);
2016-04-11 18:54:23 +02:00
static void Pho_ReqOtherUsrPhoto (void);
2018-10-08 23:04:05 +02:00
static void Pho_ReqPhoto (const struct UsrData *UsrDat);
2016-04-11 18:54:23 +02:00
static bool Pho_ReceivePhotoAndDetectFaces (bool ItsMe,const struct UsrData *UsrDat);
2015-04-02 18:39:49 +02:00
2014-12-01 23:55:08 +01:00
static void Pho_UpdatePhoto1 (struct UsrData *UsrDat);
static void Pho_UpdatePhoto2 (void);
static void Pho_ClearPhotoName (long UsrCod);
static long Pho_GetDegWithAvgPhotoLeastRecentlyUpdated (void);
static long Pho_GetTimeAvgPhotoWasComputed (long DegCod);
static long Pho_GetTimeToComputeAvgPhoto (long DegCod);
2016-06-23 13:10:43 +02:00
static void Pho_ComputeAveragePhoto (long DegCod,Usr_Sex_t Sex,Rol_Role_t Role,
2014-12-01 23:55:08 +01:00
Pho_AvgPhotoTypeOfAverage_t TypeOfAverage,const char *DirAvgPhotosRelPath,
unsigned *NumStds,unsigned *NumStdsWithPhoto,long *TimeToComputeAvgPhotoInMicroseconds);
static void Pho_PutSelectorForTypeOfAvg (void);
static Pho_AvgPhotoTypeOfAverage_t Pho_GetPhotoAvgTypeFromForm (void);
static void Pho_PutSelectorForHowComputePhotoSize (void);
static Pho_HowComputePhotoSize_t Pho_GetHowComputePhotoSizeFromForm (void);
static void Pho_PutSelectorForHowOrderDegrees (void);
static Pho_HowOrderDegrees_t Pho_GetHowOrderDegreesFromForm (void);
2015-04-02 18:39:49 +02:00
2016-03-21 18:06:36 +01:00
static void Pho_PutIconToPrintDegreeStats (void);
2015-04-02 18:39:49 +02:00
static void Pho_PutLinkToPrintViewOfDegreeStatsParams (void);
2014-12-01 23:55:08 +01:00
static void Pho_PutLinkToCalculateDegreeStats (void);
static void Pho_GetMaxStdsPerDegree (void);
static void Pho_ShowOrPrintClassPhotoDegrees (Pho_AvgPhotoSeeOrPrint_t SeeOrPrint);
static void Pho_ShowOrPrintListDegrees (Pho_AvgPhotoSeeOrPrint_t SeeOrPrint);
2018-11-01 13:03:25 +01:00
static unsigned long Pho_BuildQueryOfDegrees (MYSQL_RES **mysql_res);
2014-12-01 23:55:08 +01:00
static void Pho_GetNumStdsInDegree (long DegCod,Usr_Sex_t Sex,int *NumStds,int *NumStdsWithPhoto);
static void Pho_UpdateDegStats (long DegCod,Usr_Sex_t Sex,unsigned NumStds,unsigned NumStdsWithPhoto,long TimeToComputeAvgPhoto);
static void Pho_ShowDegreeStat (int NumStds,int NumStdsWithPhoto);
2016-05-05 10:41:23 +02:00
static void Pho_ShowDegreeAvgPhotoAndStat (struct Degree *Deg,
Pho_AvgPhotoSeeOrPrint_t SeeOrPrint,
Usr_Sex_t Sex,
int NumStds,int NumStdsWithPhoto);
2014-12-01 23:55:08 +01:00
static void Pho_ComputePhotoSize (int NumStds,int NumStdsWithPhoto,unsigned *PhotoWidth,unsigned *PhotoHeight);
/*****************************************************************************/
/************** Check if I can change the photo of another user **************/
/*****************************************************************************/
2017-01-27 01:02:52 +01:00
bool Pho_ICanChangeOtherUsrPhoto (const struct UsrData *UsrDat)
2014-12-01 23:55:08 +01:00
{
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (UsrDat->UsrCod);
2018-10-10 14:03:06 +02:00
if (ItsMe)
2014-12-01 23:55:08 +01:00
return true;
2017-01-27 01:02:52 +01:00
/* Check if I have permission to change user's photo */
2017-06-04 18:18:54 +02:00
switch (Gbl.Usrs.Me.Role.Logged)
2014-12-01 23:55:08 +01:00
{
2017-05-18 19:13:41 +02:00
case Rol_TCH:
2017-05-22 14:52:11 +02:00
/* A teacher can change the photo of confirmed students */
2017-06-08 15:32:33 +02:00
if (UsrDat->Roles.InCurrentCrs.Role == Rol_STD && // A student
UsrDat->Accepted) // who accepted registration
2017-01-27 15:21:01 +01:00
return true;
return false;
2015-04-07 21:44:24 +02:00
case Rol_DEG_ADM:
2015-09-16 15:26:18 +02:00
case Rol_CTR_ADM:
case Rol_INS_ADM:
2015-04-07 21:44:24 +02:00
case Rol_SYS_ADM:
2017-01-28 18:08:06 +01:00
return Usr_ICanEditOtherUsr (UsrDat);
2014-12-01 23:55:08 +01:00
default:
return false;
}
}
/*****************************************************************************/
2015-01-01 19:39:46 +01:00
/********** Put a link to the action used to request user's photo ************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2018-10-16 01:36:13 +02:00
void Pho_PutIconToChangeUsrPhoto (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Change_photo;
extern const char *Txt_Upload_photo;
bool PhotoExists;
2017-01-28 15:58:46 +01:00
char PhotoURL[PATH_MAX + 1];
2016-07-01 16:32:42 +02:00
const char *TitleText;
2017-05-22 14:52:11 +02:00
Act_Action_t NextAction;
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (Gbl.Record.UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
/***** Link for changing / uploading the photo *****/
2018-10-10 14:03:06 +02:00
if (ItsMe)
2018-10-07 18:07:01 +02:00
{
TitleText = Gbl.Usrs.Me.MyPhotoExists ? Txt_Change_photo :
Txt_Upload_photo;
2019-01-12 03:00:59 +01:00
Lay_PutContextualLinkOnlyIcon (ActReqMyPho,NULL,NULL,
"camera.svg",
TitleText);
2018-10-07 18:07:01 +02:00
}
2018-10-10 14:03:06 +02:00
else // Not me
2018-10-07 18:07:01 +02:00
if (Pho_ICanChangeOtherUsrPhoto (Gbl.Record.UsrDat))
2015-04-03 00:55:40 +02:00
{
2018-10-07 18:07:01 +02:00
PhotoExists = Pho_BuildLinkToPhoto (Gbl.Record.UsrDat,PhotoURL);
2016-07-01 16:32:42 +02:00
TitleText = PhotoExists ? Txt_Change_photo :
Txt_Upload_photo;
2018-10-07 18:07:01 +02:00
switch (Gbl.Record.UsrDat->Roles.InCurrentCrs.Role)
2017-05-22 14:52:11 +02:00
{
case Rol_STD:
NextAction = ActReqStdPho;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActReqTchPho;
break;
default: // Guest, user or admin
NextAction = ActReqOthPho;
break;
}
2019-01-12 03:00:59 +01:00
Lay_PutContextualLinkOnlyIcon (NextAction,NULL,
Rec_PutParamUsrCodEncrypted,
"camera.svg",
TitleText);
2015-04-03 00:55:40 +02:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
/************** Put a link to request the removal of my photo ****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
static void Pho_PutIconToRequestRemoveMyPhoto (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Remove_photo;
2016-06-14 19:26:13 +02:00
/***** Link to request the removal of my photo *****/
2016-04-11 20:00:02 +02:00
if (Gbl.Usrs.Me.MyPhotoExists)
2019-01-12 03:00:59 +01:00
Lay_PutContextualLinkOnlyIcon (ActReqRemMyPho,NULL,NULL,
"trash.svg",
Txt_Remove_photo);
2015-04-02 18:39:49 +02:00
}
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
/********** Put a link to request the removal of a user's photo **************/
2015-04-02 18:39:49 +02:00
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
static void Pho_PutIconToRequestRemoveOtherUsrPhoto (void)
2015-04-02 18:39:49 +02:00
{
extern const char *Txt_Remove_photo;
2017-01-28 15:58:46 +01:00
char PhotoURL[PATH_MAX + 1];
2016-04-11 20:00:02 +02:00
bool PhotoExists;
2017-05-22 14:52:11 +02:00
Act_Action_t NextAction;
2015-04-02 18:39:49 +02:00
2016-06-14 19:26:13 +02:00
/***** Link to request the removal of another user's photo *****/
2016-07-08 12:43:48 +02:00
PhotoExists = Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
2016-04-11 20:00:02 +02:00
if (PhotoExists)
2017-05-22 14:52:11 +02:00
{
2017-06-08 15:32:33 +02:00
switch (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role)
2017-05-22 14:52:11 +02:00
{
case Rol_STD:
NextAction = ActReqRemStdPho;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActReqRemTchPho;
break;
default: // Guest, user or admin
NextAction = ActReqRemOthPho;
break;
}
2019-01-12 03:00:59 +01:00
Lay_PutContextualLinkOnlyIcon (NextAction,NULL,
Usr_PutParamOtherUsrCodEncrypted,
"trash.svg",
Txt_Remove_photo);
2017-05-22 14:52:11 +02:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************ Form for sending my photo **************************/
/*****************************************************************************/
2018-10-07 22:53:59 +02:00
void Pho_ReqMyPhoto (void)
2014-12-01 23:55:08 +01:00
{
2016-04-11 18:54:23 +02:00
/***** Show the form for sending the photo *****/
2018-10-08 23:04:05 +02:00
Pho_ReqPhoto (&Gbl.Usrs.Me.UsrDat);
2018-10-09 00:06:30 +02:00
/***** Show my record and other data *****/
2018-10-09 13:41:55 +02:00
Rec_ShowMySharedRecordAndMore ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Form for sending other user's photo *********************/
/*****************************************************************************/
2016-04-11 18:54:23 +02:00
static void Pho_ReqOtherUsrPhoto (void)
{
/***** Show the form to send another user's photo *****/
2018-10-08 23:04:05 +02:00
Pho_ReqPhoto (&Gbl.Usrs.Other.UsrDat);
/***** Show another user's record card *****/
2018-10-09 01:04:47 +02:00
Rec_ShowPublicSharedRecordOtherUsr ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Show a form for sending an user's photo ******************/
/*****************************************************************************/
2018-10-08 23:04:05 +02:00
static void Pho_ReqPhoto (const struct UsrData *UsrDat)
2014-12-01 23:55:08 +01:00
{
2016-11-13 01:02:08 +01:00
extern const char *Hlp_PROFILE_Photo;
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2015-04-03 00:55:40 +02:00
extern const char *Txt_Photo;
2016-11-10 12:38:41 +01:00
extern const char *Txt_You_can_send_a_file_with_an_image_in_JPEG_format_;
2014-12-01 23:55:08 +01:00
extern const char *Txt_File_with_the_photo;
extern const char *Txt_Upload_photo;
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (UsrDat->UsrCod);
2017-05-22 14:52:11 +02:00
Act_Action_t NextAction;
2016-04-11 20:00:02 +02:00
2017-06-12 14:16:33 +02:00
/***** Start box *****/
2018-10-09 00:48:43 +02:00
Box_StartBox (NULL,Txt_Photo,ItsMe ? Pho_PutIconToRequestRemoveMyPhoto :
Pho_PutIconToRequestRemoveOtherUsrPhoto,
2018-10-08 23:04:05 +02:00
Hlp_PROFILE_Photo,Box_NOT_CLOSABLE);
2014-12-01 23:55:08 +01:00
2019-10-20 22:00:28 +02:00
/***** Begin form *****/
2016-04-11 20:00:02 +02:00
if (ItsMe)
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActDetMyPho);
2014-12-01 23:55:08 +01:00
else
{
2017-06-08 15:32:33 +02:00
switch (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role)
2017-05-22 14:52:11 +02:00
{
case Rol_STD:
NextAction = ActDetStdPho;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActDetTchPho;
break;
default: // Guest, user or admin
NextAction = ActDetOthPho;
break;
}
2018-11-09 20:47:39 +01:00
Frm_StartForm (NextAction);
2015-04-02 18:39:49 +02:00
Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod);
2014-12-01 23:55:08 +01:00
}
2015-04-03 00:55:40 +02:00
2018-10-08 23:04:05 +02:00
/***** Show help message *****/
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_INFO,Txt_You_can_send_a_file_with_an_image_in_JPEG_format_);
2015-04-03 00:55:40 +02:00
/***** Form to upload photo *****/
2016-03-29 01:12:43 +02:00
fprintf (Gbl.F.Out,"<label class=\"%s\">"
2016-12-20 02:18:50 +01:00
"%s:&nbsp;"
2016-04-11 15:32:59 +02:00
"<input type=\"file\" name=\"%s\" accept=\"image/*\""
2016-12-20 02:18:50 +01:00
" onchange=\"document.getElementById('%s').submit();\" />"
"</label>",
2019-02-22 21:47:50 +01:00
The_ClassFormInBox[Gbl.Prefs.Theme],
2014-12-01 23:55:08 +01:00
Txt_File_with_the_photo,
Fil_NAME_OF_PARAM_FILENAME_ORG,
2016-03-29 01:12:43 +02:00
Gbl.Form.Id);
2015-04-03 00:55:40 +02:00
/***** End form *****/
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2016-04-11 20:00:02 +02:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2017-06-10 21:38:10 +02:00
Box_EndBox ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Send another user's photograph **********************/
/*****************************************************************************/
void Pho_SendPhotoUsr (void)
{
2018-10-10 14:03:06 +02:00
bool ItsMe;
2014-12-01 23:55:08 +01:00
/***** Get user whose photo must be sent or removed *****/
if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ())
{
2017-01-27 01:02:52 +01:00
if (Pho_ICanChangeOtherUsrPhoto (&Gbl.Usrs.Other.UsrDat)) // If I have permission to change user's photo...
2014-12-01 23:55:08 +01:00
{
2017-06-09 15:04:02 +02:00
Gbl.Usrs.Other.UsrDat.Accepted = Usr_CheckIfUsrHasAcceptedInCurrentCrs (&Gbl.Usrs.Other.UsrDat);
2018-10-10 23:56:42 +02:00
ItsMe = Usr_ItsMe (Gbl.Usrs.Other.UsrDat.UsrCod);
2018-10-10 14:03:06 +02:00
if (ItsMe)
2016-04-11 18:54:23 +02:00
/***** Form to send my photo *****/
2018-10-07 22:53:59 +02:00
Pho_ReqMyPhoto ();
2018-10-10 14:03:06 +02:00
else // Not me
2016-04-11 18:54:23 +02:00
/***** Form to send another user's photo *****/
2016-04-11 20:00:02 +02:00
Pho_ReqOtherUsrPhoto ();
2014-12-01 23:55:08 +01:00
}
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2014-12-01 23:55:08 +01:00
}
else // User not found
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Receive my photo and detect faces on it ********************/
/*****************************************************************************/
void Pho_RecMyPhotoDetFaces (void)
{
/***** Receive my photo and detect faces on it *****/
2016-04-11 18:54:23 +02:00
if (!Pho_ReceivePhotoAndDetectFaces (true,&Gbl.Usrs.Me.UsrDat))
2018-10-08 23:04:05 +02:00
Pho_ReqPhoto (&Gbl.Usrs.Me.UsrDat); // Request my photograph again
2018-10-09 00:06:30 +02:00
/***** Show my record and other data *****/
2018-10-09 13:41:55 +02:00
Rec_ShowMySharedRecordAndMore ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********** Receive another user's photo and detect faces on it **************/
/*****************************************************************************/
2016-04-11 18:54:23 +02:00
void Pho_RecOtherUsrPhotoDetFaces (void)
2014-12-01 23:55:08 +01:00
{
/***** Get user's code from form *****/
2016-01-25 14:40:57 +01:00
Usr_GetParamOtherUsrCodEncryptedAndGetListIDs ();
2014-12-01 23:55:08 +01:00
/***** Get password, user type and user's data from database *****/
2019-03-19 13:22:14 +01:00
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Usr_DONT_GET_PREFS))
2016-04-11 18:54:23 +02:00
{
2014-12-01 23:55:08 +01:00
/***** Receive photo *****/
2016-04-11 18:54:23 +02:00
if (!Pho_ReceivePhotoAndDetectFaces (false,&Gbl.Usrs.Other.UsrDat))
2018-10-08 23:04:05 +02:00
Pho_ReqPhoto (&Gbl.Usrs.Other.UsrDat); // Request user's photograph again
/***** Show another user's record card *****/
2018-10-09 01:04:47 +02:00
Rec_ShowPublicSharedRecordOtherUsr ();
2016-04-11 18:54:23 +02:00
}
2014-12-01 23:55:08 +01:00
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2014-12-01 23:55:08 +01:00
}
2016-06-14 19:26:13 +02:00
/*****************************************************************************/
/********************** Request the removal of my photo **********************/
/*****************************************************************************/
void Pho_ReqRemoveMyPhoto (void)
{
extern const char *Txt_Do_you_really_want_to_remove_your_photo;
extern const char *Txt_Remove_photo;
extern const char *Txt_The_photo_no_longer_exists;
/***** Show current photo and help message *****/
2016-07-08 12:43:48 +02:00
if (Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,Gbl.Usrs.Me.PhotoURL))
2016-06-14 19:26:13 +02:00
{
2017-04-27 15:02:00 +02:00
/***** Show question and button to remove my photo *****/
/* Start alert */
2017-05-11 23:45:46 +02:00
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_remove_your_photo);
2016-06-14 19:26:13 +02:00
2017-04-27 15:02:00 +02:00
/* Show current photo */
2016-06-14 19:26:13 +02:00
Pho_ShowUsrPhoto (&Gbl.Usrs.Me.UsrDat,Gbl.Usrs.Me.PhotoURL,
"PHOTO186x248",Pho_NO_ZOOM,false);
2017-04-27 15:02:00 +02:00
/* End alert */
2017-05-25 14:25:22 +02:00
Ale_ShowAlertAndButton2 (ActRemMyPho,NULL,NULL,NULL,
2017-06-11 19:02:40 +02:00
Btn_REMOVE_BUTTON,Txt_Remove_photo);
2016-06-14 19:26:13 +02:00
}
else
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_INFO,Txt_The_photo_no_longer_exists);
2018-10-09 01:04:47 +02:00
/***** Show my record and other data *****/
2018-10-09 13:41:55 +02:00
Rec_ShowMySharedRecordAndMore ();
2016-06-14 19:26:13 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/****************************** Remove my photo ******************************/
/*****************************************************************************/
void Pho_RemoveMyPhoto1 (void)
{
/***** Remove photo *****/
2017-05-09 20:56:02 +02:00
Pho_RemovePhoto (&Gbl.Usrs.Me.UsrDat);
2014-12-01 23:55:08 +01:00
/***** The link to my photo is not valid now, so build it again before writing the web page *****/
2016-07-08 12:43:48 +02:00
Gbl.Usrs.Me.MyPhotoExists = Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,Gbl.Usrs.Me.PhotoURL);
2014-12-01 23:55:08 +01:00
}
void Pho_RemoveMyPhoto2 (void)
{
2017-05-09 20:56:02 +02:00
/***** Write success / warning message *****/
2019-03-09 20:12:44 +01:00
Ale_ShowAlerts (NULL);
2018-10-09 01:04:47 +02:00
/***** Show my record and other data *****/
2018-10-09 13:41:55 +02:00
Rec_ShowMySharedRecordAndMore ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-06-14 19:26:13 +02:00
/**************** Request the removal of another user's photo ****************/
/*****************************************************************************/
void Pho_ReqRemoveUsrPhoto (void)
{
extern const char *Txt_Photo;
extern const char *Txt_Do_you_really_want_to_remove_the_photo_of_X;
extern const char *Txt_Remove_photo;
extern const char *Txt_The_photo_no_longer_exists;
2017-01-28 15:58:46 +01:00
char PhotoURL[PATH_MAX + 1];
2017-05-22 14:52:11 +02:00
Act_Action_t NextAction;
2016-06-14 19:26:13 +02:00
/***** Get user's code from form *****/
Usr_GetParamOtherUsrCodEncryptedAndGetListIDs ();
/***** Get password, user type and user's data from database *****/
2019-03-19 13:22:14 +01:00
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Usr_DONT_GET_PREFS))
2016-06-14 19:26:13 +02:00
{
2017-01-27 01:02:52 +01:00
if (Pho_ICanChangeOtherUsrPhoto (&Gbl.Usrs.Other.UsrDat))
2016-06-14 19:26:13 +02:00
{
/***** Show current photo and help message *****/
2016-07-08 12:43:48 +02:00
if (Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL))
2016-06-14 19:26:13 +02:00
{
2017-04-28 13:28:05 +02:00
/***** Show question and button to remove user's photo *****/
/* Start alert */
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_photo_of_X,
Gbl.Usrs.Other.UsrDat.FullName);
2017-04-28 13:28:05 +02:00
/* Show current photo */
2016-06-14 19:26:13 +02:00
Pho_ShowUsrPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL,
"PHOTO186x248",Pho_NO_ZOOM,false);
2017-04-28 13:28:05 +02:00
/* End alert */
2017-06-08 15:32:33 +02:00
switch (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role)
2017-05-22 14:52:11 +02:00
{
case Rol_STD:
NextAction = ActRemStdPho;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActRemTchPho;
break;
default: // Guest, user or admin
NextAction = ActRemOthPho;
break;
}
2017-05-25 14:25:22 +02:00
Ale_ShowAlertAndButton2 (NextAction,NULL,NULL,
2017-05-22 14:52:11 +02:00
Usr_PutParamOtherUsrCodEncrypted,
2017-06-11 19:02:40 +02:00
Btn_REMOVE_BUTTON,Txt_Remove_photo);
2016-06-14 19:26:13 +02:00
}
else
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_INFO,Txt_The_photo_no_longer_exists);
2016-06-14 19:26:13 +02:00
}
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2016-06-14 19:26:13 +02:00
}
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2018-10-09 01:04:47 +02:00
/***** Show another user's record card *****/
Rec_ShowPublicSharedRecordOtherUsr ();
2016-06-14 19:26:13 +02:00
}
/*****************************************************************************/
2014-12-01 23:55:08 +01:00
/************************ Remove another user's photo ************************/
/*****************************************************************************/
void Pho_RemoveUsrPhoto (void)
{
/***** Get user's code from form *****/
2016-01-25 14:40:57 +01:00
Usr_GetParamOtherUsrCodEncryptedAndGetListIDs ();
2014-12-01 23:55:08 +01:00
/***** Get password, user type and user's data from database *****/
2019-03-19 13:22:14 +01:00
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Usr_DONT_GET_PREFS))
2014-12-01 23:55:08 +01:00
{
/***** Remove photo *****/
if (Pho_RemovePhoto (&Gbl.Usrs.Other.UsrDat))
2019-03-09 20:12:44 +01:00
Ale_ShowAlerts (NULL);
2014-12-01 23:55:08 +01:00
}
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2018-10-09 01:04:47 +02:00
/***** Show another user's record card *****/
Rec_ShowPublicSharedRecordOtherUsr ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Receive a photo and detect faces on it ********************/
/*****************************************************************************/
2016-04-11 18:54:23 +02:00
// Return false if no "green" faces detected
2014-12-01 23:55:08 +01:00
2016-04-11 18:54:23 +02:00
static bool Pho_ReceivePhotoAndDetectFaces (bool ItsMe,const struct UsrData *UsrDat)
2014-12-01 23:55:08 +01:00
{
2015-01-14 00:32:23 +01:00
extern const char *Txt_The_file_is_not_X;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Could_not_detect_any_face_in_front_position_;
extern const char *Txt_A_face_marked_in_green_has_been_detected_;
extern const char *Txt_A_face_marked_in_red_has_been_detected_;
extern const char *Txt_X_faces_marked_in_green_have_been_detected_;
extern const char *Txt_X_faces_marked_in_red_have_been_detected_;
extern const char *Txt_X_faces_have_been_detected_in_front_position_1_Z_;
extern const char *Txt_X_faces_have_been_detected_in_front_position_Y_Z_;
2015-07-22 13:32:56 +02:00
extern const char *Txt_Faces_detected;
2017-01-15 18:02:52 +01:00
char PathPhotosPriv[PATH_MAX + 1];
2016-04-01 01:59:27 +02:00
struct Param *Param;
2017-01-15 18:02:52 +01:00
char FileNamePhotoSrc[PATH_MAX + 1];
char FileNamePhotoTmp[PATH_MAX + 1]; // Full name (including path and .jpg) of the destination temporary file
char FileNamePhotoMap[PATH_MAX + 1]; // Full name (including path) of the temporary file with the original image with faces
char FileNameTxtMap[PATH_MAX + 1]; // Full name (including path) of the temporary file with the text neccesary to make the image map
char PathRelPhoto[PATH_MAX + 1];
FILE *FileTxtMap = NULL; // Temporary file with the text neccesary to make the image map. Initialized to avoid warning
char MIMEType[Brw_MAX_BYTES_MIME_TYPE + 1];
2014-12-01 23:55:08 +01:00
bool WrongType = false;
2017-01-15 18:02:52 +01:00
char Command[256 + PATH_MAX]; // Command to call the program of preprocessing of photos
2014-12-01 23:55:08 +01:00
int ReturnCode;
2015-09-16 15:26:18 +02:00
int NumLastForm = 0; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
char FormId[32];
unsigned NumFacesTotal = 0;
unsigned NumFacesGreen = 0;
unsigned NumFacesRed = 0;
unsigned NumFace;
unsigned X;
unsigned Y;
unsigned Radius;
unsigned BackgroundCode;
2017-01-15 18:02:52 +01:00
char StrFileName[NAME_MAX + 1];
2017-05-22 14:52:11 +02:00
Act_Action_t NextAction;
2019-02-17 01:14:55 +01:00
char ErrorTxt[256];
2014-12-01 23:55:08 +01:00
/***** Creates directories if not exist *****/
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_PHOTO_PRIVATE);
2018-10-18 02:02:32 +02:00
snprintf (PathPhotosPriv,sizeof (PathPhotosPriv),
2019-03-20 01:36:36 +01:00
"%s/%02u",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100));
2014-12-01 23:55:08 +01:00
Fil_CreateDirIfNotExists (PathPhotosPriv);
2016-03-28 19:30:37 +02:00
/***** Create directories if not exists
and remove old temporary files *****/
/* Create public directory for photos */
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_PHOTO_PUBLIC);
2016-03-28 19:30:37 +02:00
/* Create temporary directory for photos */
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_PHOTO_TMP_PUBLIC);
2014-12-01 23:55:08 +01:00
/***** First of all, copy in disk the file received from stdin (really from Gbl.F.Tmp) *****/
2016-04-04 12:13:37 +02:00
Param = Fil_StartReceptionOfFile (Fil_NAME_OF_PARAM_FILENAME_ORG,
FileNamePhotoSrc,MIMEType);
2014-12-01 23:55:08 +01:00
/* Check if the file type is image/jpeg or image/pjpeg or application/octet-stream */
if (strcmp (MIMEType,"image/jpeg"))
if (strcmp (MIMEType,"image/pjpeg"))
if (strcmp (MIMEType,"application/octet-stream"))
if (strcmp (MIMEType,"application/octetstream"))
if (strcmp (MIMEType,"application/octet"))
WrongType = true;
if (WrongType)
{
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_WARNING,Txt_The_file_is_not_X,
"jpg");
2016-04-11 18:54:23 +02:00
return false;
2014-12-01 23:55:08 +01:00
}
/* End the reception of photo in a temporary file */
2018-10-18 02:02:32 +02:00
snprintf (FileNamePhotoTmp,sizeof (FileNamePhotoTmp),
2019-03-20 01:36:36 +01:00
"%s/%s.jpg",
Cfg_PATH_PHOTO_TMP_PUBLIC,
Gbl.UniqueNameEncrypted);
2016-04-01 01:59:27 +02:00
if (!Fil_EndReceptionOfFile (FileNamePhotoTmp,Param))
2014-12-01 23:55:08 +01:00
{
2019-02-16 18:11:52 +01:00
Ale_ShowAlert (Ale_ERROR,"Error copying file.");
2016-04-11 18:54:23 +02:00
return false;
2014-12-01 23:55:08 +01:00
}
/* Copy the original photo received to private directory.
The purpose of this copy is only to have a backup used for researching better methods to detect faces in images */
2018-10-18 02:02:32 +02:00
snprintf (PathRelPhoto,sizeof (PathRelPhoto),
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld_original.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100),UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
Fil_FastCopyOfFiles (FileNamePhotoTmp,PathRelPhoto);
/***** Call to program that makes photo processing / face detection *****/
2018-10-18 02:02:32 +02:00
snprintf (Command,sizeof (Command),
Cfg_COMMAND_FACE_DETECTION,
FileNamePhotoTmp);
2014-12-01 23:55:08 +01:00
ReturnCode = system (Command);
if (ReturnCode == -1)
Lay_ShowErrorAndExit ("Error when running command to process photo and detect faces.");
/***** Write message depending on return code *****/
ReturnCode = WEXITSTATUS(ReturnCode);
switch (ReturnCode)
{
case 0: // Faces detected
/***** Open text file with text for image map *****/
2018-10-18 02:02:32 +02:00
snprintf (FileNameTxtMap,sizeof (FileNameTxtMap),
2019-03-20 01:36:36 +01:00
"%s/%s_map.txt",
Cfg_PATH_PHOTO_TMP_PUBLIC,
Gbl.UniqueNameEncrypted);
2014-12-01 23:55:08 +01:00
if ((FileTxtMap = fopen (FileNameTxtMap,"rb")) == NULL)
Lay_ShowErrorAndExit ("Can not read text file with coordinates of detected faces.");
/***** Read file with coordinates for image map and compute the number of faces *****/
2016-01-14 10:31:09 +01:00
NumLastForm = Gbl.Form.Num;
2014-12-01 23:55:08 +01:00
while (!feof (FileTxtMap))
{
if (fscanf (FileTxtMap,"%u %u %u %u %s\n",&X,&Y,&Radius,&BackgroundCode,StrFileName) != 5) // Example of StrFileName = "4924a838630e_016"
break;
if (BackgroundCode == 1)
{
NumFacesGreen++;
2017-05-22 14:52:11 +02:00
if (ItsMe)
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActUpdMyPho);
2017-05-22 14:52:11 +02:00
else
{
2017-06-08 15:32:33 +02:00
switch (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role)
2017-05-22 14:52:11 +02:00
{
case Rol_STD:
NextAction = ActUpdStdPho;
break;
case Rol_NET:
case Rol_TCH:
NextAction = ActUpdTchPho;
break;
default: // Guest, user or admin
NextAction = ActUpdOthPho;
break;
}
2018-11-09 20:47:39 +01:00
Frm_StartForm (NextAction);
2015-04-02 18:39:49 +02:00
Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod);
2017-05-22 14:52:11 +02:00
}
2014-12-01 23:55:08 +01:00
Par_PutHiddenParamString ("FileName",StrFileName);
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
}
else
NumFacesRed++;
}
NumFacesTotal = NumFacesGreen + NumFacesRed;
break;
case 1: // No faces detected
NumFacesTotal = NumFacesGreen = NumFacesRed = 0;
break;
default: // Error
2019-02-17 01:14:55 +01:00
snprintf (ErrorTxt,sizeof (ErrorTxt),
2018-10-16 21:56:01 +02:00
"Photo could not be processed successfully.<br />"
"Error code returned by the program of processing: %d",
ReturnCode);
2019-02-17 01:14:55 +01:00
Lay_ShowErrorAndExit (ErrorTxt);
2014-12-01 23:55:08 +01:00
break;
}
2019-02-17 01:14:55 +01:00
/***** Start alert to the user about the number of faces detected in the image*****/
2014-12-01 23:55:08 +01:00
if (NumFacesTotal == 0)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_WARNING,Txt_Could_not_detect_any_face_in_front_position_);
2014-12-01 23:55:08 +01:00
else if (NumFacesTotal == 1)
{
if (NumFacesGreen == 1)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_SUCCESS,Txt_A_face_marked_in_green_has_been_detected_);
2014-12-01 23:55:08 +01:00
else
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_WARNING,Txt_A_face_marked_in_red_has_been_detected_);
2014-12-01 23:55:08 +01:00
}
else // NumFacesTotal > 1
{
if (NumFacesRed == 0)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_SUCCESS,Txt_X_faces_marked_in_green_have_been_detected_,
NumFacesGreen);
2014-12-01 23:55:08 +01:00
else if (NumFacesGreen == 0)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_WARNING,Txt_X_faces_marked_in_red_have_been_detected_,
NumFacesRed);
2014-12-01 23:55:08 +01:00
else // NumFacesGreen > 0
{
if (NumFacesGreen == 1)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_SUCCESS,Txt_X_faces_have_been_detected_in_front_position_1_Z_,
NumFacesTotal,NumFacesRed);
2014-12-01 23:55:08 +01:00
else
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton1 (Ale_SUCCESS,Txt_X_faces_have_been_detected_in_front_position_Y_Z_,
NumFacesTotal,NumFacesGreen,NumFacesRed);
2014-12-01 23:55:08 +01:00
}
}
/***** Create map *****/
fprintf (Gbl.F.Out,"<map name=\"faces_map\">\n");
if (NumFacesTotal)
{
/***** Read again the file with coordinates and create area shapes *****/
rewind (FileTxtMap);
for (NumFace = 0; !feof (FileTxtMap);)
{
if (fscanf (FileTxtMap,"%u %u %u %u %s\n",&X,&Y,&Radius,&BackgroundCode,StrFileName) != 5)
break;
if (BackgroundCode == 1)
{
NumFace++;
2018-10-18 02:02:32 +02:00
snprintf (FormId,sizeof (FormId),
"form_%d",
NumLastForm + NumFace);
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"<area shape=\"circle\""
2015-11-03 12:20:57 +01:00
" href=\"javascript:document.getElementById('%s').submit();\""
2014-12-01 23:55:08 +01:00
" coords=\"%u,%u,%u\">\n",
FormId,X,Y,Radius);
}
}
/***** Close text file with text for image map *****/
fclose (FileTxtMap);
}
fprintf (Gbl.F.Out,"</map>\n");
/***** Show map photo *****/
2018-10-18 02:02:32 +02:00
snprintf (FileNamePhotoMap,sizeof (FileNamePhotoMap),
2019-03-20 01:36:36 +01:00
"%s/%s_map.jpg",
Cfg_PATH_PHOTO_TMP_PUBLIC,
2018-10-18 02:02:32 +02:00
Gbl.UniqueNameEncrypted);
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"TIT CM\"");
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"<img src=\"%s/%s_map.jpg\""
2015-07-22 13:32:56 +02:00
" usemap=\"#faces_map\""
2019-10-23 20:07:56 +02:00
" alt=\"%s\" title=\"%s\" />",
2019-03-20 01:36:36 +01:00
Cfg_URL_PHOTO_TMP_PUBLIC,
2015-07-22 13:32:56 +02:00
Gbl.UniqueNameEncrypted,
Txt_Faces_detected,Txt_Faces_detected);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2016-04-11 18:54:23 +02:00
2018-10-08 23:04:05 +02:00
/***** End alert *****/
Ale_ShowAlertAndButton2 (ActUnk,NULL,NULL,NULL,Btn_NO_BUTTON,NULL);
2016-04-11 18:54:23 +02:00
/***** Button to send another photo *****/
return (NumFacesGreen != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************************** Update my photo *******************************/
/*****************************************************************************/
void Pho_UpdateMyPhoto1 (void)
{
Pho_UpdatePhoto1 (&Gbl.Usrs.Me.UsrDat);
/***** The link to my photo is not valid now, so build it again before writing the web page *****/
2016-07-08 12:43:48 +02:00
Gbl.Usrs.Me.MyPhotoExists = Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,Gbl.Usrs.Me.PhotoURL);
2014-12-01 23:55:08 +01:00
}
void Pho_UpdateMyPhoto2 (void)
{
Pho_UpdatePhoto2 ();
2018-10-08 23:04:05 +02:00
2018-10-09 00:06:30 +02:00
/***** Show my record and other data *****/
2018-10-09 13:41:55 +02:00
Rec_ShowMySharedRecordAndMore ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Update another user's photo *************************/
/*****************************************************************************/
void Pho_UpdateUsrPhoto1 (void)
{
/***** Get user's code from form and user's data *****/
if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ())
Pho_UpdatePhoto1 (&Gbl.Usrs.Other.UsrDat);
else
2019-03-09 20:12:44 +01:00
Ale_ShowAlertUserNotFoundOrYouDoNotHavePermission ();
2014-12-01 23:55:08 +01:00
}
void Pho_UpdateUsrPhoto2 (void)
{
Pho_UpdatePhoto2 ();
2018-10-08 23:04:05 +02:00
/***** Show another user's record card *****/
2018-10-09 01:04:47 +02:00
Rec_ShowPublicSharedRecordOtherUsr ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Update a user's photo with a selected face ******************/
/*****************************************************************************/
static void Pho_UpdatePhoto1 (struct UsrData *UsrDat)
{
2017-05-09 20:56:02 +02:00
extern const char *Txt_Photo_has_been_updated;
2017-01-28 15:58:46 +01:00
char PathPhotoTmp[PATH_MAX + 1]; // Full name (including path and .jpg) of the temporary file with the selected face
char PathRelPhoto[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
/***** Get the name of the file with the selected face *****/
Par_GetParToText ("FileName",Gbl.Usrs.FileNamePhoto,NAME_MAX); // Example of FileNamePhoto: "4924a838630e_016"
/***** Convert the temporary photo resulting of the processing to the current photo of the user *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPhotoTmp,sizeof (PathPhotoTmp),
2019-03-20 01:36:36 +01:00
"%s/%s_paso3.jpg",
Cfg_PATH_PHOTO_TMP_PUBLIC,
Gbl.Usrs.FileNamePhoto);
2014-12-01 23:55:08 +01:00
if (Fil_CheckIfPathExists (PathPhotoTmp)) // The file with the selected photo exists
{
/* Copy the temporary file of the third (last) step resulting of the processing to the directory of private photos */
2018-10-18 02:02:32 +02:00
snprintf (PathRelPhoto,sizeof (PathRelPhoto),
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100),UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
Fil_FastCopyOfFiles (PathPhotoTmp,PathRelPhoto);
/* Update public photo name in database */
Pho_UpdatePhotoName (UsrDat);
/* Remove the user from the list of users without photo */
2014-12-12 22:39:55 +01:00
Pho_RemoveUsrFromTableClicksWithoutPhoto (UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_Photo_has_been_updated);
2014-12-01 23:55:08 +01:00
}
else
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_ERROR,NULL,
"Error updating photo.");
2014-12-01 23:55:08 +01:00
}
static void Pho_UpdatePhoto2 (void)
{
extern const char *Txt_PHOTO_PROCESSING_CAPTIONS[3];
unsigned NumPhoto;
2018-10-08 23:04:05 +02:00
/***** Start alert *****/
2019-03-09 20:12:44 +01:00
Ale_ShowLastAlertAndButton1 ();
2018-10-08 23:04:05 +02:00
2014-12-01 23:55:08 +01:00
/***** Show the three images resulting of the processing *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginWide ();
HTM_TR_Begin (NULL);
2014-12-01 23:55:08 +01:00
for (NumPhoto = 0;
NumPhoto < 3;
NumPhoto++)
2019-10-07 17:36:41 +02:00
{
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CT\" style=\"width:33%%;\"");
2019-10-09 15:44:12 +02:00
fprintf (Gbl.F.Out,"<img src=\"%s/%s_paso%u.jpg\""
2015-07-22 13:32:56 +02:00
" alt=\"%s\" title=\"%s\""
2015-09-24 18:02:21 +02:00
" style=\"width:%upx; height:%upx;\" />"
2019-10-07 17:36:41 +02:00
"<br />%s",
2019-03-20 01:36:36 +01:00
Cfg_URL_PHOTO_TMP_PUBLIC,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.FileNamePhoto,NumPhoto + 1,
2015-07-22 13:32:56 +02:00
Txt_PHOTO_PROCESSING_CAPTIONS[NumPhoto],
Txt_PHOTO_PROCESSING_CAPTIONS[NumPhoto],
2015-09-24 18:02:21 +02:00
Pho_PHOTO_REAL_WIDTH,Pho_PHOTO_REAL_HEIGHT,
2014-12-01 23:55:08 +01:00
Txt_PHOTO_PROCESSING_CAPTIONS[NumPhoto]);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
}
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
2018-10-08 23:04:05 +02:00
/***** End alert *****/
Ale_ShowAlertAndButton2 (ActUnk,NULL,NULL,NULL,Btn_NO_BUTTON,NULL);
2014-12-01 23:55:08 +01:00
}
2014-12-12 22:39:55 +01:00
/*****************************************************************************/
/******************* Update number of clicks without photo *******************/
/*****************************************************************************/
unsigned Pho_UpdateMyClicksWithoutPhoto (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
unsigned NumClicks;
/***** Get number of clicks without photo from database *****/
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get number of clicks"
" without photo",
"SELECT NumClicks FROM clicks_without_photo"
" WHERE UsrCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-12 22:39:55 +01:00
/***** Update the list of clicks without photo *****/
if (NumRows) // The user exists ==> update number of clicks without photo
{
/* Get current number of clicks */
row = mysql_fetch_row (mysql_res);
sscanf (row[0],"%u",&NumClicks);
/* Update number of clicks */
if (NumClicks <= Pho_MAX_CLICKS_WITHOUT_PHOTO)
{
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update number of clicks without photo",
"UPDATE clicks_without_photo"
" SET NumClicks=NumClicks+1 WHERE UsrCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-12 22:39:55 +01:00
NumClicks++;
}
}
else // The user does not exist ==> add him/her
{
/* Add the user, with one access */
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create number of clicks without photo",
"INSERT INTO clicks_without_photo"
" (UsrCod,NumClicks)"
" VALUES"
" (%ld,1)",
Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-12 22:39:55 +01:00
NumClicks = 1;
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Return the number of rows of the result *****/
return NumClicks;
}
/*****************************************************************************/
/******** Remove user from table with number of clicks without photo *********/
/*****************************************************************************/
void Pho_RemoveUsrFromTableClicksWithoutPhoto (long UsrCod)
{
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a user from the list of users without photo",
"DELETE FROM clicks_without_photo WHERE UsrCod=%ld",
UsrCod);
2014-12-12 22:39:55 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************* Check if user's photo can be shown ********************/
/*****************************************************************************/
// Returns true if the photo can be shown and false if not.
// Public photo means two different things depending on the user's type
2018-10-18 02:02:32 +02:00
bool Pho_ShowingUsrPhotoIsAllowed (struct UsrData *UsrDat,char PhotoURL[PATH_MAX + 1])
2014-12-01 23:55:08 +01:00
{
2015-03-06 23:20:33 +01:00
bool ICanSeePhoto;
2014-12-01 23:55:08 +01:00
/***** Check if I can see the other's photo *****/
2017-01-28 15:58:46 +01:00
ICanSeePhoto = Pri_ShowingIsAllowed (UsrDat->PhotoVisibility,UsrDat);
2014-12-01 23:55:08 +01:00
/***** Photo is shown if I can see it, and it exists *****/
2016-07-08 12:43:48 +02:00
return ICanSeePhoto ? Pho_BuildLinkToPhoto (UsrDat,PhotoURL) :
2014-12-01 23:55:08 +01:00
false;
}
/*****************************************************************************/
/***************** Create a public link to a private photo *******************/
/*****************************************************************************/
// Returns false if photo does not exist
// Returns true if link is created successfully
2018-10-18 02:02:32 +02:00
bool Pho_BuildLinkToPhoto (const struct UsrData *UsrDat,char PhotoURL[PATH_MAX + 1])
2014-12-01 23:55:08 +01:00
{
2017-01-28 15:58:46 +01:00
char PathPublPhoto[PATH_MAX + 1];
char PathPrivPhoto[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
if (UsrDat->Photo[0])
{
/***** Make path to public photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPublPhoto,sizeof (PathPublPhoto),
2019-03-20 01:36:36 +01:00
"%s/%s.jpg",
Cfg_PATH_PHOTO_PUBLIC,UsrDat->Photo);
2014-12-01 23:55:08 +01:00
/***** Make path to private photo from public directory *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPrivPhoto,sizeof (PathPrivPhoto),
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100),UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
/***** Create a symbolic link to the private photo, if not exists *****/
if (!Fil_CheckIfPathExists (PathPublPhoto))
if (symlink (PathPrivPhoto,PathPublPhoto) != 0)
Lay_ShowErrorAndExit ("Can not create public link"
" to access to user's private photo");
/***** Create the public URL of the photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PhotoURL,PATH_MAX + 1,
2019-03-20 01:36:36 +01:00
"%s/%s.jpg",
Cfg_URL_PHOTO_PUBLIC,UsrDat->Photo);
2014-12-01 23:55:08 +01:00
return true;
}
else
{
PhotoURL[0] = '\0';
return false;
}
}
/*****************************************************************************/
/*************** Check if photo exists and return path to it *****************/
/*****************************************************************************/
// Returns false if photo does not exist
// Returns true if photo exists
2018-10-18 02:02:32 +02:00
bool Pho_CheckIfPrivPhotoExists (long UsrCod,char PathPrivRelPhoto[PATH_MAX + 1])
2014-12-01 23:55:08 +01:00
{
/***** Make path to private photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPrivRelPhoto,PATH_MAX + 1,
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrCod % 100),UsrCod);
2014-12-01 23:55:08 +01:00
return Fil_CheckIfPathExists (PathPrivRelPhoto);
}
/*****************************************************************************/
/************************** Remove a user's photo ****************************/
/*****************************************************************************/
// Returns true on success, false on error
bool Pho_RemovePhoto (struct UsrData *UsrDat)
{
2017-05-09 20:56:02 +02:00
extern const char *Txt_Photo_removed;
2017-01-28 15:58:46 +01:00
char PathPrivRelPhoto[PATH_MAX + 1];
char PathPublPhoto[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
unsigned NumErrors = 0;
if (UsrDat->Photo[0])
{
/***** Clear photo name in database *****/
Pho_ClearPhotoName (UsrDat->UsrCod);
/***** Remove public link *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPublPhoto,sizeof (PathPublPhoto),
2019-03-20 01:36:36 +01:00
"%s/%s.jpg",
Cfg_PATH_PHOTO_PUBLIC,UsrDat->Photo);
2014-12-01 23:55:08 +01:00
if (Fil_CheckIfPathExists (PathPublPhoto)) // Public link exists
if (unlink (PathPublPhoto)) // Remove public link
NumErrors++;
/***** Remove photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPrivRelPhoto,sizeof (PathPrivRelPhoto),
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100),UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
if (Fil_CheckIfPathExists (PathPrivRelPhoto)) // Photo exists
{
if (unlink (PathPrivRelPhoto)) // Remove photo
NumErrors++;
}
/***** Remove original photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPrivRelPhoto,sizeof (PathPrivRelPhoto),
2019-03-20 01:36:36 +01:00
"%s/%02u/%ld_original.jpg",
Cfg_PATH_PHOTO_PRIVATE,
2018-10-18 02:02:32 +02:00
(unsigned) (UsrDat->UsrCod % 100),UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
if (Fil_CheckIfPathExists (PathPrivRelPhoto)) // Original photo exists
if (unlink (PathPrivRelPhoto)) // Remove original photo
NumErrors++;
/***** Clear photo name in user's data *****/
UsrDat->Photo[0] = '\0';
}
2017-05-09 20:56:02 +02:00
if (NumErrors)
{
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_ERROR,NULL,
"Error removing photo.");
2017-05-09 20:56:02 +02:00
return false;
}
else
{
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_Photo_removed);
2017-05-09 20:56:02 +02:00
return true;
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Clear photo name of an user in database ******************/
/*****************************************************************************/
static void Pho_ClearPhotoName (long UsrCod)
{
/***** Clear photo name in user's data *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not clear the name of a user's photo",
"UPDATE usr_data SET Photo='' WHERE UsrCod=%ld",
UsrCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Update photo name of an user in database ******************/
/*****************************************************************************/
void Pho_UpdatePhotoName (struct UsrData *UsrDat)
{
2017-01-28 15:58:46 +01:00
char PathPublPhoto[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
/***** Update photo name in database *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the name of a user's photo",
"UPDATE usr_data SET Photo='%s' WHERE UsrCod=%ld",
Gbl.UniqueNameEncrypted,UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
/***** Remove the old symbolic link to photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathPublPhoto,sizeof (PathPublPhoto),
2019-03-20 01:36:36 +01:00
"%s/%s.jpg",
Cfg_PATH_PHOTO_PUBLIC,UsrDat->Photo);
2014-12-01 23:55:08 +01:00
unlink (PathPublPhoto); // Remove public link
/***** Update photo name in user's data *****/
2017-01-15 22:58:26 +01:00
Str_Copy (UsrDat->Photo,Gbl.UniqueNameEncrypted,
2017-03-07 01:56:41 +01:00
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Write code to show the photo of a user *******************/
/*****************************************************************************/
void Pho_ShowUsrPhoto (const struct UsrData *UsrDat,const char *PhotoURL,
2016-01-14 02:43:46 +01:00
const char *ClassPhoto,Pho_Zoom_t Zoom,
2016-01-14 10:31:09 +01:00
bool FormUnique)
2014-12-01 23:55:08 +01:00
{
2019-03-07 13:00:18 +01:00
extern const char *Rol_Icons[Rol_NUM_ROLES];
2019-02-22 14:04:54 +01:00
extern const char *Txt_Following;
extern const char *Txt_Followers;
unsigned NumFollowing;
unsigned NumFollowers;
2015-07-15 19:54:47 +02:00
bool PhotoExists;
2019-04-19 13:11:54 +02:00
Act_BrowserTab_t BrowserTab = Act_GetBrowserTab (Gbl.Action.Act);
bool BrowserTabIs1stTab = (BrowserTab == Act_BRW_1ST_TAB ||
BrowserTab == Act_AJAX_NORMAL ||
BrowserTab == Act_AJAX_RFRESH);
2018-04-24 13:21:53 +02:00
bool PutLinkToPublicProfile = !Gbl.Form.Inside && // Only if not inside another form
2019-04-19 13:11:54 +02:00
BrowserTabIs1stTab; // Only in main browser tab (or AJAX)
2018-04-24 13:21:53 +02:00
bool PutZoomCode = (Zoom == Pho_ZOOM) && // Make zoom
2019-04-19 13:11:54 +02:00
BrowserTabIs1stTab; // Only in main browser tab (or AJAX)
2018-11-09 20:47:39 +01:00
char IdCaption[Frm_MAX_BYTES_ID + 1];
2019-03-07 13:00:18 +01:00
char MainDegreeShrtName[Hie_MAX_BYTES_SHRT_NAME + 1];
Rol_Role_t MaxRole; // Maximum user's role in his/her main degree
2014-12-01 23:55:08 +01:00
2019-10-20 22:00:28 +02:00
/***** Begin form to go to public profile *****/
2015-03-13 00:16:02 +01:00
if (PutLinkToPublicProfile)
{
2016-01-14 10:31:09 +01:00
if (FormUnique)
2017-02-17 01:59:58 +01:00
{
2018-11-09 20:47:39 +01:00
Frm_StartFormUnique (ActSeeOthPubPrf);
2017-02-17 06:32:57 +01:00
Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod);
2018-11-09 20:47:39 +01:00
Frm_LinkFormSubmitUnique (NULL,NULL);
2017-02-17 06:32:57 +01:00
}
2016-01-14 02:43:46 +01:00
else
2017-02-17 01:59:58 +01:00
{
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActSeeOthPubPrf);
2017-02-17 06:32:57 +01:00
Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod);
2018-11-09 20:47:39 +01:00
Frm_LinkFormSubmit (NULL,NULL,NULL);
2017-02-17 01:59:58 +01:00
}
2015-03-13 00:16:02 +01:00
}
2016-06-17 19:42:15 +02:00
/***** Hidden div to pass user's name to Javascript *****/
if (PutZoomCode)
{
2018-11-09 20:47:39 +01:00
Frm_SetUniqueId (IdCaption);
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("id=\"%s\" class=\"NOT_SHOWN\"",IdCaption);
2017-03-01 14:53:18 +01:00
2017-03-02 01:02:15 +01:00
/* First name and surnames */
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_N_BOLD\""); // Limited width
2017-03-05 15:12:48 +01:00
Usr_WriteFirstNameBRSurnames (UsrDat);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2017-03-01 14:53:18 +01:00
2019-03-07 13:00:18 +01:00
/* Nickname */
if (UsrDat->Nickname[0])
2019-10-23 20:07:56 +02:00
{
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_SMALL_N\"");
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"@%s",UsrDat->Nickname);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
}
2019-03-07 13:00:18 +01:00
2019-02-22 14:04:54 +01:00
/* Institution full name and institution country */
2017-03-02 00:53:34 +01:00
if (UsrDat->InsCod > 0)
{
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_SMALL\"");
2017-03-02 00:53:34 +01:00
Ins_WriteInstitutionNameAndCty (UsrDat->InsCod);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2017-03-02 00:53:34 +01:00
}
/* User's country */
else if (UsrDat->CtyCod > 0)
2017-03-01 14:53:18 +01:00
{
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_SMALL\"");
2017-03-01 14:53:18 +01:00
Cty_WriteCountryName (UsrDat->CtyCod,
2019-03-07 13:00:18 +01:00
NULL); // Don't put link to country
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2017-03-01 14:53:18 +01:00
}
2019-03-07 13:00:18 +01:00
/* Main degree (in which the user has more courses) short name */
Usr_GetMainDeg (UsrDat->UsrCod,MainDegreeShrtName,&MaxRole);
if (MainDegreeShrtName[0])
2019-10-23 20:07:56 +02:00
{
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_SMALL\"");
HTM_DIV_Begin ("class=\"ZOOM_DEG\" style=\"background-image:url('%s/%s');\"",
Cfg_URL_ICON_PUBLIC,Rol_Icons[MaxRole]);
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"%s",
2019-03-07 13:00:18 +01:00
MainDegreeShrtName);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
HTM_DIV_End ();
}
2019-03-07 13:00:18 +01:00
2019-02-22 14:04:54 +01:00
/* Following and followers */
2019-03-07 13:00:18 +01:00
if (UsrDat->Nickname[0]) // Get social data only if nickname is retrieved (in some actions)
{
Fol_GetNumFollow (UsrDat->UsrCod,&NumFollowing,&NumFollowers);
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE\"");
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"<span class=\"DAT_N_BOLD\">%u</span>"
2019-03-07 13:00:18 +01:00
"<span class=\"DAT_SMALL\">&nbsp;%s&nbsp;</span>"
"<span class=\"DAT_N_BOLD\">%u</span>"
2019-10-23 20:07:56 +02:00
"<span class=\"DAT_SMALL\">&nbsp;%s</span>",
2019-03-07 13:00:18 +01:00
NumFollowing,Txt_Following,
NumFollowers,Txt_Followers);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2019-03-07 13:00:18 +01:00
}
2019-02-22 14:04:54 +01:00
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2016-06-17 19:42:15 +02:00
}
2015-03-13 00:16:02 +01:00
/***** Start image *****/
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"<img src=\"");
2015-07-15 19:54:47 +02:00
PhotoExists = false;
2014-12-01 23:55:08 +01:00
if (PhotoURL)
2015-07-15 19:54:47 +02:00
if (PhotoURL[0])
PhotoExists = true;
if (PhotoExists)
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"%s",PhotoURL);
else
2019-03-20 01:36:36 +01:00
fprintf (Gbl.F.Out,"%s/usr_bl.jpg",Cfg_URL_ICON_PUBLIC);
2015-07-22 13:32:56 +02:00
fprintf (Gbl.F.Out,"\" alt=\"%s\" title=\"%s\""
" class=\"%s\"",
2017-03-01 14:53:18 +01:00
UsrDat->FullName,UsrDat->FullName,
2015-07-22 13:32:56 +02:00
ClassPhoto);
2015-03-13 00:16:02 +01:00
/***** Image zoom *****/
if (PutZoomCode)
2017-03-01 15:23:30 +01:00
{
fprintf (Gbl.F.Out," onmouseover=\"zoom(this,'");
if (PhotoExists)
fprintf (Gbl.F.Out,"%s",PhotoURL);
else
2019-03-20 01:36:36 +01:00
fprintf (Gbl.F.Out,"%s/usr_bl.jpg",Cfg_URL_ICON_PUBLIC);
2017-03-01 15:23:30 +01:00
fprintf (Gbl.F.Out,"','%s');\" onmouseout=\"noZoom();\"",
IdCaption);
}
2015-03-13 00:16:02 +01:00
/***** End image *****/
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out," />");
2015-03-13 00:16:02 +01:00
/***** End form to go to public profile *****/
if (PutLinkToPublicProfile)
{
fprintf (Gbl.F.Out,"</a>");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2015-03-13 00:16:02 +01:00
}
2014-12-01 23:55:08 +01:00
}
2015-03-06 14:11:11 +01:00
/*****************************************************************************/
/************************** Change photo visibility **************************/
/*****************************************************************************/
void Pho_ChangePhotoVisibility (void)
{
2015-03-06 22:36:29 +01:00
extern const char *Pri_VisibilityDB[Pri_NUM_OPTIONS_PRIVACY];
2015-01-01 19:39:46 +01:00
/***** Get param with public/private photo *****/
2019-03-23 13:10:31 +01:00
Gbl.Usrs.Me.UsrDat.PhotoVisibility = Pri_GetParamVisibility ("VisPho",
Pri_PHOTO_ALLOWED_VIS);
2015-01-01 19:39:46 +01:00
/***** Store public/private photo in database *****/
2019-03-26 11:53:21 +01:00
DB_QueryUPDATE ("can not update your setting about photo visibility",
2018-11-03 12:16:40 +01:00
"UPDATE usr_data SET PhotoVisibility='%s' WHERE UsrCod=%ld",
Pri_VisibilityDB[Gbl.Usrs.Me.UsrDat.PhotoVisibility],
Gbl.Usrs.Me.UsrDat.UsrCod);
2015-03-06 21:45:57 +01:00
/***** Show form again *****/
2019-03-26 11:53:21 +01:00
Set_EditSettings ();
2015-01-01 19:39:46 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/******** Calculate average photos of all students from each degree **********/
/*****************************************************************************/
void Pho_CalcPhotoDegree (void)
{
Pho_AvgPhotoTypeOfAverage_t TypeOfAverage;
long DegCod = -1L;
2017-01-28 15:58:46 +01:00
char DirAvgPhotosRelPath[Pho_NUM_AVERAGE_PHOTO_TYPES][PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
unsigned NumStds,NumStdsWithPhoto;
Usr_Sex_t Sex;
long TotalTimeToComputeAvgPhotoInMicroseconds,PartialTimeToComputeAvgPhotoInMicroseconds;
/***** Get type of average *****/
Gbl.Stat.DegPhotos.TypeOfAverage = Pho_GetPhotoAvgTypeFromForm ();
/***** Create public directories for average photos if not exist *****/
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_PHOTO_PUBLIC);
2014-12-01 23:55:08 +01:00
for (TypeOfAverage = (Pho_AvgPhotoTypeOfAverage_t) 0;
TypeOfAverage < Pho_NUM_AVERAGE_PHOTO_TYPES;
TypeOfAverage++)
{
2018-10-18 02:02:32 +02:00
snprintf (DirAvgPhotosRelPath[TypeOfAverage],
sizeof (DirAvgPhotosRelPath[TypeOfAverage]),
2019-03-20 01:36:36 +01:00
"%s/%s",
Cfg_PATH_PHOTO_PUBLIC,Pho_StrAvgPhotoDirs[TypeOfAverage]);
2014-12-01 23:55:08 +01:00
Fil_CreateDirIfNotExists (DirAvgPhotosRelPath[TypeOfAverage]);
}
/***** Creates private directory for lists of users' photos if not exists *****/
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_PHOTO_TMP_PRIVATE);
2014-12-01 23:55:08 +01:00
/***** Get the degree which photo will be computed *****/
2017-05-31 21:05:59 +02:00
DegCod = Deg_GetAndCheckParamOtherDegCod (1);
2014-12-01 23:55:08 +01:00
/***** Prevent the computing of an average photo too recently updated *****/
if (Pho_GetTimeAvgPhotoWasComputed (DegCod) >=
2015-10-27 19:00:21 +01:00
Gbl.StartExecutionTimeUTC - Cfg_MIN_TIME_TO_RECOMPUTE_AVG_PHOTO)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Average photo has been computed recently.");
/***** Get list of students in this degree *****/
Usr_GetUnorderedStdsCodesInDeg (DegCod);
for (Sex = (Usr_Sex_t) 0;
Sex < Usr_NUM_SEXS;
Sex++)
{
TotalTimeToComputeAvgPhotoInMicroseconds = 0;
for (TypeOfAverage = (Pho_AvgPhotoTypeOfAverage_t) 0;
TypeOfAverage < Pho_NUM_AVERAGE_PHOTO_TYPES;
TypeOfAverage++)
{
/***** Compute average photos of students belonging this degree *****/
2017-05-18 19:13:41 +02:00
Pho_ComputeAveragePhoto (DegCod,Sex,Rol_STD,
2014-12-01 23:55:08 +01:00
TypeOfAverage,DirAvgPhotosRelPath[TypeOfAverage],
&NumStds,&NumStdsWithPhoto,&PartialTimeToComputeAvgPhotoInMicroseconds);
TotalTimeToComputeAvgPhotoInMicroseconds += PartialTimeToComputeAvgPhotoInMicroseconds;
}
/***** Store stats in database *****/
Pho_UpdateDegStats (DegCod,Sex,NumStds,NumStdsWithPhoto,TotalTimeToComputeAvgPhotoInMicroseconds);
}
/***** Free memory for students list *****/
2017-05-18 19:13:41 +02:00
Usr_FreeUsrsList (Rol_STD);
2014-12-01 23:55:08 +01:00
/***** Show photos *****/
Pho_ShowOrPrintPhotoDegree (Pho_DEGREES_SEE);
}
/*****************************************************************************/
/******** Get degree code with average photo least recently updated **********/
/*****************************************************************************/
// Returns -1 when error or when all the degrees have been updated too recently
static long Pho_GetDegWithAvgPhotoLeastRecentlyUpdated (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows = 0;
long DegCod = -1L;
/***** Delete all the degrees in sta_degrees table not present in degrees table *****/
Pho_RemoveObsoleteStatDegrees ();
2016-04-16 15:05:18 +02:00
/***** 1. If a degree is not in table of computed degrees,
choose it as least recently updated *****/
/* Get one degree with students not yet computed */
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get degrees",
"SELECT DISTINCT degrees.DegCod"
" FROM degrees,courses,crs_usr"
" WHERE degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND degrees.DegCod NOT IN"
" (SELECT DISTINCT DegCod FROM sta_degrees)"
" LIMIT 1",
(unsigned) Rol_STD);
2014-12-01 23:55:08 +01:00
/* If number of rows is 1, then get the degree code */
if (NumRows == 1)
{
/* Get row */
row = mysql_fetch_row (mysql_res);
/* Get degree code (row[0]) */
if ((DegCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of degree.");
}
else // NumRows == 0
{
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
2016-04-16 15:05:18 +02:00
/***** 2. If all the degrees are in table,
choose the least recently updated that has students *****/
2014-12-01 23:55:08 +01:00
/* Get degrees from database */
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get degrees",
"SELECT sta_degrees.DegCod"
" FROM sta_degrees,courses,crs_usr"
" WHERE sta_degrees.TimeAvgPhoto<"
2019-02-13 13:32:11 +01:00
"FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)"
2018-11-01 13:03:25 +01:00
" AND sta_degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" ORDER BY sta_degrees.TimeAvgPhoto LIMIT 1",
Cfg_MIN_TIME_TO_RECOMPUTE_AVG_PHOTO,
(unsigned) Rol_STD);
2014-12-01 23:55:08 +01:00
/* If number of rows is 1, then get the degree code */
if (NumRows == 1)
{
/* Get row */
2016-04-16 15:05:18 +02:00
row = mysql_fetch_row (mysql_res);
2014-12-01 23:55:08 +01:00
/* Get degree code (row[0]) */
if ((DegCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of degree.");
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return DegCod;
}
/*****************************************************************************/
/* Delete all the degrees in sta_degrees table not present in degrees table **/
/*****************************************************************************/
void Pho_RemoveObsoleteStatDegrees (void)
{
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove old degrees from stats",
"DELETE FROM sta_degrees"
" WHERE DegCod NOT IN (SELECT DegCod FROM degrees)");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Get time when average photo was computed ******************/
/*****************************************************************************/
static long Pho_GetTimeAvgPhotoWasComputed (long DegCod)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
long TimeAvgPhotoWasComputed = 0L;
/***** Get last time an average photo was computed from database *****/
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get last time"
" an average photo was computed",
"SELECT MIN(UNIX_TIMESTAMP(TimeAvgPhoto))"
" FROM sta_degrees WHERE DegCod=%ld",
DegCod);
2014-12-01 23:55:08 +01:00
if (NumRows == 1)
{
/***** Get row *****/
row = mysql_fetch_row (mysql_res);
/***** Get time when average photo was computed (row[0]) *****/
if (row[0])
sscanf (row[0],"%ld",&TimeAvgPhotoWasComputed);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return TimeAvgPhotoWasComputed;
}
/*****************************************************************************/
/********************* Get time to compute average photo *********************/
/*****************************************************************************/
static long Pho_GetTimeToComputeAvgPhoto (long DegCod)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
Usr_Sex_t Sex;
long PartialTimeToComputeAvgPhoto;
long TotalTimeToComputeAvgPhoto = -1L;
/***** Get time to compute average photo from database *****/
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get time to compute"
" average photo",
"SELECT TimeToComputeAvgPhoto FROM sta_degrees"
" WHERE DegCod=%ld",
DegCod);
2014-12-01 23:55:08 +01:00
/***** Count number of rows in result *****/
if (NumRows == Usr_NUM_SEXS)
{
TotalTimeToComputeAvgPhoto = 0;
for (Sex = (Usr_Sex_t) 0;
Sex < Usr_NUM_SEXS;
Sex++)
{
/***** Get row *****/
row = mysql_fetch_row (mysql_res);
/***** Get time to compute average photo (row[0]) *****/
PartialTimeToComputeAvgPhoto = -1L;
if (row[0][0])
if (sscanf (row[0],"%ld",&PartialTimeToComputeAvgPhoto) != 1)
PartialTimeToComputeAvgPhoto = -1L;
if (PartialTimeToComputeAvgPhoto < 0)
{
TotalTimeToComputeAvgPhoto = -1L;
break;
}
TotalTimeToComputeAvgPhoto += PartialTimeToComputeAvgPhoto;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return TotalTimeToComputeAvgPhoto;
}
/*****************************************************************************/
/********************** Compute the average photo of a list ******************/
/*****************************************************************************/
// Returns number of users in list with photo
2016-06-23 13:10:43 +02:00
static void Pho_ComputeAveragePhoto (long DegCod,Usr_Sex_t Sex,Rol_Role_t Role,
2014-12-01 23:55:08 +01:00
Pho_AvgPhotoTypeOfAverage_t TypeOfAverage,const char *DirAvgPhotosRelPath,
unsigned *NumStds,unsigned *NumStdsWithPhoto,long *TimeToComputeAvgPhotoInMicroseconds)
{
extern const char *Usr_StringsSexDB[Usr_NUM_SEXS];
unsigned NumUsr;
2017-01-28 15:58:46 +01:00
char PathPrivRelPhoto[PATH_MAX + 1]; // Relative path to private photo, to calculate average face
char PathRelAvgPhoto[PATH_MAX + 1];
char FileNamePhotoNames[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
FILE *FilePhotoNames = NULL; // Initialized to avoid warning
char StrCallToProgram[256]; // Call to photo processing program
int ReturnCode;
/* To compute execution time of this function */
struct timeval tvStartComputingStat;
struct timeval tvEndComputingStat;
struct timezone tz;
/***** Set start time to compute the stats of this degree *****/
gettimeofday (&tvStartComputingStat,&tz);
/***** Reset number of students in this degree *****/
*NumStds = *NumStdsWithPhoto = 0;
/***** Build name for file with average photo *****/
2018-10-18 02:02:32 +02:00
snprintf (PathRelAvgPhoto,sizeof (PathRelAvgPhoto),
"%s/%ld_%s.jpg",
DirAvgPhotosRelPath,DegCod,Usr_StringsSexDB[Sex]);
2014-12-01 23:55:08 +01:00
/***** Remove old file if exists *****/
if (Fil_CheckIfPathExists (PathRelAvgPhoto)) // If file exists
unlink (PathRelAvgPhoto);
2016-05-05 10:01:35 +02:00
/***** Build names for text file with photo paths *****/
2018-10-18 02:02:32 +02:00
snprintf (FileNamePhotoNames,sizeof (FileNamePhotoNames),
2019-03-20 01:36:36 +01:00
"%s/%ld.txt",
Cfg_PATH_PHOTO_TMP_PRIVATE,DegCod);
2016-05-05 10:01:35 +02:00
if ((FilePhotoNames = fopen (FileNamePhotoNames,"wb")) == NULL)
Lay_ShowErrorAndExit ("Can not open file to compute average photo.");
/***** Loop writing file names in text file *****/
for (NumUsr = 0;
2016-06-23 13:10:43 +02:00
NumUsr < Gbl.Usrs.LstUsrs[Role].NumUsrs;
2016-05-05 10:01:35 +02:00
NumUsr++)
2014-12-01 23:55:08 +01:00
{
2016-06-23 13:10:43 +02:00
Gbl.Usrs.Other.UsrDat.Sex = Gbl.Usrs.LstUsrs[Role].Lst[NumUsr].Sex;
2016-05-05 10:01:35 +02:00
if (Sex == Usr_SEX_ALL || Sex == Gbl.Usrs.Other.UsrDat.Sex)
{
(*NumStds)++;
2014-12-01 23:55:08 +01:00
2016-05-05 10:01:35 +02:00
/***** Add photo to file for average face calculation *****/
2016-06-23 13:10:43 +02:00
Gbl.Usrs.Other.UsrDat.UsrCod = Gbl.Usrs.LstUsrs[Role].Lst[NumUsr].UsrCod;
2016-05-05 10:01:35 +02:00
if (Pho_CheckIfPrivPhotoExists (Gbl.Usrs.Other.UsrDat.UsrCod,PathPrivRelPhoto))
{
(*NumStdsWithPhoto)++;
fprintf (FilePhotoNames,"%s\n",PathPrivRelPhoto);
}
}
}
fclose (FilePhotoNames);
2014-12-01 23:55:08 +01:00
2016-05-05 10:01:35 +02:00
/***** Call to program to calculate average photo *****/
if (*NumStdsWithPhoto)
{
2018-10-18 02:02:32 +02:00
snprintf (StrCallToProgram,sizeof (StrCallToProgram),
"%s %s %s",
Pho_StrAvgPhotoPrograms[TypeOfAverage],
FileNamePhotoNames,PathRelAvgPhoto);
2016-05-05 10:01:35 +02:00
ReturnCode = system (StrCallToProgram);
if (ReturnCode == -1)
Lay_ShowErrorAndExit ("Error when running program that computes the average photo.");
/* Write message depending on the return code */
if (WEXITSTATUS(ReturnCode))
Lay_ShowErrorAndExit ("The average photo has not been computed successfully.");
2014-12-01 23:55:08 +01:00
}
/***** Time used to compute the stats of this degree *****/
if (gettimeofday (&tvEndComputingStat, &tz))
// Error in gettimeofday
*TimeToComputeAvgPhotoInMicroseconds = -1L;
else
{
if (tvEndComputingStat.tv_usec < tvStartComputingStat.tv_usec)
{
tvEndComputingStat.tv_sec--;
tvEndComputingStat.tv_usec += 1000000L;
}
2016-06-23 13:10:43 +02:00
*TimeToComputeAvgPhotoInMicroseconds = (tvEndComputingStat.tv_sec -
tvStartComputingStat.tv_sec) * 1000000L +
tvEndComputingStat.tv_usec -
tvStartComputingStat.tv_usec;
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/*** Show class photo with average photos of all students from each degree ***/
/*****************************************************************************/
void Pho_ShowPhotoDegree (void)
{
/***** Get type of average *****/
Gbl.Stat.DegPhotos.TypeOfAverage = Pho_GetPhotoAvgTypeFromForm ();
Pho_ShowOrPrintPhotoDegree (Pho_DEGREES_SEE);
}
/*****************************************************************************/
/** Print class photo with average photos of all students from each degree ***/
/*****************************************************************************/
void Pho_PrintPhotoDegree (void)
{
/***** Get type of average *****/
Gbl.Stat.DegPhotos.TypeOfAverage = Pho_GetPhotoAvgTypeFromForm ();
Pho_ShowOrPrintPhotoDegree (Pho_DEGREES_PRINT);
}
/*****************************************************************************/
/*** Show class photo with average photos of all students from each degree ***/
/*****************************************************************************/
void Pho_ShowOrPrintPhotoDegree (Pho_AvgPhotoSeeOrPrint_t SeeOrPrint)
{
2017-12-19 18:41:19 +01:00
extern const char *Hlp_ANALYTICS_Degrees;
2017-02-09 18:56:29 +01:00
extern const char *Txt_Degrees;
2014-12-01 23:55:08 +01:00
/***** Get photo size from form *****/
Gbl.Stat.DegPhotos.HowComputePhotoSize = Pho_GetHowComputePhotoSizeFromForm ();
/***** Get how to order degrees from form *****/
Gbl.Stat.DegPhotos.HowOrderDegrees = Pho_GetHowOrderDegreesFromForm ();
2015-10-19 21:49:45 +02:00
/***** Get and update type of list,
number of columns in class photo
and preference about view photos *****/
2014-12-01 23:55:08 +01:00
Usr_GetAndUpdatePrefsAboutUsrList ();
2017-02-09 18:56:29 +01:00
switch (SeeOrPrint)
2014-12-01 23:55:08 +01:00
{
2017-02-09 18:56:29 +01:00
case Pho_DEGREES_SEE:
2017-06-12 14:16:33 +02:00
/***** Start box *****/
2017-06-11 22:26:40 +02:00
Box_StartBox (NULL,Txt_Degrees,Pho_PutIconToPrintDegreeStats,
2017-12-19 18:41:19 +01:00
Hlp_ANALYTICS_Degrees,Box_NOT_CLOSABLE);
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginCenterPadding (2);
2014-12-01 23:55:08 +01:00
2017-02-09 18:56:29 +01:00
/***** Put a selector for the type of average *****/
Pho_PutSelectorForTypeOfAvg ();
2014-12-01 23:55:08 +01:00
2017-02-09 18:56:29 +01:00
/***** Put a selector for the size of photos *****/
Pho_PutSelectorForHowComputePhotoSize ();
/***** Put a selector for the order of degrees *****/
Pho_PutSelectorForHowOrderDegrees ();
2014-12-01 23:55:08 +01:00
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2018-10-09 22:21:44 +02:00
/***** Link to compute average photos *****/
Pho_PutLinkToCalculateDegreeStats ();
2017-02-09 18:56:29 +01:00
break;
case Pho_DEGREES_PRINT:
2017-06-12 14:16:33 +02:00
/***** Start box *****/
2017-06-10 21:38:10 +02:00
Box_StartBox (NULL,Txt_Degrees,NULL,
2017-06-12 15:03:29 +02:00
NULL,Box_NOT_CLOSABLE);
2017-02-09 18:56:29 +01:00
break;
2014-12-01 23:55:08 +01:00
}
2016-05-05 10:01:35 +02:00
/***** Get maximum number of students
and maximum number of students with photo
in all degrees *****/
2014-12-01 23:55:08 +01:00
Pho_GetMaxStdsPerDegree ();
/***** Draw the classphoto/list *****/
switch (Gbl.Usrs.Me.ListType)
{
2017-01-29 21:41:08 +01:00
case Usr_LIST_AS_CLASS_PHOTO:
2014-12-01 23:55:08 +01:00
Pho_ShowOrPrintClassPhotoDegrees (SeeOrPrint);
break;
2017-01-29 21:41:08 +01:00
case Usr_LIST_AS_LISTING:
2014-12-01 23:55:08 +01:00
Pho_ShowOrPrintListDegrees (SeeOrPrint);
break;
2017-01-29 21:41:08 +01:00
default:
break;
2014-12-01 23:55:08 +01:00
}
2017-02-09 18:56:29 +01:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2017-06-10 21:38:10 +02:00
Box_EndBox ();
2014-12-01 23:55:08 +01:00
}
2019-04-11 09:55:35 +02:00
/*****************************************************************************/
/**************** Put parameter for degree average photos ********************/
/*****************************************************************************/
void Pho_PutParamsDegPhoto ()
{
Pho_PutHiddenParamTypeOfAvg ();
Pho_PutHiddenParamPhotoSize ();
Pho_PutHiddenParamOrderDegrees ();
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/******************* Put a selector for the type of average ******************/
/*****************************************************************************/
static void Pho_PutSelectorForTypeOfAvg (void)
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Average_type;
extern const char *Txt_AVERAGE_PHOTO_TYPES[Pho_NUM_AVERAGE_PHOTO_TYPES];
Pho_AvgPhotoTypeOfAverage_t TypeOfAvg;
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"RM\"");
2019-10-09 15:44:12 +02:00
fprintf (Gbl.F.Out,"<label for=\"AvgType\" class=\"%s\">%s:</label>",
2019-02-22 21:47:50 +01:00
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Average_type);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActSeePhoDeg);
2014-12-01 23:55:08 +01:00
Pho_PutHiddenParamPhotoSize ();
Pho_PutHiddenParamOrderDegrees ();
2017-02-01 11:23:48 +01:00
Usr_PutParamsPrefsAboutUsrList ();
2016-12-27 16:45:37 +01:00
fprintf (Gbl.F.Out,"<select id=\"AvgType\" name=\"AvgType\""
2015-10-22 14:49:48 +02:00
" onchange=\"document.getElementById('%s').submit();\">",
2016-01-14 10:31:09 +01:00
Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
for (TypeOfAvg = (Pho_AvgPhotoTypeOfAverage_t) 0;
TypeOfAvg < Pho_NUM_AVERAGE_PHOTO_TYPES;
TypeOfAvg++)
{
fprintf (Gbl.F.Out,"<option value=\"%u\"",(unsigned) TypeOfAvg);
if (TypeOfAvg == Gbl.Stat.DegPhotos.TypeOfAverage)
fprintf (Gbl.F.Out," selected=\"selected\"");
2015-03-06 14:11:11 +01:00
fprintf (Gbl.F.Out,">%s</option>",Txt_AVERAGE_PHOTO_TYPES[TypeOfAvg]);
2014-12-01 23:55:08 +01:00
}
2015-03-13 00:16:02 +01:00
fprintf (Gbl.F.Out,"</select>");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Put hidden parameter for the type of average ***************/
/*****************************************************************************/
void Pho_PutHiddenParamTypeOfAvg (void)
{
Par_PutHiddenParamUnsigned ("AvgType",(unsigned) Gbl.Stat.DegPhotos.TypeOfAverage);
}
/*****************************************************************************/
/*********************** Get type of average for photos **********************/
/*****************************************************************************/
static Pho_AvgPhotoTypeOfAverage_t Pho_GetPhotoAvgTypeFromForm (void)
{
2017-01-29 12:42:19 +01:00
return (Pho_AvgPhotoTypeOfAverage_t)
2017-01-29 21:41:08 +01:00
Par_GetParToUnsignedLong ("AvgType",
0,
Pho_NUM_AVERAGE_PHOTO_TYPES - 1,
(unsigned long) Pho_PHOTO_AVG_DEFAULT);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Put a selector for the size of photos ********************/
/*****************************************************************************/
static void Pho_PutSelectorForHowComputePhotoSize (void)
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Size_of_photos;
extern const char *Txt_STAT_DEGREE_PHOTO_SIZE[Pho_NUM_HOW_COMPUTE_PHOTO_SIZES];
Pho_HowComputePhotoSize_t PhoSi;
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"RM\"");
2019-10-09 15:44:12 +02:00
fprintf (Gbl.F.Out,"<label for=\"PhotoSize\" class=\"%s\">%s:</label>",
2019-02-22 21:47:50 +01:00
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Size_of_photos);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActSeePhoDeg);
2014-12-01 23:55:08 +01:00
Pho_PutHiddenParamTypeOfAvg ();
Pho_PutHiddenParamOrderDegrees ();
2017-02-01 11:23:48 +01:00
Usr_PutParamsPrefsAboutUsrList ();
2016-12-27 16:45:37 +01:00
fprintf (Gbl.F.Out,"<select id=\"PhotoSize\" name=\"PhotoSize\""
2015-10-22 14:49:48 +02:00
" onchange=\"document.getElementById('%s').submit();\">",
2016-01-14 10:31:09 +01:00
Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
for (PhoSi = (Pho_HowComputePhotoSize_t) 0;
PhoSi < Pho_NUM_HOW_COMPUTE_PHOTO_SIZES;
PhoSi++)
{
fprintf (Gbl.F.Out,"<option value=\"%u\"",(unsigned) PhoSi);
if (PhoSi == Gbl.Stat.DegPhotos.HowComputePhotoSize)
fprintf (Gbl.F.Out," selected=\"selected\"");
2015-03-06 14:11:11 +01:00
fprintf (Gbl.F.Out,">%s</option>",Txt_STAT_DEGREE_PHOTO_SIZE[PhoSi]);
2014-12-01 23:55:08 +01:00
}
2015-03-13 00:16:02 +01:00
fprintf (Gbl.F.Out,"</select>");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Put hidden parameter for the size of photos ****************/
/*****************************************************************************/
void Pho_PutHiddenParamPhotoSize (void)
{
Par_PutHiddenParamUnsigned ("PhotoSize",(unsigned) Gbl.Stat.DegPhotos.HowComputePhotoSize);
}
/*****************************************************************************/
/********************* Get how to compute size of photos *********************/
/*****************************************************************************/
static Pho_HowComputePhotoSize_t Pho_GetHowComputePhotoSizeFromForm (void)
{
2017-01-29 12:42:19 +01:00
return (Pho_HowComputePhotoSize_t)
2017-01-29 21:41:08 +01:00
Par_GetParToUnsignedLong ("PhotoSize",
0,
Pho_NUM_HOW_COMPUTE_PHOTO_SIZES - 1,
(unsigned long) Pho_PHOTO_SIZE_DEFAULT);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Put a selector for the order of degrees ******************/
/*****************************************************************************/
static void Pho_PutSelectorForHowOrderDegrees (void)
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Sort_degrees_by;
extern const char *Txt_STAT_DEGREE_PHOTO_ORDER[Pho_NUM_HOW_ORDER_DEGREES];
Pho_HowOrderDegrees_t Order;
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"RM\"");
2019-10-09 15:44:12 +02:00
fprintf (Gbl.F.Out,"<label for=\"Order\" class=\"%s\">%s:</label>",
2019-02-22 21:47:50 +01:00
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Sort_degrees_by);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActSeePhoDeg);
2014-12-01 23:55:08 +01:00
Pho_PutHiddenParamTypeOfAvg ();
Pho_PutHiddenParamPhotoSize ();
2017-02-01 11:23:48 +01:00
Usr_PutParamsPrefsAboutUsrList ();
2017-01-29 12:42:19 +01:00
fprintf (Gbl.F.Out,"<select id=\"Order\" name=\"Order\""
2015-10-22 14:49:48 +02:00
" onchange=\"document.getElementById('%s').submit();\">",
2016-01-14 10:31:09 +01:00
Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
for (Order = (Pho_HowOrderDegrees_t) 0;
Order < Pho_NUM_HOW_ORDER_DEGREES;
Order++)
{
fprintf (Gbl.F.Out,"<option value=\"%u\"",(unsigned) Order);
if (Order == Gbl.Stat.DegPhotos.HowOrderDegrees)
fprintf (Gbl.F.Out," selected=\"selected\"");
2015-03-06 14:11:11 +01:00
fprintf (Gbl.F.Out,">%s</option>",Txt_STAT_DEGREE_PHOTO_ORDER[Order]);
2014-12-01 23:55:08 +01:00
}
2015-03-13 00:16:02 +01:00
fprintf (Gbl.F.Out,"</select>");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Put hidden parameter for the order of degrees **************/
/*****************************************************************************/
void Pho_PutHiddenParamOrderDegrees (void)
{
2017-01-29 12:42:19 +01:00
Par_PutHiddenParamUnsigned ("Order",(unsigned) Gbl.Stat.DegPhotos.HowOrderDegrees);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************************** Get how to order degrees ************************/
/*****************************************************************************/
static Pho_HowOrderDegrees_t Pho_GetHowOrderDegreesFromForm (void)
{
2017-01-29 12:42:19 +01:00
return (Pho_HowOrderDegrees_t)
2017-01-29 21:41:08 +01:00
Par_GetParToUnsignedLong ("Order",
0,
Pho_NUM_HOW_ORDER_DEGREES - 1,
(unsigned long) Pho_ORDER_DEFAULT);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-03-21 18:06:36 +01:00
/*************** Put icon to print view the stats of degrees ***************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-03-21 18:06:36 +01:00
static void Pho_PutIconToPrintDegreeStats (void)
2014-12-01 23:55:08 +01:00
{
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToPrint (ActPrnPhoDeg,Pho_PutLinkToPrintViewOfDegreeStatsParams);
2015-04-02 18:39:49 +02:00
}
static void Pho_PutLinkToPrintViewOfDegreeStatsParams (void)
{
2014-12-01 23:55:08 +01:00
Pho_PutHiddenParamTypeOfAvg ();
Pho_PutHiddenParamPhotoSize ();
Pho_PutHiddenParamOrderDegrees ();
2017-02-01 11:23:48 +01:00
Usr_PutParamsPrefsAboutUsrList ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Put a link to calculate the stats of degrees ****************/
/*****************************************************************************/
static void Pho_PutLinkToCalculateDegreeStats (void)
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBoxBold[The_NUM_THEMES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Calculate_average_photo_of_THE_DEGREE_X;
extern const char *Txt_unknown_TIME;
extern const char *Txt_time;
2016-04-16 15:05:18 +02:00
struct ListDegrees Degs;
2014-12-01 23:55:08 +01:00
unsigned NumDeg;
struct Degree Deg;
long EstimatedTimeToComputeAvgPhotoInMicroseconds;
2018-10-18 02:02:32 +02:00
char StrEstimatedTimeToComputeAvgPhoto[Dat_MAX_BYTES_TIME + 1];
2014-12-01 23:55:08 +01:00
if ((Deg.DegCod = Pho_GetDegWithAvgPhotoLeastRecentlyUpdated ()) > 0)
{
/***** Get list of all the degrees *****/
2016-04-16 15:05:18 +02:00
Deg_GetListAllDegsWithStds (&Degs);
2014-12-01 23:55:08 +01:00
/***** Get data of the degree from database *****/
Deg_GetDataOfDegreeByCod (&Deg);
2019-10-24 09:46:20 +02:00
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
2014-12-01 23:55:08 +01:00
2019-10-24 09:46:20 +02:00
/* Begin form */
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActCalPhoDeg);
2014-12-01 23:55:08 +01:00
Pho_PutHiddenParamTypeOfAvg ();
Pho_PutHiddenParamPhotoSize ();
Pho_PutHiddenParamOrderDegrees ();
2017-02-01 11:23:48 +01:00
Usr_PutParamsPrefsAboutUsrList ();
2019-01-12 19:46:33 +01:00
Frm_LinkFormSubmitAnimated (Txt_Calculate_average_photo_of_THE_DEGREE_X,
2019-02-22 21:47:50 +01:00
The_ClassFormInBoxBold[Gbl.Prefs.Theme],
2016-07-01 17:13:41 +02:00
NULL);
2019-01-12 19:46:33 +01:00
Ico_PutCalculateIconWithText (Txt_Calculate_average_photo_of_THE_DEGREE_X);
2014-12-01 23:55:08 +01:00
2019-10-24 09:46:20 +02:00
/* Selector with all the degrees with students */
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"<select name=\"OthDegCod\">");
for (NumDeg = 0;
2016-04-16 15:05:18 +02:00
NumDeg < Degs.Num;
2014-12-01 23:55:08 +01:00
NumDeg++)
{
/* Get time to compute average photo of this degree */
2016-04-16 15:05:18 +02:00
EstimatedTimeToComputeAvgPhotoInMicroseconds = Pho_GetTimeToComputeAvgPhoto (Degs.Lst[NumDeg].DegCod);
2014-12-01 23:55:08 +01:00
if (EstimatedTimeToComputeAvgPhotoInMicroseconds == -1L)
2017-01-15 22:58:26 +01:00
Str_Copy (StrEstimatedTimeToComputeAvgPhoto,Txt_unknown_TIME,
2018-10-18 02:02:32 +02:00
Dat_MAX_BYTES_TIME);
2014-12-01 23:55:08 +01:00
else
2017-03-07 19:55:29 +01:00
Sta_WriteTime (StrEstimatedTimeToComputeAvgPhoto,
EstimatedTimeToComputeAvgPhotoInMicroseconds);
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"<option value=\"%ld\"%s>%s (%s: %s)</option>",
2016-04-16 15:05:18 +02:00
Degs.Lst[NumDeg].DegCod,
Degs.Lst[NumDeg].DegCod == Deg.DegCod ? " selected=\"selected\"" :
((Pho_GetTimeAvgPhotoWasComputed (Degs.Lst[NumDeg].DegCod) >=
Gbl.StartExecutionTimeUTC - Cfg_MIN_TIME_TO_RECOMPUTE_AVG_PHOTO) ? " disabled=\"disabled\"" :
""),
2016-10-28 10:03:37 +02:00
Degs.Lst[NumDeg].ShrtName,
2014-12-01 23:55:08 +01:00
Txt_time,
StrEstimatedTimeToComputeAvgPhoto);
}
2015-03-13 00:16:02 +01:00
fprintf (Gbl.F.Out,"</select>");
2019-10-24 09:46:20 +02:00
/* End form and contextual menu */
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-24 09:46:20 +02:00
Mnu_ContextMenuEnd ();
2014-12-01 23:55:08 +01:00
2016-04-16 15:05:18 +02:00
/***** Free list of all the degrees with students *****/
Deg_FreeListDegs (&Degs);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/*** Get number of students and number of students with photo in a degree ****/
/*****************************************************************************/
static void Pho_GetMaxStdsPerDegree (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
/***** Get maximum number of students in a degree from database *****/
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get maximum"
" number of students in a degree",
"SELECT MAX(NumStds),MAX(NumStdsWithPhoto),"
"MAX(NumStdsWithPhoto/NumStds)"
" FROM sta_degrees"
" WHERE Sex='all' AND NumStds>0");
2014-12-01 23:55:08 +01:00
/***** Count number of rows in result *****/
if (NumRows == 1)
{
row = mysql_fetch_row (mysql_res);
if (row[0] == NULL)
Gbl.Stat.DegPhotos.MaxStds = -1;
else if (sscanf (row[0],"%d",&Gbl.Stat.DegPhotos.MaxStds) != 1)
Gbl.Stat.DegPhotos.MaxStds = -1;
if (row[1] == NULL)
Gbl.Stat.DegPhotos.MaxStdsWithPhoto = -1;
else if (sscanf (row[1],"%d",&Gbl.Stat.DegPhotos.MaxStdsWithPhoto) != 1)
Gbl.Stat.DegPhotos.MaxStdsWithPhoto = -1;
if (row[2] == NULL)
Gbl.Stat.DegPhotos.MaxPercent = -1.0;
else if (sscanf (row[2],"%f",&Gbl.Stat.DegPhotos.MaxPercent) != 1)
Gbl.Stat.DegPhotos.MaxPercent = -1.0;
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
else
{
Gbl.Stat.DegPhotos.MaxStds = Gbl.Stat.DegPhotos.MaxStdsWithPhoto = -1;
Gbl.Stat.DegPhotos.MaxPercent = -1.0;
}
}
/*****************************************************************************/
/************ Show or print the stats of degrees as class photo **************/
/*****************************************************************************/
static void Pho_ShowOrPrintClassPhotoDegrees (Pho_AvgPhotoSeeOrPrint_t SeeOrPrint)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-11-01 13:03:25 +01:00
unsigned long NumDeg;
unsigned long NumDegs;
2014-12-01 23:55:08 +01:00
struct Degree Deg;
unsigned NumDegsNotEmpty;
2015-10-02 01:04:28 +02:00
int NumStds;
int NumStdsWithPhoto;
2014-12-01 23:55:08 +01:00
bool TRIsOpen = false;
/***** Get degrees from database *****/
2018-11-01 13:03:25 +01:00
NumDegs = Pho_BuildQueryOfDegrees (&mysql_res);
2014-12-01 23:55:08 +01:00
2018-11-01 13:03:25 +01:00
if (NumDegs) // Degrees with students found
2014-12-01 23:55:08 +01:00
{
2015-10-02 01:04:28 +02:00
/***** Form to select type of list used to display degree photos *****/
if (SeeOrPrint == Pho_DEGREES_SEE)
2019-04-11 14:45:31 +02:00
Usr_ShowFormsToSelectUsrListType (Pho_PutParamsDegPhoto);
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginCenter ();
2014-12-01 23:55:08 +01:00
2015-10-02 01:04:28 +02:00
/***** Get and print degrees *****/
2018-11-01 13:03:25 +01:00
for (NumDeg = 0, NumDegsNotEmpty = 0;
NumDeg < NumDegs;
NumDeg++)
2015-10-02 01:04:28 +02:00
{
/***** Get next degree *****/
row = mysql_fetch_row (mysql_res);
/* Get degree code (row[0]) */
if ((Deg.DegCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of degree.");
/* Get data of degree */
Deg_GetDataOfDegreeByCod (&Deg);
/* Get number of students and number of students with photo in this degree */
Pho_GetNumStdsInDegree (Deg.DegCod,Usr_SEX_ALL,&NumStds,&NumStdsWithPhoto);
2016-05-05 10:41:23 +02:00
if (NumStds > 0)
2015-10-02 01:04:28 +02:00
{
if ((NumDegsNotEmpty % Gbl.Usrs.ClassPhoto.Cols) == 0)
{
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2015-10-02 01:04:28 +02:00
TRIsOpen = true;
}
/***** Show average photo of students belonging to this degree *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CLASSPHOTO CM\"");
2015-10-27 00:36:23 +01:00
Pho_ShowDegreeAvgPhotoAndStat (&Deg,SeeOrPrint,Usr_SEX_ALL,NumStds,NumStdsWithPhoto);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2015-10-02 01:04:28 +02:00
if ((++NumDegsNotEmpty % Gbl.Usrs.ClassPhoto.Cols) == 0)
{
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2015-10-02 01:04:28 +02:00
TRIsOpen = false;
}
}
}
if (TRIsOpen)
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
2015-10-02 01:04:28 +02:00
else // No degrees with students found
2017-02-09 19:27:18 +01:00
/***** Show warning indicating no students found *****/
2017-05-18 19:13:41 +02:00
Usr_ShowWarningNoUsersFound (Rol_STD);
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/**************** Show or print the stats of degrees as list *****************/
/*****************************************************************************/
static void Pho_ShowOrPrintListDegrees (Pho_AvgPhotoSeeOrPrint_t SeeOrPrint)
{
extern const char *Txt_No_INDEX;
extern const char *Txt_Degree;
extern const char *Txt_SEX_PLURAL_Abc[Usr_NUM_SEXS];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-11-01 13:03:25 +01:00
unsigned long NumDeg;
unsigned long NumDegs;
2014-12-01 23:55:08 +01:00
unsigned NumDegsNotEmpty;
2015-10-02 01:04:28 +02:00
int NumStds;
int NumStdsWithPhoto;
2014-12-01 23:55:08 +01:00
struct Degree Deg;
Usr_Sex_t Sex;
/***** Get degrees from database *****/
2018-11-01 13:03:25 +01:00
NumDegs = Pho_BuildQueryOfDegrees (&mysql_res);
2014-12-01 23:55:08 +01:00
2018-11-01 13:03:25 +01:00
if (NumDegs) // Degrees with students found
2014-12-01 23:55:08 +01:00
{
2015-10-02 01:04:28 +02:00
/***** Class photo start *****/
2014-12-01 23:55:08 +01:00
if (SeeOrPrint == Pho_DEGREES_SEE)
2015-10-02 01:04:28 +02:00
/***** Form to select type of list used to display degree photos *****/
2019-04-11 14:45:31 +02:00
Usr_ShowFormsToSelectUsrListType (Pho_PutParamsDegPhoto);
2015-10-02 01:04:28 +02:00
/***** Write heading *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginCenterPadding (2);
HTM_TR_Begin (NULL);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"RT",Txt_No_INDEX);
HTM_TH (1,1,"CT",Txt_Degree);
2014-12-01 23:55:08 +01:00
for (Sex = (Usr_Sex_t) 0;
Sex < Usr_NUM_SEXS;
Sex++)
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"CT",Txt_SEX_PLURAL_Abc[Sex]);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2015-10-02 01:04:28 +02:00
/***** Get degrees *****/
2018-11-01 13:03:25 +01:00
for (NumDeg = 0, Gbl.RowEvenOdd = 0, NumDegsNotEmpty = 0;
NumDeg < NumDegs;
NumDeg++, Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd)
2015-10-02 01:04:28 +02:00
{
/***** Get next degree *****/
row = mysql_fetch_row (mysql_res);
/* Get degree code (row[0]) */
if ((Deg.DegCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of degree.");
/* Get data of degree */
Deg_GetDataOfDegreeByCod (&Deg);
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-07 17:36:41 +02:00
/***** Show logo and name of this degree *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT RM COLOR%u\"",Gbl.RowEvenOdd);
2019-10-09 15:44:12 +02:00
fprintf (Gbl.F.Out,"%u",++NumDegsNotEmpty);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2015-10-02 01:04:28 +02:00
/***** Show logo and name of this degree *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM COLOR%u\"",Gbl.RowEvenOdd);
2015-10-02 01:04:28 +02:00
if (SeeOrPrint == Pho_DEGREES_SEE)
2015-12-05 12:43:52 +01:00
Deg_DrawDegreeLogoAndNameWithLink (&Deg,ActSeeDegInf,
2019-10-15 15:23:38 +02:00
"DAT","CT");
2015-12-05 12:43:52 +01:00
else // Pho_DEGREES_PRINT
{
2019-10-15 15:23:38 +02:00
Log_DrawLogo (Hie_DEG,Deg.DegCod,Deg.ShrtName,20,"CT",true);
2015-12-05 12:43:52 +01:00
fprintf (Gbl.F.Out,"&nbsp;%s</a>",Deg.FullName);
}
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2015-10-02 01:04:28 +02:00
for (Sex = (Usr_Sex_t) 0;
Sex < Usr_NUM_SEXS;
Sex++)
{
/***** Show average photo of students belonging to this degree *****/
Pho_GetNumStdsInDegree (Deg.DegCod,Sex,&NumStds,&NumStdsWithPhoto);
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CLASSPHOTO CM COLOR%u\"",Gbl.RowEvenOdd);
2015-10-02 01:04:28 +02:00
if (Gbl.Usrs.Listing.WithPhotos)
2015-10-27 00:36:23 +01:00
Pho_ShowDegreeAvgPhotoAndStat (&Deg,SeeOrPrint,Sex,NumStds,NumStdsWithPhoto);
2015-10-02 01:04:28 +02:00
else
Pho_ShowDegreeStat (NumStds,NumStdsWithPhoto);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2015-10-02 01:04:28 +02:00
}
2019-10-07 17:36:41 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2015-10-02 01:04:28 +02:00
}
/***** Photos end *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
2015-10-02 01:04:28 +02:00
else // No degrees with students found!
2017-02-09 19:27:18 +01:00
/***** Show warning indicating no students found *****/
2017-05-18 19:13:41 +02:00
Usr_ShowWarningNoUsersFound (Rol_STD);
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/****** Build a query to get the degrees ordered by different criteria *******/
/*****************************************************************************/
2018-11-01 13:03:25 +01:00
static unsigned long Pho_BuildQueryOfDegrees (MYSQL_RES **mysql_res)
2014-12-01 23:55:08 +01:00
{
2018-11-01 13:03:25 +01:00
unsigned long NumDegs = 0; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
switch (Gbl.Stat.DegPhotos.HowOrderDegrees)
{
case Pho_NUMBER_OF_STUDENTS:
2018-11-01 13:03:25 +01:00
NumDegs = DB_QuerySELECT (mysql_res,"can not get degrees",
"SELECT degrees.DegCod"
" FROM degrees,sta_degrees"
" WHERE sta_degrees.Sex='all'"
" AND sta_degrees.NumStds>0"
" AND degrees.DegCod=sta_degrees.DegCod"
" ORDER BY sta_degrees.NumStds DESC,"
"sta_degrees.NumStdsWithPhoto DESC,"
"degrees.ShortName");
2014-12-01 23:55:08 +01:00
break;
case Pho_NUMBER_OF_PHOTOS:
2018-11-01 13:03:25 +01:00
NumDegs = DB_QuerySELECT (mysql_res,"can not get degrees",
"SELECT degrees.DegCod"
" FROM degrees,sta_degrees"
" WHERE sta_degrees.Sex='all'"
" AND sta_degrees.NumStds>0"
" AND degrees.DegCod=sta_degrees.DegCod"
" ORDER BY sta_degrees.NumStdsWithPhoto DESC,"
"sta_degrees.NumStds DESC,"
"degrees.ShortName");
2014-12-01 23:55:08 +01:00
break;
case Pho_PERCENT:
2018-11-01 13:03:25 +01:00
NumDegs = DB_QuerySELECT (mysql_res,"can not get degrees",
"SELECT degrees.DegCod"
" FROM degrees,sta_degrees"
" WHERE sta_degrees.Sex='all'"
" AND sta_degrees.NumStds>0"
" AND degrees.DegCod=sta_degrees.DegCod"
" ORDER BY sta_degrees.NumStdsWithPhoto/"
"sta_degrees.NumStds DESC,"
"degrees.ShortName");
2014-12-01 23:55:08 +01:00
break;
case Pho_DEGREE_NAME:
2018-11-01 13:03:25 +01:00
NumDegs = DB_QuerySELECT (mysql_res,"can not get degrees",
"SELECT degrees.DegCod"
" FROM degrees,sta_degrees"
" WHERE sta_degrees.Sex='all'"
" AND sta_degrees.NumStds>0"
" AND degrees.DegCod=sta_degrees.DegCod"
" ORDER BY degrees.ShortName");
2014-12-01 23:55:08 +01:00
break;
}
2018-11-01 13:03:25 +01:00
return NumDegs;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*** Get number of students and number of students with photo in a degree ****/
/*****************************************************************************/
static void Pho_GetNumStdsInDegree (long DegCod,Usr_Sex_t Sex,int *NumStds,int *NumStdsWithPhoto)
{
extern const char *Usr_StringsSexDB[Usr_NUM_SEXS];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
/***** Get the number of students in a degree from database *****/
2018-11-01 13:03:25 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get the number of students"
" in a degree",
"SELECT NumStds,NumStdsWithPhoto"
" FROM sta_degrees"
" WHERE DegCod=%ld AND Sex='%s'",
DegCod,Usr_StringsSexDB[Sex]);
2014-12-01 23:55:08 +01:00
if (NumRows == 0)
*NumStds = *NumStdsWithPhoto = -1;
else
{
row = mysql_fetch_row (mysql_res);
if (sscanf (row[0],"%d",NumStds) != 1)
*NumStds = -1;
if (sscanf (row[1],"%d",NumStdsWithPhoto) != 1)
*NumStdsWithPhoto = -1;
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
}
/*****************************************************************************/
/*********************** Update statistics of a degree ***********************/
/*****************************************************************************/
static void Pho_UpdateDegStats (long DegCod,Usr_Sex_t Sex,unsigned NumStds,unsigned NumStdsWithPhoto,long TimeToComputeAvgPhotoInMicroseconds)
{
extern const char *Usr_StringsSexDB[Usr_NUM_SEXS];
2018-10-24 09:25:09 +02:00
2018-11-02 16:39:35 +01:00
DB_QueryREPLACE ("can not save stats of a degree",
"REPLACE INTO sta_degrees"
" (DegCod,Sex,NumStds,NumStdsWithPhoto,"
"TimeAvgPhoto,TimeToComputeAvgPhoto)"
" VALUES"
" (%ld,'%s',%u,%u,NOW(),%ld)",
DegCod,Usr_StringsSexDB[Sex],NumStds,NumStdsWithPhoto,
TimeToComputeAvgPhotoInMicroseconds);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Show the average photo of a degree **********************/
/*****************************************************************************/
static void Pho_ShowDegreeStat (int NumStds,int NumStdsWithPhoto)
{
extern const char *Txt_photos;
fprintf (Gbl.F.Out,"<span class=\"DAT\">%d&nbsp;</span>"
"<span class=\"DAT_SMALL\">(%d&nbsp;%s,&nbsp;%d%%)</span>",
NumStds,NumStdsWithPhoto,Txt_photos,
NumStds > 0 ? (int) (((NumStdsWithPhoto * 100.0) / NumStds) + 0.5) :
0);
}
/*****************************************************************************/
/******************* Show the average photo of a degree **********************/
/*****************************************************************************/
2016-05-05 10:41:23 +02:00
static void Pho_ShowDegreeAvgPhotoAndStat (struct Degree *Deg,
Pho_AvgPhotoSeeOrPrint_t SeeOrPrint,
Usr_Sex_t Sex,
int NumStds,int NumStdsWithPhoto)
2014-12-01 23:55:08 +01:00
{
extern const char *Usr_StringsSexDB[Usr_NUM_SEXS];
2016-05-30 19:11:08 +02:00
extern const char *Txt_Go_to_X;
2014-12-01 23:55:08 +01:00
extern const char *Txt_students_ABBREVIATION;
extern const char *Txt_SEX_PLURAL_abc[Usr_NUM_SEXS];
extern const char *Txt_photos;
2015-09-23 14:31:47 +02:00
unsigned PhotoWidth;
unsigned PhotoHeight;
2017-01-28 15:58:46 +01:00
char PathRelAvgPhoto[PATH_MAX + 1];
char PhotoURL[PATH_MAX + 1];
2018-10-04 21:57:25 +02:00
char PhotoCaption[1024 + Hie_MAX_BYTES_SHRT_NAME];
2016-05-05 10:41:23 +02:00
bool ShowDegPhoto;
2018-11-09 20:47:39 +01:00
char IdCaption[Frm_MAX_BYTES_ID + 1];
2016-06-17 19:42:15 +02:00
/***** Initializations *****/
PhotoURL[0] = '\0';
PhotoCaption[0] = '\0';
2014-12-01 23:55:08 +01:00
2017-03-03 21:06:34 +01:00
/***** Compute photo width and height
to be proportional to number of students *****/
2014-12-01 23:55:08 +01:00
Pho_ComputePhotoSize (NumStds,NumStdsWithPhoto,&PhotoWidth,&PhotoHeight);
2016-05-05 10:41:23 +02:00
/***** Put link to degree *****/
2014-12-01 23:55:08 +01:00
if (SeeOrPrint == Pho_DEGREES_SEE)
2016-05-30 19:11:08 +02:00
{
2018-11-09 20:47:39 +01:00
Frm_StartFormGoTo (ActSeeDegInf);
2016-05-30 19:11:08 +02:00
Deg_PutParamDegCod (Deg->DegCod);
2018-10-18 02:02:32 +02:00
snprintf (Gbl.Title,sizeof (Gbl.Title),
Txt_Go_to_X,
Deg->FullName);
2018-11-09 20:47:39 +01:00
Frm_LinkFormSubmit (Gbl.Title,NULL,NULL);
2016-05-30 19:11:08 +02:00
}
2014-12-01 23:55:08 +01:00
2016-05-05 10:41:23 +02:00
/***** Check if photo of degree can be shown *****/
2017-06-04 18:18:54 +02:00
if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM)
2016-05-05 10:41:23 +02:00
ShowDegPhoto = (NumStds > 0);
else
ShowDegPhoto = (NumStds > 0 &&
NumStdsWithPhoto >= Cfg_MIN_PHOTOS_TO_SHOW_AVERAGE);
if (ShowDegPhoto)
2014-12-01 23:55:08 +01:00
{
2018-10-18 02:02:32 +02:00
snprintf (PathRelAvgPhoto,sizeof (PathRelAvgPhoto),
2019-03-20 01:36:36 +01:00
"%s/%s/%ld_%s.jpg",
Cfg_PATH_PHOTO_PUBLIC,
2018-10-18 02:02:32 +02:00
Pho_StrAvgPhotoDirs[Gbl.Stat.DegPhotos.TypeOfAverage],
Deg->DegCod,Usr_StringsSexDB[Sex]);
2014-12-01 23:55:08 +01:00
if (Fil_CheckIfPathExists (PathRelAvgPhoto))
2016-06-17 19:42:15 +02:00
{
2018-10-18 02:02:32 +02:00
snprintf (PhotoURL,sizeof (PhotoURL),
2019-03-20 01:36:36 +01:00
"%s/%s/%ld_%s.jpg",
Cfg_URL_PHOTO_PUBLIC,
2018-10-18 02:02:32 +02:00
Pho_StrAvgPhotoDirs[Gbl.Stat.DegPhotos.TypeOfAverage],
Deg->DegCod,Usr_StringsSexDB[Sex]);
2014-12-01 23:55:08 +01:00
if (SeeOrPrint == Pho_DEGREES_SEE)
{
2016-06-17 19:42:15 +02:00
/***** Hidden div to pass user's name to Javascript *****/
2018-10-18 02:02:32 +02:00
snprintf (PhotoCaption,sizeof (PhotoCaption),
"%s<br />"
"%d&nbsp;%s&nbsp;(%s)<br />"
"%d&nbsp;%s&nbsp;(%d%%)",
Deg->ShrtName,
NumStds,Txt_students_ABBREVIATION,Txt_SEX_PLURAL_abc[Sex],
NumStdsWithPhoto,Txt_photos,
NumStds > 0 ? (int) (((NumStdsWithPhoto * 100.0) / NumStds) + 0.5) :
0);
2018-11-09 20:47:39 +01:00
Frm_SetUniqueId (IdCaption);
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("id=\"%s\" class=\"NOT_SHOWN\"",IdCaption);
HTM_DIV_Begin ("class=\"ZOOM_TXT_LINE DAT_N\"");
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"%s",PhotoCaption);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
HTM_DIV_End ();
2016-06-17 19:42:15 +02:00
}
}
}
/***** Show photo *****/
fprintf (Gbl.F.Out,"<img src=\"");
if (PhotoURL[0])
{
fprintf (Gbl.F.Out,"%s\"",PhotoURL);
if (PhotoCaption[0])
2017-03-03 21:06:34 +01:00
fprintf (Gbl.F.Out," onmouseover=\"zoom(this,'%s','%s');\""
" onmouseout=\"noZoom();\"",
2016-06-17 19:42:15 +02:00
PhotoURL,IdCaption);
2014-12-01 23:55:08 +01:00
}
else
2019-03-20 01:36:36 +01:00
fprintf (Gbl.F.Out,"%s/usr_bl.jpg\"",Cfg_URL_ICON_PUBLIC);
2016-06-17 19:42:15 +02:00
fprintf (Gbl.F.Out," alt=\"%s\""
" style=\"width:%upx; height:%upx;\" />",
2016-10-28 10:03:37 +02:00
Deg->ShrtName,
2016-06-17 19:42:15 +02:00
PhotoWidth,PhotoHeight);
2016-05-05 10:41:23 +02:00
/***** Caption *****/
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"CLASSPHOTO_CAPTION\"");
2019-10-23 21:12:40 +02:00
fprintf (Gbl.F.Out,"%s<br />"
2017-03-03 21:06:34 +01:00
"%d&nbsp;%s<br />"
"%d&nbsp;%s<br />"
2019-10-23 20:07:56 +02:00
"(%d%%)",
2017-03-03 21:06:34 +01:00
Deg->ShrtName,
2014-12-01 23:55:08 +01:00
NumStds,Txt_students_ABBREVIATION,
NumStdsWithPhoto,Txt_photos,
NumStds > 0 ? (int) (((NumStdsWithPhoto * 100.0) / NumStds) + 0.5) :
0);
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2014-12-01 23:55:08 +01:00
if (SeeOrPrint == Pho_DEGREES_SEE)
2016-05-30 19:11:08 +02:00
{
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"</a>");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2016-05-30 19:11:08 +02:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******** Compute photo width and height for class photo of degrees **********/
/*****************************************************************************/
2015-09-28 18:28:29 +02:00
#define MIN_WIDTH_PHOTO 10
#define MIN_HEIGHT_PHOTO 15
2015-09-23 14:31:47 +02:00
#define MIN_PIXELS_PHOTO (MIN_WIDTH_PHOTO * MIN_HEIGHT_PHOTO)
2015-09-28 18:28:29 +02:00
#define DEF_WIDTH_PHOTO 45
#define DEF_HEIGHT_PHOTO 60
2015-09-23 14:31:47 +02:00
#define DEF_PIXELS_PHOTO (DEF_WIDTH_PHOTO * DEF_HEIGHT_PHOTO)
2015-09-28 18:28:29 +02:00
#define MAX_WIDTH_PHOTO 90
#define MAX_HEIGHT_PHOTO 120
2015-09-23 14:31:47 +02:00
#define MAX_PIXELS_PHOTO (MAX_WIDTH_PHOTO * MAX_HEIGHT_PHOTO)
2014-12-01 23:55:08 +01:00
static void Pho_ComputePhotoSize (int NumStds,int NumStdsWithPhoto,unsigned *PhotoWidth,unsigned *PhotoHeight)
{
unsigned PhotoPixels = DEF_PIXELS_PHOTO;
switch (Gbl.Stat.DegPhotos.HowComputePhotoSize)
{
case Pho_PROPORTIONAL_TO_NUMBER_OF_STUDENTS:
if (Gbl.Stat.DegPhotos.MaxStds > 0)
PhotoPixels = (unsigned) (((float) (MAX_PIXELS_PHOTO - MIN_PIXELS_PHOTO) /
Gbl.Stat.DegPhotos.MaxStds) * NumStds +
MIN_PIXELS_PHOTO + 0.5);
break;
case Pho_PROPORTIONAL_TO_NUMBER_OF_PHOTOS:
if (Gbl.Stat.DegPhotos.MaxStdsWithPhoto > 0)
PhotoPixels = (unsigned) (((float) (MAX_PIXELS_PHOTO - MIN_PIXELS_PHOTO) /
Gbl.Stat.DegPhotos.MaxStdsWithPhoto) * NumStdsWithPhoto +
MIN_PIXELS_PHOTO + 0.5);
break;
case Pho_PROPORTIONAL_TO_PERCENT:
if (Gbl.Stat.DegPhotos.MaxPercent > 0.0)
{
if (NumStds)
PhotoPixels = (unsigned) (((float) (MAX_PIXELS_PHOTO - MIN_PIXELS_PHOTO) /
Gbl.Stat.DegPhotos.MaxPercent) *
((float) NumStdsWithPhoto / NumStds) +
MIN_PIXELS_PHOTO + 0.5);
else
{
*PhotoWidth = MIN_WIDTH_PHOTO;
*PhotoHeight = MIN_HEIGHT_PHOTO;
return;
}
}
break;
case Pho_UNIQUE_SIZE:
*PhotoWidth = DEF_WIDTH_PHOTO;
*PhotoHeight = DEF_HEIGHT_PHOTO;
return;
}
*PhotoWidth = (unsigned) (sqrt (((double) Pho_PHOTO_REAL_WIDTH /
(double) Pho_PHOTO_REAL_HEIGHT) *
(double) PhotoPixels) + 0.5);
*PhotoHeight = (unsigned) (((double) Pho_PHOTO_REAL_HEIGHT /
(double) Pho_PHOTO_REAL_WIDTH) *
(double) *PhotoWidth + 0.5);
}