// swad_attendance.c: control of attendance
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2019 Antonio Caņas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
/*****************************************************************************/
/********************************** Headers **********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include // For PATH_MAX
#include // For NULL
#include // To access MySQL databases
#include // For asprintf
#include // For calloc
#include // For string functions
#include "swad_attendance.h"
#include "swad_box.h"
#include "swad_database.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_group.h"
#include "swad_HTML.h"
#include "swad_ID.h"
#include "swad_pagination.h"
#include "swad_parameter.h"
#include "swad_photo.h"
#include "swad_QR.h"
#include "swad_setting.h"
/*****************************************************************************/
/*************** External global variables from others modules ***************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/****************************** Private constants ****************************/
/*****************************************************************************/
#define Att_ATTENDANCE_TABLE_ID "att_table"
#define Att_ATTENDANCE_DETAILS_ID "att_details"
/*****************************************************************************/
/******************************** Private types ******************************/
/*****************************************************************************/
typedef enum
{
Att_NORMAL_VIEW_ONLY_ME,
Att_NORMAL_VIEW_STUDENTS,
Att_PRINT_VIEW,
} Att_TypeOfView_t;
/*****************************************************************************/
/****************************** Private variables ****************************/
/*****************************************************************************/
/*****************************************************************************/
/****************************** Private prototypes ***************************/
/*****************************************************************************/
static void Att_ShowAllAttEvents (void);
static void Att_ParamsWhichGroupsToShow (void);
static void Att_PutIconsInListOfAttEvents (void);
static void Att_PutIconToCreateNewAttEvent (void);
static void Att_PutButtonToCreateNewAttEvent (void);
static void Att_PutParamsToCreateNewAttEvent (void);
static void Att_ShowOneAttEvent (struct AttendanceEvent *Att,bool ShowOnlyThisAttEventComplete);
static void Att_WriteAttEventAuthor (struct AttendanceEvent *Att);
static void Att_GetParamAttOrder (void);
static void Att_PutFormToListMyAttendance (void);
static void Att_PutFormToListStdsAttendance (void);
static void Att_PutFormToListStdsParams (void);
static void Att_PutFormsToRemEditOneAttEvent (const struct AttendanceEvent *Att,
const char *Anchor);
static void Att_PutParams (void);
static void Att_GetListAttEvents (Att_OrderNewestOldest_t OrderNewestOldest);
static void Att_GetDataOfAttEventByCodAndCheckCrs (struct AttendanceEvent *Att);
static void Att_ResetAttendanceEvent (struct AttendanceEvent *Att);
static void Att_GetAttEventDescriptionFromDB (long AttCod,char Description[Cns_MAX_BYTES_TEXT + 1]);
static bool Att_CheckIfSimilarAttEventExists (const char *Field,const char *Value,long AttCod);
static void Att_ShowLstGrpsToEditAttEvent (long AttCod);
static void Att_RemoveAllTheGrpsAssociatedToAnAttEvent (long AttCod);
static void Att_CreateGrps (long AttCod);
static void Att_GetAndWriteNamesOfGrpsAssociatedToAttEvent (struct AttendanceEvent *Att);
static void Att_RemoveAllUsrsFromAnAttEvent (long AttCod);
static void Att_RemoveAttEventFromCurrentCrs (long AttCod);
static void Att_ListAttOnlyMeAsStudent (struct AttendanceEvent *Att);
static void Att_ListAttStudents (struct AttendanceEvent *Att);
static void Att_WriteRowUsrToCallTheRoll (unsigned NumUsr,
struct UsrData *UsrDat,
struct AttendanceEvent *Att);
static void Att_PutLinkAttEvent (struct AttendanceEvent *AttEvent,
const char *Title,const char *Txt,
const char *LinkStyle);
static void Att_PutParamsCodGrps (long AttCod);
static void Att_GetNumStdsTotalWhoAreInAttEvent (struct AttendanceEvent *Att);
static unsigned Att_GetNumStdsFromAListWhoAreInAttEvent (long AttCod,long LstSelectedUsrCods[],unsigned NumUsrsInList);
static bool Att_CheckIfUsrIsInTableAttUsr (long AttCod,long UsrCod,bool *Present);
static bool Att_CheckIfUsrIsPresentInAttEvent (long AttCod,long UsrCod);
static bool Att_CheckIfUsrIsPresentInAttEventAndGetComments (long AttCod,long UsrCod,
char CommentStd[Cns_MAX_BYTES_TEXT + 1],
char CommentTch[Cns_MAX_BYTES_TEXT + 1]);
static void Att_RegUsrInAttEventChangingComments (long AttCod,long UsrCod,bool Present,
const char *CommentStd,const char *CommentTch);
static void Att_RemoveUsrFromAttEvent (long AttCod,long UsrCod);
static void Usr_ListOrPrintMyAttendanceCrs (Att_TypeOfView_t TypeOfView);
static void Usr_ListOrPrintUsrsAttendanceCrs (Att_TypeOfView_t TypeOfView);
static void Att_GetListSelectedUsrCods (unsigned NumUsrsInList,long **LstSelectedUsrCods);
static void Att_GetListSelectedAttCods (char **StrAttCodsSelected);
static void Att_PutIconsMyAttList (void);
static void Att_PutFormToPrintMyListParams (void);
static void Att_PutIconsStdsAttList (void);
static void Att_PutParamsToPrintStdsList (void);
static void Att_PutButtonToShowDetails (void);
static void Att_ListEventsToSelect (Att_TypeOfView_t TypeOfView);
static void Att_PutIconToEditAttEvents (void);
static void Att_PutIconToViewAttEvents (void);
static void Att_ListUsrsAttendanceTable (Att_TypeOfView_t TypeOfView,
unsigned NumUsrsInList,
long *LstSelectedUsrCods);
static void Att_WriteTableHeadSeveralAttEvents (void);
static void Att_WriteRowUsrSeveralAttEvents (unsigned NumUsr,struct UsrData *UsrDat);
static void Att_PutCheckOrCross (bool Present);
static void Att_ListStdsWithAttEventsDetails (unsigned NumUsrsInList,
long *LstSelectedUsrCods);
static void Att_ListAttEventsForAStd (unsigned NumUsr,struct UsrData *UsrDat);
/*****************************************************************************/
/********************** List all the attendance events ***********************/
/*****************************************************************************/
void Att_SeeAttEvents (void)
{
/***** Get parameters *****/
Att_GetParamAttOrder ();
Grp_GetParamWhichGrps ();
Gbl.AttEvents.CurrentPage = Pag_GetParamPagNum (Pag_ATT_EVENTS);
/***** Get list of attendance events *****/
Att_GetListAttEvents (Att_NEWEST_FIRST);
/***** Contextual menu *****/
if (Gbl.AttEvents.Num &&
Gbl.Usrs.Me.UsrDat.Nickname[0])
switch (Gbl.Usrs.Me.Role.Logged)
{
case Rol_STD:
Mnu_ContextMenuBegin ();
Att_PutFormToListMyAttendance (); // List my attendance
Mnu_ContextMenuEnd ();
break;
case Rol_NET:
case Rol_TCH:
case Rol_SYS_ADM:
Mnu_ContextMenuBegin ();
Att_PutFormToListStdsAttendance (); // List students' attendance
Mnu_ContextMenuEnd ();
break;
default:
break;
}
/***** Show all the attendance events *****/
Att_ShowAllAttEvents ();
}
/*****************************************************************************/
/********************** Show all the attendance events ***********************/
/*****************************************************************************/
static void Att_ShowAllAttEvents (void)
{
extern const char *Hlp_USERS_Attendance;
extern const char *Txt_Events;
extern const char *Txt_START_END_TIME_HELP[Dat_NUM_START_END_TIME];
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
extern const char *Txt_Event;
extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
extern const char *Txt_No_events;
Dat_StartEndTime_t Order;
struct Pagination Pagination;
unsigned NumAttEvent;
bool ICanEdit = (Gbl.Usrs.Me.Role.Logged == Rol_TCH ||
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
/***** Compute variables related to pagination *****/
Pagination.NumItems = Gbl.AttEvents.Num;
Pagination.CurrentPage = (int) Gbl.AttEvents.CurrentPage;
Pag_CalculatePagination (&Pagination);
Gbl.AttEvents.CurrentPage = (unsigned) Pagination.CurrentPage;
/***** Write links to pages *****/
if (Pagination.MoreThanOnePage)
Pag_WriteLinksToPagesCentered (Pag_ATT_EVENTS,
0,
&Pagination);
/***** Begin box *****/
Box_BoxBegin ("100%",Txt_Events,Att_PutIconsInListOfAttEvents,
Hlp_USERS_Attendance,Box_NOT_CLOSABLE);
/***** Select whether show only my groups or all groups *****/
if (Gbl.Crs.Grps.NumGrps)
{
Set_StartSettingsHead ();
Grp_ShowFormToSelWhichGrps (ActSeeAtt,Att_ParamsWhichGroupsToShow);
Set_EndSettingsHead ();
}
if (Gbl.AttEvents.Num)
{
/***** Table head *****/
HTM_TABLE_BeginWideMarginPadding (2);
HTM_TR_Begin (NULL);
HTM_TH (1,1,"CONTEXT_COL",NULL); // Column for contextual icons
for (Order = Dat_START_TIME;
Order <= Dat_END_TIME;
Order++)
{
HTM_TH_Begin (1,1,"LM");
Frm_StartForm (ActSeeAtt);
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
Par_PutHiddenParamUnsigned ("Order",(unsigned) Order);
Frm_LinkFormSubmit (Txt_START_END_TIME_HELP[Order],"TIT_TBL",NULL);
if (Order == Gbl.AttEvents.SelectedOrder)
fprintf (Gbl.F.Out,"");
fprintf (Gbl.F.Out,"%s",Txt_START_END_TIME[Order]);
if (Order == Gbl.AttEvents.SelectedOrder)
fprintf (Gbl.F.Out,"");
Frm_LinkFormEnd ();
Frm_EndForm ();
HTM_TH_End ();
}
HTM_TH (1,1,"LM",Txt_Event);
HTM_TH (1,1,"RM",Txt_ROLES_PLURAL_Abc[Rol_STD][Usr_SEX_UNKNOWN]);
HTM_TR_End ();
/***** Write all the attendance events *****/
for (NumAttEvent = Pagination.FirstItemVisible, Gbl.RowEvenOdd = 0;
NumAttEvent <= Pagination.LastItemVisible;
NumAttEvent++)
Att_ShowOneAttEvent (&Gbl.AttEvents.Lst[NumAttEvent - 1],false);
/***** End table *****/
HTM_TABLE_End ();
}
else // No events created
Ale_ShowAlert (Ale_INFO,Txt_No_events);
/***** Button to create a new attendance event *****/
if (ICanEdit)
Att_PutButtonToCreateNewAttEvent ();
/***** End box *****/
Box_BoxEnd ();
/***** Write again links to pages *****/
if (Pagination.MoreThanOnePage)
Pag_WriteLinksToPagesCentered (Pag_ATT_EVENTS,
0,
&Pagination);
/***** Free list of attendance events *****/
Att_FreeListAttEvents ();
}
/*****************************************************************************/
/***************** Put params to select which groups to show *****************/
/*****************************************************************************/
static void Att_ParamsWhichGroupsToShow (void)
{
Att_PutHiddenParamAttOrder ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
}
/*****************************************************************************/
/************* Put contextual icons in list of attendance events *************/
/*****************************************************************************/
static void Att_PutIconsInListOfAttEvents (void)
{
bool ICanEdit = (Gbl.Usrs.Me.Role.Logged == Rol_TCH ||
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
/***** Put icon to create a new attendance event *****/
if (ICanEdit)
Att_PutIconToCreateNewAttEvent ();
/***** Put icon to print my QR code *****/
QR_PutLinkToPrintQRCode (ActPrnUsrQR,Usr_PutParamMyUsrCodEncrypted);
}
/*****************************************************************************/
/**************** Put icon to create a new attendance event ******************/
/*****************************************************************************/
static void Att_PutIconToCreateNewAttEvent (void)
{
extern const char *Txt_New_event;
/***** Put icon to create a new attendance event *****/
Ico_PutContextualIconToAdd (ActFrmNewAtt,NULL,
Att_PutParamsToCreateNewAttEvent,
Txt_New_event);
}
/*****************************************************************************/
/**************** Put button to create a new attendance event ****************/
/*****************************************************************************/
static void Att_PutButtonToCreateNewAttEvent (void)
{
extern const char *Txt_New_event;
Frm_StartForm (ActFrmNewAtt);
Att_PutParamsToCreateNewAttEvent ();
Btn_PutConfirmButton (Txt_New_event);
Frm_EndForm ();
}
/*****************************************************************************/
/************** Put parameters to create a new attendance event **************/
/*****************************************************************************/
static void Att_PutParamsToCreateNewAttEvent (void)
{
Att_PutHiddenParamAttOrder ();
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
}
/*****************************************************************************/
/************************* Show one attendance event *************************/
/*****************************************************************************/
// Only Att->AttCod must be filled
static void Att_ShowOneAttEvent (struct AttendanceEvent *Att,bool ShowOnlyThisAttEventComplete)
{
extern const char *Txt_View_event;
char *Anchor = NULL;
static unsigned UniqueId = 0;
char *Id;
Dat_StartEndTime_t StartEndTime;
char Description[Cns_MAX_BYTES_TEXT + 1];
/***** Get data of this attendance event *****/
Att_GetDataOfAttEventByCodAndCheckCrs (Att);
Att_GetNumStdsTotalWhoAreInAttEvent (Att);
/***** Set anchor string *****/
Frm_SetAnchorStr (Att->AttCod,&Anchor);
/***** Write first row of data of this attendance event *****/
/* Forms to remove/edit this attendance event */
HTM_TR_Begin (NULL);
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL\"");
else
HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL COLOR%u\"",Gbl.RowEvenOdd);
switch (Gbl.Usrs.Me.Role.Logged)
{
case Rol_TCH:
case Rol_SYS_ADM:
Att_PutFormsToRemEditOneAttEvent (Att,Anchor);
break;
default:
break;
}
HTM_TD_End ();
/* Start/end date/time */
UniqueId++;
for (StartEndTime = (Dat_StartEndTime_t) 0;
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
StartEndTime++)
{
if (asprintf (&Id,"att_date_%u_%u",(unsigned) StartEndTime,UniqueId) < 0)
Lay_NotEnoughMemoryExit ();
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("id=\"%s\" class=\"%s LB\"",
Id,
Att->Hidden ? (Att->Open ? "DATE_GREEN_LIGHT" :
"DATE_RED_LIGHT") :
(Att->Open ? "DATE_GREEN" :
"DATE_RED"));
else
HTM_TD_Begin ("id=\"%s\" class=\"%s LB COLOR%u\"",
Id,
Att->Hidden ? (Att->Open ? "DATE_GREEN_LIGHT" :
"DATE_RED_LIGHT") :
(Att->Open ? "DATE_GREEN" :
"DATE_RED"),
Gbl.RowEvenOdd);
Dat_WriteLocalDateHMSFromUTC (Id,Att->TimeUTC[StartEndTime],
Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK,
true,true,true,0x7);
HTM_TD_End ();
free ((void *) Id);
}
/* Attendance event title */
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("class=\"LT\"");
else
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
HTM_ARTICLE_Begin (Anchor);
Att_PutLinkAttEvent (Att,Txt_View_event,Att->Title,
Att->Hidden ? "ASG_TITLE_LIGHT" :
"ASG_TITLE");
HTM_ARTICLE_End ();
HTM_TD_End ();
/* Number of students in this event */
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("class=\"%s RT\"",
Att->Hidden ? "ASG_TITLE_LIGHT" :
"ASG_TITLE");
else
HTM_TD_Begin ("class=\"%s RT COLOR%u\"",
Att->Hidden ? "ASG_TITLE_LIGHT" :
"ASG_TITLE",
Gbl.RowEvenOdd);
fprintf (Gbl.F.Out,"%u",Att->NumStdsTotal);
HTM_TD_End ();
HTM_TR_End ();
/***** Write second row of data of this attendance event *****/
HTM_TR_Begin (NULL);
/* Author of the attendance event */
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("colspan=\"2\" class=\"LT\"");
else
HTM_TD_Begin ("colspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
Att_WriteAttEventAuthor (Att);
HTM_TD_End ();
/* Text of the attendance event */
Att_GetAttEventDescriptionFromDB (Att->AttCod,Description);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Description,Cns_MAX_BYTES_TEXT,false); // Convert from HTML to recpectful HTML
Str_InsertLinks (Description,Cns_MAX_BYTES_TEXT,60); // Insert links
if (ShowOnlyThisAttEventComplete)
HTM_TD_Begin ("colspan=\"2\" class=\"LT\"");
else
HTM_TD_Begin ("colspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
if (Gbl.Crs.Grps.NumGrps)
Att_GetAndWriteNamesOfGrpsAssociatedToAttEvent (Att);
HTM_DIV_Begin ("class=\"%s\"",Att->Hidden ? "DAT_LIGHT" :
"DAT");
fprintf (Gbl.F.Out,"%s",Description);
HTM_DIV_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Free anchor string *****/
Frm_FreeAnchorStr (Anchor);
Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd;
}
/*****************************************************************************/
/****************** Write the author of an attendance event ******************/
/*****************************************************************************/
static void Att_WriteAttEventAuthor (struct AttendanceEvent *Att)
{
Usr_WriteAuthor1Line (Att->UsrCod,Att->Hidden);
}
/*****************************************************************************/
/**** Get parameter with the type or order in list of attendance events ******/
/*****************************************************************************/
static void Att_GetParamAttOrder (void)
{
Gbl.AttEvents.SelectedOrder = (Dat_StartEndTime_t)
Par_GetParToUnsignedLong ("Order",
0,
Dat_NUM_START_END_TIME - 1,
(unsigned long) Att_ORDER_DEFAULT);
}
/*****************************************************************************/
/*** Put a hidden parameter with the type of order in list of att. events ****/
/*****************************************************************************/
void Att_PutHiddenParamAttOrder (void)
{
Par_PutHiddenParamUnsigned ("Order",(unsigned) Gbl.AttEvents.SelectedOrder);
}
/*****************************************************************************/
/**** Put a link (form) to list assistance of students to several events *****/
/*****************************************************************************/
static void Att_PutFormToListMyAttendance (void)
{
extern const char *Txt_Attendance_list;
Lay_PutContextualLinkIconText (ActSeeLstMyAtt,NULL,NULL,
"list-ol.svg",
Txt_Attendance_list);
}
/*****************************************************************************/
/** Put a link (form) to list my assistance (as student) to several events ***/
/*****************************************************************************/
static void Att_PutFormToListStdsAttendance (void)
{
extern const char *Txt_Attendance_list;
Lay_PutContextualLinkIconText (ActReqLstUsrAtt,NULL,
Att_PutFormToListStdsParams,
"list-ol.svg",
Txt_Attendance_list);
}
static void Att_PutFormToListStdsParams (void)
{
Att_PutHiddenParamAttOrder ();
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
}
/*****************************************************************************/
/************** Put a link (form) to edit one attendance event ***************/
/*****************************************************************************/
static void Att_PutFormsToRemEditOneAttEvent (const struct AttendanceEvent *Att,
const char *Anchor)
{
Gbl.AttEvents.AttCod = Att->AttCod; // Used as parameters in contextual links
/***** Put form to remove attendance event *****/
Ico_PutContextualIconToRemove (ActReqRemAtt,Att_PutParams);
/***** Put form to hide/show attendance event *****/
if (Att->Hidden)
Ico_PutContextualIconToUnhide (ActShoAtt,Anchor,Att_PutParams);
else
Ico_PutContextualIconToHide (ActHidAtt,Anchor,Att_PutParams);
/***** Put form to edit attendance event *****/
Ico_PutContextualIconToEdit (ActEdiOneAtt,Att_PutParams);
}
/*****************************************************************************/
/***************** Params used to edit an attendance event *******************/
/*****************************************************************************/
static void Att_PutParams (void)
{
Att_PutParamAttCod (Gbl.AttEvents.AttCod);
Att_PutHiddenParamAttOrder ();
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
}
/*****************************************************************************/
/********************* List all the attendance events ************************/
/*****************************************************************************/
static void Att_GetListAttEvents (Att_OrderNewestOldest_t OrderNewestOldest)
{
static const char *HiddenSubQuery[Rol_NUM_ROLES] =
{
" AND Hidden='N'", // Rol_UNK
" AND Hidden='N'", // Rol_GST
" AND Hidden='N'", // Rol_USR
" AND Hidden='N'", // Rol_STD
" AND Hidden='N'", // Rol_NET
"", // Rol_TCH
" AND Hidden='N'", // Rol_DEG_ADM
" AND Hidden='N'", // Rol_CTR_ADM
" AND Hidden='N'", // Rol_INS_ADM
"", // Rol_SYS_ADM
};
static const char *OrderBySubQuery[Dat_NUM_START_END_TIME][Att_NUM_ORDERS_NEWEST_OLDEST] =
{
{ // Dat_START_TIME
"StartTime DESC,EndTime DESC,Title DESC", // Att_NEWEST_FIRST
"StartTime,EndTime,Title", // Att_OLDEST_FIRST
},
{ // Dat_END_TIME
"EndTime DESC,StartTime DESC,Title DESC", // Att_NEWEST_FIRST
"EndTime,StartTime,Title", // Att_OLDEST_FIRST
}
};
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
unsigned NumAttEvent;
if (Gbl.AttEvents.LstIsRead)
Att_FreeListAttEvents ();
/***** Get list of attendance events from database *****/
if (Gbl.Crs.Grps.WhichGrps == Grp_MY_GROUPS)
NumRows = DB_QuerySELECT (&mysql_res,"can not get attendance events",
"SELECT AttCod"
" FROM att_events"
" WHERE CrsCod=%ld%s"
" AND (AttCod NOT IN (SELECT AttCod FROM att_grp) OR"
" AttCod IN (SELECT att_grp.AttCod FROM att_grp,crs_grp_usr"
" WHERE crs_grp_usr.UsrCod=%ld"
" AND att_grp.GrpCod=crs_grp_usr.GrpCod))"
" ORDER BY %s",
Gbl.Hierarchy.Crs.CrsCod,
HiddenSubQuery[Gbl.Usrs.Me.Role.Logged],
Gbl.Usrs.Me.UsrDat.UsrCod,
OrderBySubQuery[Gbl.AttEvents.SelectedOrder][OrderNewestOldest]);
else // Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS
NumRows = DB_QuerySELECT (&mysql_res,"can not get attendance events",
"SELECT AttCod"
" FROM att_events"
" WHERE CrsCod=%ld%s"
" ORDER BY %s",
Gbl.Hierarchy.Crs.CrsCod,
HiddenSubQuery[Gbl.Usrs.Me.Role.Logged],
OrderBySubQuery[Gbl.AttEvents.SelectedOrder][OrderNewestOldest]);
if (NumRows) // Attendance events found...
{
Gbl.AttEvents.Num = (unsigned) NumRows;
/***** Create list of attendance events *****/
if ((Gbl.AttEvents.Lst = (struct AttendanceEvent *) calloc (NumRows,sizeof (struct AttendanceEvent))) == NULL)
Lay_NotEnoughMemoryExit ();
/***** Get the attendance events codes *****/
for (NumAttEvent = 0;
NumAttEvent < Gbl.AttEvents.Num;
NumAttEvent++)
{
/* Get next attendance event code */
row = mysql_fetch_row (mysql_res);
if ((Gbl.AttEvents.Lst[NumAttEvent].AttCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Error: wrong attendance event code.");
}
}
else
Gbl.AttEvents.Num = 0;
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
Gbl.AttEvents.LstIsRead = true;
}
/*****************************************************************************/
/********* Get attendance event data using its code and check course *********/
/*****************************************************************************/
static void Att_GetDataOfAttEventByCodAndCheckCrs (struct AttendanceEvent *Att)
{
if (Att_GetDataOfAttEventByCod (Att))
{
if (Att->CrsCod != Gbl.Hierarchy.Crs.CrsCod)
Lay_ShowErrorAndExit ("Attendance event does not belong to current course.");
}
else // Attendance event not found
Lay_ShowErrorAndExit ("Error when getting attendance event.");
}
/*****************************************************************************/
/**************** Get attendance event data using its code *******************/
/*****************************************************************************/
// Returns true if attendance event exists
// This function can be called from web service, so do not display messages
bool Att_GetDataOfAttEventByCod (struct AttendanceEvent *Att)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
bool Found = false;
/***** Reset attendance event data *****/
Att_ResetAttendanceEvent (Att);
if (Att->AttCod > 0)
{
/***** Build query *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get attendance event data",
"SELECT AttCod,CrsCod,Hidden,UsrCod,"
"UNIX_TIMESTAMP(StartTime),"
"UNIX_TIMESTAMP(EndTime),"
"NOW() BETWEEN StartTime AND EndTime,"
"CommentTchVisible,"
"Title"
" FROM att_events"
" WHERE AttCod=%ld",
Att->AttCod);
/***** Get data of attendance event from database *****/
if ((Found = (NumRows != 0))) // Attendance event found...
{
/* Get row */
row = mysql_fetch_row (mysql_res);
/* Get code of the attendance event (row[0]) */
Att->AttCod = Str_ConvertStrCodToLongCod (row[0]);
/* Get code of the course (row[1]) */
Att->CrsCod = Str_ConvertStrCodToLongCod (row[1]);
/* Get whether the attendance event is hidden or not (row[2]) */
Att->Hidden = (row[2][0] == 'Y');
/* Get author of the attendance event (row[3]) */
Att->UsrCod = Str_ConvertStrCodToLongCod (row[3]);
/* Get start date (row[4] holds the start UTC time) */
Att->TimeUTC[Att_START_TIME] = Dat_GetUNIXTimeFromStr (row[4]);
/* Get end date (row[5] holds the end UTC time) */
Att->TimeUTC[Att_END_TIME ] = Dat_GetUNIXTimeFromStr (row[5]);
/* Get whether the attendance event is open or closed (row(6)) */
Att->Open = (row[6][0] == '1');
/* Get whether the attendance event is visible or not (row[7]) */
Att->CommentTchVisible = (row[7][0] == 'Y');
/* Get the title of the attendance event (row[8]) */
Str_Copy (Att->Title,row[8],
Att_MAX_BYTES_ATTENDANCE_EVENT_TITLE);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
return Found;
}
/*****************************************************************************/
/********************** Clear all attendance event data **********************/
/*****************************************************************************/
static void Att_ResetAttendanceEvent (struct AttendanceEvent *Att)
{
if (Att->AttCod <= 0) // If > 0 ==> keep values of AttCod and Selected
{
Att->AttCod = -1L;
Att->NumStdsTotal = 0;
Att->NumStdsFromList = 0;
Att->Selected = false;
}
Att->CrsCod = -1L;
Att->Hidden = false;
Att->UsrCod = -1L;
Att->TimeUTC[Att_START_TIME] =
Att->TimeUTC[Att_END_TIME ] = (time_t) 0;
Att->Open = false;
Att->Title[0] = '\0';
Att->CommentTchVisible = false;
}
/*****************************************************************************/
/********************** Free list of attendance events ***********************/
/*****************************************************************************/
void Att_FreeListAttEvents (void)
{
if (Gbl.AttEvents.LstIsRead && Gbl.AttEvents.Lst)
{
/***** Free memory used by the list of attendance events *****/
free ((void *) Gbl.AttEvents.Lst);
Gbl.AttEvents.Lst = NULL;
Gbl.AttEvents.Num = 0;
Gbl.AttEvents.LstIsRead = false;
}
}
/*****************************************************************************/
/***************** Get attendance event text from database *******************/
/*****************************************************************************/
static void Att_GetAttEventDescriptionFromDB (long AttCod,char Description[Cns_MAX_BYTES_TEXT + 1])
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
/***** Get text of attendance event from database *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get attendance event text",
"SELECT Txt FROM att_events"
" WHERE AttCod=%ld AND CrsCod=%ld",
AttCod,Gbl.Hierarchy.Crs.CrsCod);
/***** The result of the query must have one row or none *****/
if (NumRows == 1)
{
/* Get row */
row = mysql_fetch_row (mysql_res);
/* Get info text */
Str_Copy (Description,row[0],
Cns_MAX_BYTES_TEXT);
}
else
Description[0] = '\0';
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
if (NumRows > 1)
Lay_ShowErrorAndExit ("Error when getting attendance event text.");
}
/*****************************************************************************/
/************** Write parameter with code of attendance event ****************/
/*****************************************************************************/
void Att_PutParamSelectedAttCod (void)
{
Att_PutParamAttCod (Gbl.AttEvents.AttCod);
}
void Att_PutParamAttCod (long AttCod)
{
Par_PutHiddenParamLong ("AttCod",AttCod);
}
/*****************************************************************************/
/*************** Get parameter with code of attendance event *****************/
/*****************************************************************************/
long Att_GetParamAttCod (void)
{
/***** Get code of attendance event *****/
return Par_GetParToLong ("AttCod");
}
/*****************************************************************************/
/********* Ask for confirmation of removing of an attendance event ***********/
/*****************************************************************************/
void Att_AskRemAttEvent (void)
{
extern const char *Txt_Do_you_really_want_to_remove_the_event_X;
extern const char *Txt_Remove_event;
struct AttendanceEvent Att;
/***** Get parameters *****/
Att_GetParamAttOrder ();
Grp_GetParamWhichGrps ();
Gbl.AttEvents.CurrentPage = Pag_GetParamPagNum (Pag_ATT_EVENTS);
/***** Get attendance event code *****/
if ((Att.AttCod = Att_GetParamAttCod ()) == -1L)
Lay_ShowErrorAndExit ("Code of attendance event is missing.");
/***** Get data of the attendance event from database *****/
Att_GetDataOfAttEventByCodAndCheckCrs (&Att);
/***** Button of confirmation of removing *****/
Frm_StartForm (ActRemAtt);
Att_PutParamAttCod (Att.AttCod);
Att_PutHiddenParamAttOrder ();
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
/* Ask for confirmation of removing */
Ale_ShowAlert (Ale_WARNING,Txt_Do_you_really_want_to_remove_the_event_X,
Att.Title);
Btn_PutRemoveButton (Txt_Remove_event);
Frm_EndForm ();
/***** Show attendance events again *****/
Att_SeeAttEvents ();
}
/*****************************************************************************/
/** Get param., remove an attendance event and show attendance events again **/
/*****************************************************************************/
void Att_GetAndRemAttEvent (void)
{
extern const char *Txt_Event_X_removed;
struct AttendanceEvent Att;
/***** Get attendance event code *****/
if ((Att.AttCod = Att_GetParamAttCod ()) == -1L)
Lay_ShowErrorAndExit ("Code of attendance event is missing.");
/***** Get data of the attendance event from database *****/
// Inside this function, the course is checked to be the current one
Att_GetDataOfAttEventByCodAndCheckCrs (&Att);
/***** Remove the attendance event from database *****/
Att_RemoveAttEventFromDB (Att.AttCod);
/***** Write message to show the change made *****/
Ale_ShowAlert (Ale_SUCCESS,Txt_Event_X_removed,
Att.Title);
/***** Show attendance events again *****/
Att_SeeAttEvents ();
}
/*****************************************************************************/
/**************** Remove an attendance event from database *******************/
/*****************************************************************************/
void Att_RemoveAttEventFromDB (long AttCod)
{
/***** Remove users registered in the attendance event *****/
Att_RemoveAllUsrsFromAnAttEvent (AttCod);
/***** Remove all the groups of this attendance event *****/
Att_RemoveAllTheGrpsAssociatedToAnAttEvent (AttCod);
/***** Remove attendance event *****/
Att_RemoveAttEventFromCurrentCrs (AttCod);
}
/*****************************************************************************/
/************************* Hide an attendance event **************************/
/*****************************************************************************/
void Att_HideAttEvent (void)
{
struct AttendanceEvent Att;
/***** Get attendance event code *****/
if ((Att.AttCod = Att_GetParamAttCod ()) == -1L)
Lay_ShowErrorAndExit ("Code of attendance event is missing.");
/***** Get data of the attendance event from database *****/
Att_GetDataOfAttEventByCodAndCheckCrs (&Att);
/***** Hide attendance event *****/
DB_QueryUPDATE ("can not hide attendance event",
"UPDATE att_events SET Hidden='Y'"
" WHERE AttCod=%ld AND CrsCod=%ld",
Att.AttCod,Gbl.Hierarchy.Crs.CrsCod);
/***** Show attendance events again *****/
Att_SeeAttEvents ();
}
/*****************************************************************************/
/************************* Show an attendance event **************************/
/*****************************************************************************/
void Att_ShowAttEvent (void)
{
struct AttendanceEvent Att;
/***** Get attendance event code *****/
if ((Att.AttCod = Att_GetParamAttCod ()) == -1L)
Lay_ShowErrorAndExit ("Code of attendance event is missing.");
/***** Get data of the attendance event from database *****/
Att_GetDataOfAttEventByCodAndCheckCrs (&Att);
/***** Hide attendance event *****/
DB_QueryUPDATE ("can not show attendance event",
"UPDATE att_events SET Hidden='N'"
" WHERE AttCod=%ld AND CrsCod=%ld",
Att.AttCod,Gbl.Hierarchy.Crs.CrsCod);
/***** Show attendance events again *****/
Att_SeeAttEvents ();
}
/*****************************************************************************/
/***** Check if the title or the folder of an attendance event exists ********/
/*****************************************************************************/
static bool Att_CheckIfSimilarAttEventExists (const char *Field,const char *Value,long AttCod)
{
/***** Get number of attendance events
with a field value from database *****/
return (DB_QueryCOUNT ("can not get similar attendance events",
"SELECT COUNT(*) FROM att_events"
" WHERE CrsCod=%ld"
" AND %s='%s' AND AttCod<>%ld",
Gbl.Hierarchy.Crs.CrsCod,
Field,Value,AttCod) != 0);
}
/*****************************************************************************/
/*************** Put a form to create a new attendance event *****************/
/*****************************************************************************/
void Att_RequestCreatOrEditAttEvent (void)
{
extern const char *Hlp_USERS_Attendance_new_event;
extern const char *Hlp_USERS_Attendance_edit_event;
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_New_event;
extern const char *Txt_Edit_event;
extern const char *Txt_Teachers_comment;
extern const char *Txt_Title;
extern const char *Txt_Hidden_MALE_PLURAL;
extern const char *Txt_Visible_MALE_PLURAL;
extern const char *Txt_Description;
extern const char *Txt_Create_event;
extern const char *Txt_Save_changes;
struct AttendanceEvent Att;
bool ItsANewAttEvent;
char Description[Cns_MAX_BYTES_TEXT + 1];
/***** Get parameters *****/
Att_GetParamAttOrder ();
Grp_GetParamWhichGrps ();
Gbl.AttEvents.CurrentPage = Pag_GetParamPagNum (Pag_ATT_EVENTS);
/***** Get the code of the attendance event *****/
Att.AttCod = Att_GetParamAttCod ();
ItsANewAttEvent = (Att.AttCod <= 0);
/***** Get from the database the data of the attendance event *****/
if (ItsANewAttEvent)
{
/* Reset attendance event data */
Att.AttCod = -1L;
Att_ResetAttendanceEvent (&Att);
/* Initialize some fields */
Att.CrsCod = Gbl.Hierarchy.Crs.CrsCod;
Att.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
Att.TimeUTC[Att_START_TIME] = Gbl.StartExecutionTimeUTC;
Att.TimeUTC[Att_END_TIME ] = Gbl.StartExecutionTimeUTC + (2 * 60 * 60); // +2 hours
Att.Open = true;
}
else
{
/* Get data of the attendance event from database */
Att_GetDataOfAttEventByCodAndCheckCrs (&Att);
/* Get text of the attendance event from database */
Att_GetAttEventDescriptionFromDB (Att.AttCod,Description);
}
/***** Begin form *****/
if (ItsANewAttEvent)
Frm_StartForm (ActNewAtt);
else
{
Frm_StartForm (ActChgAtt);
Att_PutParamAttCod (Att.AttCod);
}
Att_PutHiddenParamAttOrder ();
Grp_PutParamWhichGrps ();
Pag_PutHiddenParamPagNum (Pag_ATT_EVENTS,Gbl.AttEvents.CurrentPage);
/***** Begin box and table *****/
if (ItsANewAttEvent)
Box_StartBoxTable (NULL,Txt_New_event,NULL,
Hlp_USERS_Attendance_new_event,Box_NOT_CLOSABLE,2);
else
Box_StartBoxTable (NULL,
Att.Title[0] ? Att.Title :
Txt_Edit_event,
NULL,
Hlp_USERS_Attendance_edit_event,Box_NOT_CLOSABLE,2);
/***** Attendance event title *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT\"");
fprintf (Gbl.F.Out,"