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