// 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-2015 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 **********************************/ /*****************************************************************************/ #include // For PATH_MAX #include // For NULL #include // To access MySQL databases #include // For calloc #include // For string functions #include "swad_attendance.h" #include "swad_database.h" #include "swad_global.h" #include "swad_group.h" #include "swad_ID.h" #include "swad_pagination.h" #include "swad_parameter.h" #include "swad_photo.h" #include "swad_QR.h" /*****************************************************************************/ /*************** External global variables from others modules ***************/ /*****************************************************************************/ extern struct Globals Gbl; extern struct Act_Actions Act_Actions[Act_NUM_ACTIONS]; /*****************************************************************************/ /****************************** Private constants ****************************/ /*****************************************************************************/ /*****************************************************************************/ /******************************** Private types ******************************/ /*****************************************************************************/ /*****************************************************************************/ /****************************** Private variables ****************************/ /*****************************************************************************/ /*****************************************************************************/ /****************************** Private prototypes ***************************/ /*****************************************************************************/ static void Att_ShowAllAttEvents (void); static void Att_PutFormToSelectWhichGroupsToShow (void); static void Att_ShowOneAttEvent (struct AttendanceEvent *Att,bool ShowOnlyThisAttEventComplete); static void Att_WriteAttEventAuthor (struct AttendanceEvent *Att); static void Att_GetParamAttOrderType (void); static void Att_PutFormToListStds (void); static void Att_PutFormToCreateNewAttEvent (void); static void Att_PutFormsToRemEditOneAttEvent (long AttCod,bool Hidden); static void Att_GetListAttEvents (Att_OrderTime_t Order); static void Att_GetDataOfAttEventByCodAndCheckCrs (struct AttendanceEvent *Att); static void Att_GetAttEventTxtFromDB (long AttCod,char *Txt); 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_ListAttOnlyMeAsStudent (struct AttendanceEvent *Att); static void Att_ListAttStudents (struct AttendanceEvent *Att); static void Att_WriteRowStdToCallTheRoll (unsigned NumStd,struct UsrData *UsrDat,struct AttendanceEvent *Att); static void Att_PutParamsCodGrps (long AttCod); static void Att_GetNumStdsTotalWhoAreInAttEvent (struct AttendanceEvent *Att); static unsigned Att_GetNumStdsFromAListWhoAreInAttEvent (long AttCod,long LstSelectedUsrCods[],unsigned NumStdsInList); 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,char *CommentTch); 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 Att_GetListSelectedUsrCods (unsigned NumStdsInList,long **LstSelectedUsrCods); static void Att_GetListSelectedAttCods (char **StrAttCodsSelected); static void Att_PutFormToPrintListStds (bool ShowDetails,char *StrAttCodsSelected); static void Att_PutButtonToShowDetails (char *StrAttCodsSelected); static void Att_ListEventsToSelect (void); static void Att_ListStdsAttendanceTable (unsigned NumStdsInList,long *LstSelectedUsrCods); static void Att_WriteTableHeadSeveralAttEvents (void); static void Att_WriteRowStdSeveralAttEvents (unsigned NumStd,struct UsrData *UsrDat); static void Att_ListStdsWithAttEventsDetails (unsigned NumStdsInList,long *LstSelectedUsrCods); static void Att_ListAttEventsForAStd (unsigned NumStd,struct UsrData *UsrDat); /*****************************************************************************/ /********************** List all the attendance events ***********************/ /*****************************************************************************/ void Att_SeeAttEvents (void) { /***** Get parameters *****/ Att_GetParamAttOrderType (); Grp_GetParamWhichGrps (); Pag_GetParamPagNum (Pag_ATT_EVENTS); /***** Put other options *****/ fprintf (Gbl.F.Out,"
"); /* Put link (form) to create a bew attendance event */ switch (Gbl.Usrs.Me.LoggedRole) { case Rol_ROLE_TEACHER: case Rol_ROLE_SUPERUSER: Att_PutFormToCreateNewAttEvent (); Att_PutFormToListStds (); break; default: break; } /* Put link to my QR code */ if (Gbl.Usrs.Me.UsrDat.Nickname[0]) QR_PutLinkToPrintQRCode (QR_NICKNAME,&Gbl.Usrs.Me.UsrDat,true); fprintf (Gbl.F.Out,"
"); /***** Show all the attendance events *****/ Att_ShowAllAttEvents (); } /*****************************************************************************/ /********************** Show all the attendance events ***********************/ /*****************************************************************************/ static void Att_ShowAllAttEvents (void) { extern const char *Txt_Events; extern const char *Txt_ASG_ATT_OR_SVY_HELP_ORDER[2]; extern const char *Txt_ASG_ATT_OR_SVY_ORDER[2]; extern const char *Txt_Event; extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; Att_EventsOrderType_t Order; struct Pagination Pagination; unsigned NumAttEvent; /***** Get list of attendance events *****/ Att_GetListAttEvents (Att_NEWEST_FIRST); /***** Compute variables related to pagination *****/ Pagination.NumItems = Gbl.AttEvents.Num; Pagination.CurrentPage = (int) Gbl.Pag.CurrentPage; Pag_CalculatePagination (&Pagination); Gbl.Pag.CurrentPage = (unsigned) Pagination.CurrentPage; /***** Write links to pages *****/ if (Pagination.MoreThanOnePage) Pag_WriteLinksToPagesCentered (Pag_ATT_EVENTS,0,&Pagination); /***** Table start *****/ Lay_StartRoundFrameTable10 (NULL,2,Txt_Events); /***** Select whether show only my groups or all groups *****/ if (Gbl.CurrentCrs.Grps.NumGrps) { fprintf (Gbl.F.Out,"" ""); Att_PutFormToSelectWhichGroupsToShow (); fprintf (Gbl.F.Out,"" ""); } /***** Table head *****/ fprintf (Gbl.F.Out,""); for (Order = Att_ORDER_BY_START_DATE; Order <= Att_ORDER_BY_END_DATE; Order++) { fprintf (Gbl.F.Out,""); Act_FormStart (ActSeeAtt); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); Par_PutHiddenParamUnsigned ("Order",(unsigned) Order); Act_LinkFormSubmit (Txt_ASG_ATT_OR_SVY_HELP_ORDER[Order],"TIT_TBL"); if (Order == Gbl.AttEvents.SelectedOrderType) fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"%s",Txt_ASG_ATT_OR_SVY_ORDER[Order]); if (Order == Gbl.AttEvents.SelectedOrderType) fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"" "" ""); } fprintf (Gbl.F.Out,"" "%s" "" "" "%s" "" "", Txt_Event, Txt_ROLES_PLURAL_Abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN]); /***** Write all the attendance events *****/ for (NumAttEvent = Pagination.FirstItemVisible, Gbl.RowEvenOdd = 0; NumAttEvent <= Pagination.LastItemVisible; NumAttEvent++) Att_ShowOneAttEvent (&Gbl.AttEvents.Lst[NumAttEvent-1],false); /***** Table end *****/ Lay_EndRoundFrameTable10 (); /***** Write again links to pages *****/ if (Pagination.MoreThanOnePage) Pag_WriteLinksToPagesCentered (Pag_ATT_EVENTS,0,&Pagination); /***** Free list of attendance events *****/ Att_FreeListAttEvents (); } /*****************************************************************************/ /***************** Put form to select which groups to show *******************/ /*****************************************************************************/ static void Att_PutFormToSelectWhichGroupsToShow (void) { Act_FormStart (ActSeeAtt); Att_PutHiddenParamAttOrderType (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); Grp_ShowSelectorWhichGrps (); fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /************************* 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 Txt[Cns_MAX_BYTES_TEXT+1]; /***** Get data of this attendance event *****/ Att_GetDataOfAttEventByCodAndCheckCrs (Att); Att_GetNumStdsTotalWhoAreInAttEvent (Att); /***** Start date/time *****/ fprintf (Gbl.F.Out,"" \ "Hidden ? (Att->Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT") : (Att->Open ? "DATE_GREEN" : "DATE_RED")); if (!ShowOnlyThisAttEventComplete) fprintf (Gbl.F.Out," bgcolor=\"%s\"",Gbl.ColorRows[Gbl.RowEvenOdd]); fprintf (Gbl.F.Out,">%02u/%02u/%02u
%02u:%02u h", Att->DateTimes[Att_START_TIME].Date.Day, Att->DateTimes[Att_START_TIME].Date.Month, Att->DateTimes[Att_START_TIME].Date.Year % 100, Att->DateTimes[Att_START_TIME].Time.Hour, Att->DateTimes[Att_START_TIME].Time.Minute); /***** End date/time *****/ fprintf (Gbl.F.Out,"Hidden ? (Att->Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT") : (Att->Open ? "DATE_GREEN" : "DATE_RED")); if (!ShowOnlyThisAttEventComplete) fprintf (Gbl.F.Out," background-color:%s;", Gbl.ColorRows[Gbl.RowEvenOdd]); fprintf (Gbl.F.Out,"\">" "%02u/%02u/%02u
%02u:%02u h" "", Att->DateTimes[Att_END_TIME ].Date.Day, Att->DateTimes[Att_END_TIME ].Date.Month, Att->DateTimes[Att_END_TIME ].Date.Year % 100, Att->DateTimes[Att_END_TIME ].Time.Hour, Att->DateTimes[Att_END_TIME ].Time.Minute); /***** Attendance event title *****/ fprintf (Gbl.F.Out,""); /* Put form to view attendance event */ Act_FormStart (ActSeeOneAtt); Att_PutParamAttCod (Att->AttCod); Att_PutParamsCodGrps (Att->AttCod); Act_LinkFormSubmit (Txt_View_event,Att->Hidden ? "ASG_TITLE_LIGHT" : "ASG_TITLE"); fprintf (Gbl.F.Out,"%s", Att->Title); /***** Number of students in this event *****/ fprintf (Gbl.F.Out,"" "%u" "" "", Att->NumStdsTotal); /***** Write second row of data of this attendance event *****/ fprintf (Gbl.F.Out,"" "", Gbl.ColorRows[Gbl.RowEvenOdd]); /* Author of the attendance event */ Att_WriteAttEventAuthor (Att); /* Forms to remove/edit this attendance event */ switch (Gbl.Usrs.Me.LoggedRole) { case Rol_ROLE_TEACHER: case Rol_ROLE_SUPERUSER: Att_PutFormsToRemEditOneAttEvent (Att->AttCod,Att->Hidden); break; default: break; } fprintf (Gbl.F.Out,""); /* Text of the attendance event */ Att_GetAttEventTxtFromDB (Att->AttCod,Txt); Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Txt,Cns_MAX_BYTES_TEXT,false); // Convert from HTML to recpectful HTML Str_InsertLinkInURLs (Txt,Cns_MAX_BYTES_TEXT,60); // Insert links fprintf (Gbl.F.Out,"", Gbl.ColorRows[Gbl.RowEvenOdd]); if (Gbl.CurrentCrs.Grps.NumGrps) Att_GetAndWriteNamesOfGrpsAssociatedToAttEvent (Att); fprintf (Gbl.F.Out,"

%s

", Att->Hidden ? "DAT_LIGHT" : "DAT", Txt); fprintf (Gbl.F.Out,"" ""); Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; } /*****************************************************************************/ /****************** Write the author of an attendance event ******************/ /*****************************************************************************/ static void Att_WriteAttEventAuthor (struct AttendanceEvent *Att) { bool ShowPhoto = false; char PhotoURL[PATH_MAX+1]; char FirstName[Usr_MAX_BYTES_NAME+1]; char Surnames[2*(Usr_MAX_BYTES_NAME+1)]; struct UsrData UsrDat; /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Get data of author *****/ UsrDat.UsrCod = Att->UsrCod; if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // Get of the database the data of the author ShowPhoto = Pho_ShowUsrPhotoIsAllowed (&UsrDat,PhotoURL); /***** Show photo *****/ Pho_ShowUsrPhoto (&UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO12x16",true); /***** Write name *****/ strcpy (FirstName,UsrDat.FirstName); strcpy (Surnames,UsrDat.Surname1); if (UsrDat.Surname2[0]) { strcat (Surnames," "); strcat (Surnames,UsrDat.Surname2); } Str_LimitLengthHTMLStr (FirstName,9); Str_LimitLengthHTMLStr (Surnames,9); fprintf (Gbl.F.Out,"%s %s", Att->Hidden ? "MSG_AUT_LIGHT" : "MSG_AUT", FirstName,Surnames); /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /**** Get parameter with the type or order in list of attendance events ******/ /*****************************************************************************/ static void Att_GetParamAttOrderType (void) { char UnsignedStr[10+1]; unsigned UnsignedNum; Par_GetParToText ("Order",UnsignedStr,10); if (sscanf (UnsignedStr,"%u",&UnsignedNum) == 1) Gbl.AttEvents.SelectedOrderType = (Att_EventsOrderType_t) UnsignedNum; else Gbl.AttEvents.SelectedOrderType = Att_DEFAULT_ORDER_TYPE; } /*****************************************************************************/ /*** Put a hidden parameter with the type of order in list of att. events ****/ /*****************************************************************************/ void Att_PutHiddenParamAttOrderType (void) { Par_PutHiddenParamUnsigned ("Order",(unsigned) Gbl.AttEvents.SelectedOrderType); } /*****************************************************************************/ /**** Put a link (form) to list assistance of students to several events *****/ /*****************************************************************************/ static void Att_PutFormToListStds (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Attendance_list; /***** Put form to create a new attendance event *****/ Act_FormStart (ActReqLstAttStd); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); Act_LinkFormSubmit (Txt_Attendance_list,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("list",Txt_Attendance_list,Txt_Attendance_list); fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /*********** Put a link (form) to create a new attendance event **************/ /*****************************************************************************/ static void Att_PutFormToCreateNewAttEvent (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_New_event; /***** Put form to create a new attendance event *****/ Act_FormStart (ActFrmNewAtt); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); Act_LinkFormSubmit (Txt_New_event,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("new",Txt_New_event,Txt_New_event); fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /************** Put a link (form) to edit one attendance event ***************/ /*****************************************************************************/ static void Att_PutFormsToRemEditOneAttEvent (long AttCod,bool Hidden) { extern const char *Txt_Remove; extern const char *Txt_Show; extern const char *Txt_Hide; extern const char *Txt_Edit; /***** Put form to remove attendance event *****/ fprintf (Gbl.F.Out,"" "" "", Gbl.Prefs.IconsURL, Txt_Remove, Txt_Remove); /***** Put form to hide/show attendance event *****/ fprintf (Gbl.F.Out,""); /***** Put form to edit attendance event *****/ fprintf (Gbl.F.Out,"" "" "
"); Act_FormStart (ActReqRemAtt); Att_PutParamAttCod (AttCod); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); fprintf (Gbl.F.Out,"" "" ""); Act_FormStart (Hidden ? ActShoAtt : ActHidAtt); Att_PutParamAttCod (AttCod); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); if (Hidden) fprintf (Gbl.F.Out,"", Gbl.Prefs.IconsURL, Txt_Show, Txt_Show); else fprintf (Gbl.F.Out,"", Gbl.Prefs.IconsURL, Txt_Hide, Txt_Hide); fprintf (Gbl.F.Out,"" ""); Act_FormStart (ActEdiOneAtt); Att_PutParamAttCod (AttCod); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); fprintf (Gbl.F.Out,"" "" "
", Gbl.Prefs.IconsURL, Txt_Edit, Txt_Edit); } /*****************************************************************************/ /********************* List all the attendance events ************************/ /*****************************************************************************/ static void Att_GetListAttEvents (Att_OrderTime_t Order) { char HiddenSubQuery[256]; char OrderBySubQuery[256]; char Query[2048]; 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 *****/ switch (Gbl.Usrs.Me.LoggedRole) { case Rol_ROLE_TEACHER: case Rol_ROLE_SUPERUSER: HiddenSubQuery[0] = '\0'; break; default: sprintf (HiddenSubQuery,"AND Hidden='N'"); break; } switch (Gbl.AttEvents.SelectedOrderType) { case Att_ORDER_BY_START_DATE: if (Order == Att_NEWEST_FIRST) sprintf (OrderBySubQuery,"StartTime DESC,EndTime DESC,Title DESC"); else sprintf (OrderBySubQuery,"StartTime,EndTime,Title"); break; case Att_ORDER_BY_END_DATE: if (Order == Att_NEWEST_FIRST) sprintf (OrderBySubQuery,"EndTime DESC,StartTime DESC,Title DESC"); else sprintf (OrderBySubQuery,"EndTime,StartTime,Title"); break; } if (Gbl.CurrentCrs.Grps.WhichGrps == Grp_ONLY_MY_GROUPS) sprintf (Query,"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.CurrentCrs.Crs.CrsCod,HiddenSubQuery,Gbl.Usrs.Me.UsrDat.UsrCod,OrderBySubQuery); else // Gbl.CurrentCrs.Grps.WhichGrps == Grp_ALL_GROUPS sprintf (Query,"SELECT AttCod" " FROM att_events" " WHERE CrsCod='%ld'%s" " ORDER BY %s", Gbl.CurrentCrs.Crs.CrsCod,HiddenSubQuery,OrderBySubQuery); if ((NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get attendance events"))) // 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_ShowErrorAndExit ("Not enough memory to store list of attendance events."); /***** 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.CurrentCrs.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) { char Query[1024]; MYSQL_RES *mysql_res; MYSQL_ROW row; bool Found; /***** Build query *****/ sprintf (Query,"SELECT AttCod,CrsCod,Hidden,UsrCod," "DATE_FORMAT(StartTime,'%%Y%%m%%d%%H%%i%%S')," "DATE_FORMAT(EndTime,'%%Y%%m%%d%%H%%i%%S')," "NOW() BETWEEN StartTime AND EndTime," "CommentTchVisible," "Title" " FROM att_events" " WHERE AttCod='%ld'", Att->AttCod); /***** Clear data *****/ Att->DateTimes[Att_START_TIME].Date.Day = Att->DateTimes[Att_START_TIME].Date.Month = Att->DateTimes[Att_START_TIME].Date.Year = 0; Att->Title[0] = '\0'; /***** Get data of attendance event from database *****/ if ((Found = (DB_QuerySELECT (Query,&mysql_res,"can not get attendance event data") != 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 wether the attendance event is hidden or not (row[2]) */ Att->Hidden = (Str_ConvertToUpperLetter (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 date in YYYYMMDDHHMMSS format) */ if (!(Dat_GetDateTimeFromYYYYMMDDHHMMSS (&(Att->DateTimes[Att_START_TIME]),row[4]))) Lay_ShowErrorAndExit ("Error when reading start date of attendance event."); /* Get end date (row[5] holds the end date in YYYYMMDDHHMMSS format) */ if (!(Dat_GetDateTimeFromYYYYMMDDHHMMSS (&(Att->DateTimes[Att_END_TIME]),row[5]))) Lay_ShowErrorAndExit ("Error when reading end date of attendance event."); /* 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]) */ strcpy (Att->Title,row[8]); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return Found; } /*****************************************************************************/ /********************** 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_GetAttEventTxtFromDB (long AttCod,char *Txt) { char Query[512]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; /***** Get text of attendance event from database *****/ sprintf (Query,"SELECT Txt FROM att_events WHERE AttCod='%ld' AND CrsCod='%ld'", AttCod,Gbl.CurrentCrs.Crs.CrsCod); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get attendance event text"); /***** The result of the query must have one row or none *****/ if (NumRows == 1) { /* Get info text */ row = mysql_fetch_row (mysql_res); strcpy (Txt,row[0]); } else Txt[0] = '\0'; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); if (NumRows > 1) Lay_ShowErrorAndExit ("Error when getting attendance event text."); } /*****************************************************************************/ /************** Get summary and content of an attendance event ***************/ /*****************************************************************************/ // This function may be called inside a web service, so don't report error void Att_GetNotifAttEvent (char *SummaryStr,char **ContentStr,long AttCod,unsigned MaxChars,bool GetContent) { extern const char *Txt_Start_date; extern const char *Txt_End_date; char Query[512]; MYSQL_RES *mysql_res; MYSQL_ROW row; struct DateTime DateTimes[Att_NUM_DATES]; SummaryStr[0] = '\0'; // Return nothing on error /***** Build query *****/ sprintf (Query,"SELECT Title," "DATE_FORMAT(StartTime,'%%Y%%m%%d%%H%%i%%S')," "DATE_FORMAT(EndTime,'%%Y%%m%%d%%H%%i%%S')," "Txt" " FROM att_events" " WHERE AttCod='%ld'", AttCod); if (!mysql_query (&Gbl.mysql,Query)) if ((mysql_res = mysql_store_result (&Gbl.mysql)) != NULL) { /***** Result should have a unique row *****/ if (mysql_num_rows (mysql_res) == 1) { /***** Get row *****/ row = mysql_fetch_row (mysql_res); /***** Get summary *****/ strcpy (SummaryStr,row[0]); if (MaxChars) Str_LimitLengthHTMLStr (SummaryStr,MaxChars); /***** Get content *****/ if (GetContent) { if ((*ContentStr = (char *) malloc (512+Cns_MAX_BYTES_TEXT)) == NULL) Lay_ShowErrorAndExit ("Error allocating memory for notification content."); (*ContentStr)[0] = '\0'; // Return nothing on error /* Get start date (row[1] holds the start date in YYYYMMDDHHMMSS format) */ if (!(Dat_GetDateTimeFromYYYYMMDDHHMMSS (&DateTimes[Att_START_TIME],row[1]))) Lay_ShowErrorAndExit ("Error when reading start date of attendance event."); /* Get end date (row[2] holds the end date in YYYYMMDDHHMMSS format) */ if (!(Dat_GetDateTimeFromYYYYMMDDHHMMSS (&DateTimes[Att_END_TIME ],row[2]))) Lay_ShowErrorAndExit ("Error when reading end date of attendance event."); sprintf (*ContentStr,"%s: %02u/%02u/%04u %02u:%02u
%s: %02u/%02u/%04u %02u:%02u
%s", Txt_Start_date, DateTimes[Att_START_TIME].Date.Day, DateTimes[Att_START_TIME].Date.Month, DateTimes[Att_START_TIME].Date.Year, DateTimes[Att_START_TIME].Time.Hour, DateTimes[Att_START_TIME].Time.Minute, Txt_End_date, DateTimes[Att_END_TIME].Date.Day, DateTimes[Att_END_TIME].Date.Month, DateTimes[Att_END_TIME].Date.Year, DateTimes[Att_END_TIME].Time.Hour, DateTimes[Att_END_TIME].Time.Minute, row[3]); } } mysql_free_result (mysql_res); } } /*****************************************************************************/ /************** Write parameter with code of attendance event ****************/ /*****************************************************************************/ void Att_PutParamAttCod (long AttCod) { Par_PutHiddenParamLong ("AttCod",AttCod); } /*****************************************************************************/ /*************** Get parameter with code of attendance event *****************/ /*****************************************************************************/ long Att_GetParamAttCod (void) { char LongStr[1+10+1]; /***** Get parameter with code of attendance event *****/ Par_GetParToText ("AttCod",LongStr,1+10); return Str_ConvertStrCodToLongCod (LongStr); } /*****************************************************************************/ /********* 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_GetParamAttOrderType (); Grp_GetParamWhichGrps (); 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 *****/ Act_FormStart (ActRemAtt); Att_PutParamAttCod (Att.AttCod); Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); /***** Ask for confirmation of removing *****/ sprintf (Gbl.Message,Txt_Do_you_really_want_to_remove_the_event_X, Att.Title); Lay_ShowAlert (Lay_WARNING,Gbl.Message); fprintf (Gbl.F.Out,"
" "" "
" "", Txt_Remove_event); /***** Show attendance events again *****/ Att_SeeAttEvents (); } /*****************************************************************************/ /************************ Remove an attendance event *************************/ /*****************************************************************************/ void Att_RemoveAttEvent (void) { extern const char *Txt_Event_X_removed; char Query[512]; 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); // Inside this function, the course is checked to be the current one /***** Remove users registered in the attendance event *****/ sprintf (Query,"DELETE FROM att_usr" " WHERE AttCod='%ld'", Att.AttCod); DB_QueryDELETE (Query,"can not remove attendance event"); /***** Remove all the groups of this attendance event *****/ Att_RemoveAllTheGrpsAssociatedToAnAttEvent (Att.AttCod); /***** Remove attendance event *****/ sprintf (Query,"DELETE FROM att_events" " WHERE AttCod='%ld' AND CrsCod='%ld'", Att.AttCod,Gbl.CurrentCrs.Crs.CrsCod); DB_QueryDELETE (Query,"can not remove attendance event"); /***** Write message to show the change made *****/ sprintf (Gbl.Message,Txt_Event_X_removed, Att.Title); Lay_ShowAlert (Lay_SUCCESS,Gbl.Message); /***** Show attendance events again *****/ Att_SeeAttEvents (); } /*****************************************************************************/ /************************* Hide an attendance event **************************/ /*****************************************************************************/ void Att_HideAttEvent (void) { extern const char *Txt_Event_X_is_now_hidden; char Query[512]; 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 *****/ sprintf (Query,"UPDATE att_events SET Hidden='Y'" " WHERE AttCod='%ld' AND CrsCod='%ld'", Att.AttCod,Gbl.CurrentCrs.Crs.CrsCod); DB_QueryUPDATE (Query,"can not hide attendance event"); /***** Write message to show the change made *****/ sprintf (Gbl.Message,Txt_Event_X_is_now_hidden, Att.Title); Lay_ShowAlert (Lay_SUCCESS,Gbl.Message); /***** Show attendance events again *****/ Att_SeeAttEvents (); } /*****************************************************************************/ /************************* Show an attendance event **************************/ /*****************************************************************************/ void Att_ShowAttEvent (void) { extern const char *Txt_Event_X_is_now_visible; char Query[512]; 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 *****/ sprintf (Query,"UPDATE att_events SET Hidden='N'" " WHERE AttCod='%ld' AND CrsCod='%ld'", Att.AttCod,Gbl.CurrentCrs.Crs.CrsCod); DB_QueryUPDATE (Query,"can not show attendance event"); /***** Write message to show the change made *****/ sprintf (Gbl.Message,Txt_Event_X_is_now_visible, Att.Title); Lay_ShowAlert (Lay_SUCCESS,Gbl.Message); /***** 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) { char Query[512]; /***** Get number of attendance events with a field value from database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_events" " WHERE CrsCod='%ld' AND %s='%s' AND AttCod<>'%ld'", Gbl.CurrentCrs.Crs.CrsCod,Field,Value,AttCod); return (DB_QueryCOUNT (Query,"can not get similar attendance events") != 0); } /*****************************************************************************/ /*************** Put a form to create a new attendance event *****************/ /*****************************************************************************/ void Att_RequestCreatOrEditAttEvent (void) { extern const char *The_ClassFormul[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_Start_date; extern const char *Txt_End_date; 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_Modify_event; struct AttendanceEvent Att; bool ItsANewAttEvent; Att_StartOrEndTime_t StartOrEndTime; const char *NameSelectYear [Att_NUM_DATES] = {"StartYear" ,"EndYear" }; const char *NameSelectMonth [Att_NUM_DATES] = {"StartMonth" ,"EndMonth" }; const char *NameSelectDay [Att_NUM_DATES] = {"StartDay" ,"EndDay" }; const char *NameSelectHour [Att_NUM_DATES] = {"StartHour" ,"EndHour" }; const char *NameSelectMinute[Att_NUM_DATES] = {"StartMinute","EndMinute"}; const char *Dates[Att_NUM_DATES] = {Txt_Start_date,Txt_End_date}; char Txt[Cns_MAX_BYTES_TEXT+1]; /***** Get parameters *****/ Att_GetParamAttOrderType (); Grp_GetParamWhichGrps (); Pag_GetParamPagNum (Pag_ATT_EVENTS); /***** Get the code of the attendance event *****/ ItsANewAttEvent = ((Att.AttCod = Att_GetParamAttCod ()) == -1L); /***** Get from the database the data of the attendance event *****/ if (ItsANewAttEvent) { /* Initialize to empty attendance event */ Att.AttCod = -1L; Att.DateTimes[Att_START_TIME].Date.Day = Gbl.Now.Date.Day; Att.DateTimes[Att_START_TIME].Date.Month = Gbl.Now.Date.Month; Att.DateTimes[Att_START_TIME].Date.Year = Gbl.Now.Date.Year; Att.DateTimes[Att_START_TIME].Time.Hour = Gbl.Now.Time.Hour; Att.DateTimes[Att_START_TIME].Time.Minute = Gbl.Now.Time.Minute; Att.DateTimes[Att_START_TIME].Time.Second = Gbl.Now.Time.Second; Att.DateTimes[Att_END_TIME ].Date.Day = Gbl.Now.Date.Day; Att.DateTimes[Att_END_TIME ].Date.Month = Gbl.Now.Date.Month; Att.DateTimes[Att_END_TIME ].Date.Year = Gbl.Now.Date.Year; Att.DateTimes[Att_END_TIME ].Time.Hour = 23; Att.DateTimes[Att_END_TIME ].Time.Minute = 59; Att.Open = true; Att.Title[0] = '\0'; } else { /* Get data of the attendance event from database */ Att_GetDataOfAttEventByCodAndCheckCrs (&Att); /* Get text of the attendance event from database */ Att_GetAttEventTxtFromDB (Att.AttCod,Txt); } /***** Form start *****/ if (ItsANewAttEvent) Act_FormStart (ActNewAtt); else { Act_FormStart (ActChgAtt); Att_PutParamAttCod (Att.AttCod); } Att_PutHiddenParamAttOrderType (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Gbl.Pag.CurrentPage); /***** Table start *****/ Lay_StartRoundFrameTable10 (NULL,2,ItsANewAttEvent ? Txt_New_event : Txt_Edit_event); /***** Attendance event title *****/ fprintf (Gbl.F.Out,"" "" "%s:" "" "" "" "" "", Txt_Title, Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE,Att.Title); /***** Attendance event start and end dates *****/ for (StartOrEndTime = Att_START_TIME; StartOrEndTime <= Att_END_TIME; StartOrEndTime++) { fprintf (Gbl.F.Out,"" "" "%s:" "" "" "" "" "" "" "
", Dates[StartOrEndTime]); /* Date */ Dat_WriteFormDate (Gbl.Now.Date.Year-1,Gbl.Now.Date.Year+1, NameSelectDay [StartOrEndTime], NameSelectMonth[StartOrEndTime], NameSelectYear [StartOrEndTime], &(Att.DateTimes[StartOrEndTime].Date), false,false); fprintf (Gbl.F.Out,""); /* Time */ Dat_WriteFormHourMinute (NameSelectHour [StartOrEndTime], NameSelectMinute[StartOrEndTime], &(Att.DateTimes[StartOrEndTime].Time), false,false); fprintf (Gbl.F.Out,"
" ""); } /***** Visibility of comments *****/ fprintf (Gbl.F.Out,"" "" "%s:" "" "" "" "" ""); /***** Attendance event description *****/ fprintf (Gbl.F.Out,"" "" "%s:" "" "" "" "" ""); /***** Groups *****/ Att_ShowLstGrpsToEditAttEvent (Att.AttCod); /***** Table end *****/ Lay_EndRoundFrameTable10 (); /***** New attendance event *****/ Lay_PutSendButton (ItsANewAttEvent ? Txt_Create_event : Txt_Modify_event); /***** Form end *****/ fprintf (Gbl.F.Out,"
"); /***** Show current attendance events *****/ Att_ShowAllAttEvents (); } /*****************************************************************************/ /************* Show list of groups to edit and attendance event **************/ /*****************************************************************************/ static void Att_ShowLstGrpsToEditAttEvent (long AttCod) { extern const char *Txt_Groups; extern const char *Txt_The_whole_course; unsigned NumGrpTyp; /***** Get list of groups types and groups in this course *****/ Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS); if (Gbl.CurrentCrs.Grps.GrpTypes.Num) { /***** Start table *****/ fprintf (Gbl.F.Out,"" "" "%s:" "" "", Txt_Groups); Lay_StartRoundFrameTable10 (NULL,0,NULL); /***** First row: checkbox to select the whole course *****/ fprintf (Gbl.F.Out,"" "" "%s %s" "", Txt_The_whole_course,Gbl.CurrentCrs.Crs.ShortName); /***** List the groups for each group type *****/ for (NumGrpTyp = 0; NumGrpTyp < Gbl.CurrentCrs.Grps.GrpTypes.Num; NumGrpTyp++) if (Gbl.CurrentCrs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps) Grp_ListGrpsToEditAsgAttOrSvy (&Gbl.CurrentCrs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],AttCod,Grp_ATT_EVENT); /***** End table *****/ Lay_EndRoundFrameTable10 (); fprintf (Gbl.F.Out,"" ""); } /***** Free list of groups types and groups in this course *****/ Grp_FreeListGrpTypesAndGrps (); } /*****************************************************************************/ /*************** Receive form to create a new attendance event ***************/ /*****************************************************************************/ void Att_RecFormAttEvent (void) { extern const char *Txt_Already_existed_an_event_with_the_title_X; extern const char *Txt_You_must_specify_the_title_of_the_event; extern const char *Txt_Created_new_event_X; extern const char *Txt_The_event_has_been_modified; struct AttendanceEvent OldAtt,NewAtt; char YN[1+1]; bool ItsANewAttEvent; bool NewAttEventIsCorrect = true; char Txt[Cns_MAX_BYTES_TEXT+1]; /***** Get the code of the attendance event *****/ ItsANewAttEvent = ((NewAtt.AttCod = Att_GetParamAttCod ()) == -1L); if (!ItsANewAttEvent) { /* Get data of the old (current) attendance event from database */ OldAtt.AttCod = NewAtt.AttCod; Att_GetDataOfAttEventByCodAndCheckCrs (&OldAtt); } /***** Get start date *****/ Dat_GetDateFromForm ("StartDay","StartMonth","StartYear", &(NewAtt.DateTimes[Att_START_TIME].Date.Day), &(NewAtt.DateTimes[Att_START_TIME].Date.Month), &(NewAtt.DateTimes[Att_START_TIME].Date.Year)); Dat_GetHourMinuteFromForm ("StartHour","StartMinute", &(NewAtt.DateTimes[Att_START_TIME].Time.Hour), &(NewAtt.DateTimes[Att_START_TIME].Time.Minute)); NewAtt.DateTimes[Att_START_TIME].Time.Second = 0; /***** Get end date *****/ Dat_GetDateFromForm ("EndDay","EndMonth","EndYear", &(NewAtt.DateTimes[Att_END_TIME].Date.Day), &(NewAtt.DateTimes[Att_END_TIME].Date.Month), &(NewAtt.DateTimes[Att_END_TIME].Date.Year)); Dat_GetHourMinuteFromForm ("EndHour","EndMinute", &(NewAtt.DateTimes[Att_END_TIME].Time.Hour), &(NewAtt.DateTimes[Att_END_TIME].Time.Minute)); NewAtt.DateTimes[Att_END_TIME].Time.Second = 59; /***** Get boolean parameter that indicates if teacher's comments are visible by students *****/ Par_GetParToText ("CommentTchVisible",YN,1); NewAtt.CommentTchVisible = (Str_ConvertToUpperLetter (YN[0]) == 'Y'); /***** Get attendance event title *****/ Par_GetParToText ("Title",NewAtt.Title,Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE); /***** Get attendance event text *****/ Par_GetParToHTML ("Txt",Txt,Cns_MAX_BYTES_TEXT); // Store in HTML format (not rigorous) /***** Adjust dates *****/ if (NewAtt.DateTimes[Att_START_TIME].Date.Day == 0 || NewAtt.DateTimes[Att_START_TIME].Date.Month == 0 || NewAtt.DateTimes[Att_START_TIME].Date.Year == 0) { NewAtt.DateTimes[Att_START_TIME].Date.Day = Gbl.Now.Date.Day; NewAtt.DateTimes[Att_START_TIME].Date.Month = Gbl.Now.Date.Month; NewAtt.DateTimes[Att_START_TIME].Date.Year = Gbl.Now.Date.Year; NewAtt.DateTimes[Att_START_TIME].Time.Hour = Gbl.Now.Time.Hour; NewAtt.DateTimes[Att_START_TIME].Time.Minute = Gbl.Now.Time.Minute; } if (NewAtt.DateTimes[Att_END_TIME].Date.Day == 0 || NewAtt.DateTimes[Att_END_TIME].Date.Month == 0 || NewAtt.DateTimes[Att_END_TIME].Date.Year == 0) { NewAtt.DateTimes[Att_END_TIME].Date.Day = Gbl.Now.Date.Day; NewAtt.DateTimes[Att_END_TIME].Date.Month = Gbl.Now.Date.Month; NewAtt.DateTimes[Att_END_TIME].Date.Year = Gbl.Now.Date.Year; NewAtt.DateTimes[Att_END_TIME].Time.Hour = 23; NewAtt.DateTimes[Att_END_TIME].Time.Minute = 59; } /***** Check if title is correct *****/ if (NewAtt.Title[0]) // If there's an attendance event title { /* If title of attendance event was in database... */ if (Att_CheckIfSimilarAttEventExists ("Title",NewAtt.Title,NewAtt.AttCod)) { NewAttEventIsCorrect = false; sprintf (Gbl.Message,Txt_Already_existed_an_event_with_the_title_X, NewAtt.Title); Lay_ShowAlert (Lay_WARNING,Gbl.Message); } } else // If there is not an attendance event title { NewAttEventIsCorrect = false; Lay_ShowAlert (Lay_WARNING,Txt_You_must_specify_the_title_of_the_event); } /***** Create a new attendance event or update an existing one *****/ if (NewAttEventIsCorrect) { /* Get groups for this attendance events */ Grp_GetParCodsSeveralGrpsToEditAsgAttOrSvy (); if (ItsANewAttEvent) { Att_CreateAttEvent (&NewAtt,Txt); // Add new attendance event to database /***** Write success message *****/ sprintf (Gbl.Message,Txt_Created_new_event_X,NewAtt.Title); Lay_ShowAlert (Lay_SUCCESS,Gbl.Message); } else { Att_UpdateAttEvent (&NewAtt,Txt); /***** Write success message *****/ Lay_ShowAlert (Lay_SUCCESS,Txt_The_event_has_been_modified); } /* Free memory for list of selected groups */ Grp_FreeListCodSelectedGrps (); } else Att_RequestCreatOrEditAttEvent (); /***** Show attendance events again *****/ Att_SeeAttEvents (); } /*****************************************************************************/ /********************* Create a new attendance event *************************/ /*****************************************************************************/ void Att_CreateAttEvent (struct AttendanceEvent *Att,const char *Txt) { char Query[1024+Cns_MAX_BYTES_TEXT]; /***** Create a new attendance event *****/ sprintf (Query,"INSERT INTO att_events (CrsCod,UsrCod,StartTime,EndTime,CommentTchVisible,Title,Txt)" " VALUES ('%ld','%ld','%04u%02u%02u%02u%02u%02u','%04u%02u%02u%02u%02u%02u','%c','%s','%s')", Gbl.CurrentCrs.Crs.CrsCod, Gbl.Usrs.Me.UsrDat.UsrCod, Att->DateTimes[Att_START_TIME].Date.Year, Att->DateTimes[Att_START_TIME].Date.Month, Att->DateTimes[Att_START_TIME].Date.Day, Att->DateTimes[Att_START_TIME].Time.Hour, Att->DateTimes[Att_START_TIME].Time.Minute, Att->DateTimes[Att_START_TIME].Time.Second, Att->DateTimes[Att_END_TIME ].Date.Year, Att->DateTimes[Att_END_TIME ].Date.Month, Att->DateTimes[Att_END_TIME ].Date.Day, Att->DateTimes[Att_END_TIME ].Time.Hour, Att->DateTimes[Att_END_TIME ].Time.Minute, Att->DateTimes[Att_END_TIME ].Time.Second, Att->CommentTchVisible ? 'Y' : 'N', Att->Title, Txt); Att->AttCod = DB_QueryINSERTandReturnCode (Query,"can not create new attendance event"); /***** Create groups *****/ if (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps) Att_CreateGrps (Att->AttCod); } /*****************************************************************************/ /****************** Update an existing attendance event **********************/ /*****************************************************************************/ void Att_UpdateAttEvent (struct AttendanceEvent *Att,const char *Txt) { char Query[1024+Cns_MAX_BYTES_TEXT]; /***** Update the data of the attendance event *****/ sprintf (Query,"UPDATE att_events" " SET StartTime='%04u%02u%02u%02u%02u%02u',EndTime='%04u%02u%02u%02u%02u%02u'," "CommentTchVisible='%c',Title='%s',Txt='%s'" " WHERE AttCod='%ld' AND CrsCod='%ld'", Att->DateTimes[Att_START_TIME].Date.Year, Att->DateTimes[Att_START_TIME].Date.Month, Att->DateTimes[Att_START_TIME].Date.Day, Att->DateTimes[Att_START_TIME].Time.Hour, Att->DateTimes[Att_START_TIME].Time.Minute, Att->DateTimes[Att_START_TIME].Time.Second, Att->DateTimes[Att_END_TIME ].Date.Year, Att->DateTimes[Att_END_TIME ].Date.Month, Att->DateTimes[Att_END_TIME ].Date.Day , Att->DateTimes[Att_END_TIME ].Time.Hour, Att->DateTimes[Att_END_TIME ].Time.Minute, Att->DateTimes[Att_END_TIME ].Time.Second, Att->CommentTchVisible ? 'Y' : 'N', Att->Title, Txt, Att->AttCod,Gbl.CurrentCrs.Crs.CrsCod); DB_QueryUPDATE (Query,"can not update attendance event"); /***** Update groups *****/ /* Remove old groups */ Att_RemoveAllTheGrpsAssociatedToAnAttEvent (Att->AttCod); /* Create new groups */ if (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps) Att_CreateGrps (Att->AttCod); } /*****************************************************************************/ /******** Check if an attendance event is associated to any group ************/ /*****************************************************************************/ bool Att_CheckIfAttEventIsAssociatedToGrps (long AttCod) { char Query[256]; /***** Get if an attendance event is associated to a group from database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_grp WHERE AttCod='%ld'", AttCod); return (DB_QueryCOUNT (Query,"can not check if an attendance event is associated to groups") != 0); } /*****************************************************************************/ /********* Check if an attendance event is associated to a group *************/ /*****************************************************************************/ bool Att_CheckIfAttEventIsAssociatedToGrp (long AttCod,long GrpCod) { char Query[512]; /***** Get if an attendance event is associated to a group from database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_grp WHERE AttCod='%ld' AND GrpCod='%ld'", AttCod,GrpCod); return (DB_QueryCOUNT (Query,"can not check if an attendance event is associated to a group") != 0); } /*****************************************************************************/ /****************** Remove groups of an attendance event *********************/ /*****************************************************************************/ static void Att_RemoveAllTheGrpsAssociatedToAnAttEvent (long AttCod) { char Query[256]; /***** Remove groups of the attendance event *****/ sprintf (Query,"DELETE FROM att_grp WHERE AttCod='%ld'",AttCod); DB_QueryDELETE (Query,"can not remove the groups associated to an attendance event"); } /*****************************************************************************/ /*********** Remove one student from all the attendance events ***************/ /*****************************************************************************/ void Att_RemoveUsrFromAllAttEvents (long UsrCod) { char Query[256]; /***** Remove group from all the attendance events *****/ sprintf (Query,"DELETE FROM att_usr WHERE UsrCod='%ld'",UsrCod); DB_QueryDELETE (Query,"can not remove user from all attendance events"); } /*****************************************************************************/ /*********** Remove one student from all the attendance events ***************/ /*****************************************************************************/ void Att_RemoveUsrFromCrsAttEvents (long UsrCod,long CrsCod) { char Query[512]; /***** Remove group from all the attendance events *****/ sprintf (Query,"DELETE FROM att_usr USING att_events,att_usr" " WHERE att_events.CrsCod='%ld'" " AND att_events.AttCod=att_usr.AttCod AND att_usr.UsrCod='%ld'", CrsCod,UsrCod); DB_QueryDELETE (Query,"can not remove user from attendance events of a course"); } /*****************************************************************************/ /************* Remove one group from all the attendance events ***************/ /*****************************************************************************/ void Att_RemoveGroup (long GrpCod) { char Query[256]; /***** Remove group from all the attendance events *****/ sprintf (Query,"DELETE FROM att_grp WHERE GrpCod='%ld'",GrpCod); DB_QueryDELETE (Query,"can not remove group from the associations between attendance events and groups"); } /*****************************************************************************/ /******** Remove groups of one type from all the attendance events ***********/ /*****************************************************************************/ void Att_RemoveGroupsOfType (long GrpTypCod) { char Query[256]; /***** Remove group from all the attendance events *****/ sprintf (Query,"DELETE FROM att_grp USING crs_grp,att_grp" " WHERE crs_grp.GrpTypCod='%ld' AND crs_grp.GrpCod=att_grp.GrpCod", GrpTypCod); DB_QueryDELETE (Query,"can not remove groups of a type from the associations between attendance events and groups"); } /*****************************************************************************/ /***************** Create groups of an attendance event **********************/ /*****************************************************************************/ static void Att_CreateGrps (long AttCod) { unsigned NumGrpSel; char Query[256]; /***** Create groups of the attendance event *****/ for (NumGrpSel = 0; NumGrpSel < Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps; NumGrpSel++) { /* Create group */ sprintf (Query,"INSERT INTO att_grp (AttCod,GrpCod) VALUES ('%ld','%ld')", AttCod,Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod[NumGrpSel]); DB_QueryINSERT (Query,"can not associate a group to an attendance event"); } } /*****************************************************************************/ /****** Get and write the names of the groups of an attendance event *********/ /*****************************************************************************/ static void Att_GetAndWriteNamesOfGrpsAssociatedToAttEvent (struct AttendanceEvent *Att) { extern const char *Txt_Group; extern const char *Txt_Groups; extern const char *Txt_and; extern const char *Txt_The_whole_course; char Query[512]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumGrp; unsigned NumGrps; /***** Get groups associated to an attendance event from database *****/ sprintf (Query,"SELECT crs_grp_types.GrpTypName,crs_grp.GrpName" " FROM att_grp,crs_grp,crs_grp_types" " WHERE att_grp.AttCod='%ld' AND att_grp.GrpCod=crs_grp.GrpCod" " AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod" " ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName", Att->AttCod); NumGrps = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get groups of an attendance event"); /***** Write heading *****/ fprintf (Gbl.F.Out,"

%s: ", Att->Hidden ? "ASG_GRP_LIGHT" : "ASG_GRP", (NumGrps == 1) ? Txt_Group : Txt_Groups); /***** Write groups *****/ if (NumGrps) // Groups found... { /* Get and write the group types and names */ for (NumGrp = 0; NumGrp < NumGrps; NumGrp++) { /* Get next group */ row = mysql_fetch_row (mysql_res); /* Write group type name and group name */ fprintf (Gbl.F.Out,"%s %s",row[0],row[1]); if (NumGrps >= 2) { if (NumGrp == NumGrps-2) fprintf (Gbl.F.Out," %s ",Txt_and); if (NumGrps >= 3) if (NumGrp < NumGrps-2) fprintf (Gbl.F.Out,", "); } } } else fprintf (Gbl.F.Out,"%s %s", Txt_The_whole_course,Gbl.CurrentCrs.Crs.ShortName); fprintf (Gbl.F.Out,"

"); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /*************** Remove all the attendance events of a course ****************/ /*****************************************************************************/ void Att_RemoveCrsAttEvents (long CrsCod) { char Query[512]; /***** Remove students *****/ sprintf (Query,"DELETE FROM att_usr USING att_events,att_usr" " WHERE att_events.CrsCod='%ld' AND att_events.AttCod=att_usr.AttCod", CrsCod); DB_QueryDELETE (Query,"can not remove all the students registered in events of a course"); /***** Remove groups *****/ sprintf (Query,"DELETE FROM att_grp USING att_events,att_grp" " WHERE att_events.CrsCod='%ld' AND att_events.AttCod=att_grp.AttCod", CrsCod); DB_QueryDELETE (Query,"can not remove all the groups associated to attendance events of a course"); /***** Remove attendance events *****/ sprintf (Query,"DELETE FROM att_events WHERE CrsCod='%ld'", CrsCod); DB_QueryDELETE (Query,"can not remove all the attendance events of a course"); } /*****************************************************************************/ /*************** Get number of attendance events in a course *****************/ /*****************************************************************************/ unsigned Att_GetNumAttEventsInCrs (long CrsCod) { char Query[256]; /***** Get number of attendance events in a course from database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_events WHERE CrsCod='%ld'", CrsCod); return (unsigned) DB_QueryCOUNT (Query,"can not get number of attendance events in course"); } /*****************************************************************************/ /*************** Get number of courses with attendance events ****************/ /*****************************************************************************/ // Returns the number of courses with attendance events // in this location (all the platform, current degree or current course) unsigned Att_GetNumCoursesWithAttEvents (Sco_Scope_t Scope) { char Query[1024]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumCourses; /***** Get number of courses with attendance events from database *****/ switch (Scope) { case Sco_SCOPE_PLATFORM: sprintf (Query,"SELECT COUNT(DISTINCT (CrsCod))" " FROM att_events" " WHERE CrsCod>'0'"); break; case Sco_SCOPE_INSTITUTION: sprintf (Query,"SELECT COUNT(DISTINCT (att_events.CrsCod))" " FROM centres,degrees,courses,att_events" " WHERE centres.InsCod='%ld'" " AND centres.CtrCod=degrees.CtrCod" " AND degrees.DegCod=courses.DegCod" " AND courses.Status=0" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentIns.Ins.InsCod); break; case Sco_SCOPE_CENTRE: sprintf (Query,"SELECT COUNT(DISTINCT (att_events.CrsCod))" " FROM degrees,courses,att_events" " WHERE degrees.CtrCod='%ld'" " AND degrees.DegCod=courses.DegCod" " AND courses.Status=0" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentCtr.Ctr.CtrCod); break; case Sco_SCOPE_DEGREE: sprintf (Query,"SELECT COUNT(DISTINCT (att_events.CrsCod))" " FROM courses,att_events" " WHERE courses.DegCod='%ld'" " AND courses.Status=0" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentDeg.Deg.DegCod); break; case Sco_SCOPE_COURSE: sprintf (Query,"SELECT COUNT(DISTINCT (CrsCod))" " FROM att_events" " WHERE CrsCod='%ld'", Gbl.CurrentCrs.Crs.CrsCod); break; default: Lay_ShowErrorAndExit ("Wrong scope."); break; } DB_QuerySELECT (Query,&mysql_res,"can not get number of courses with attendance events"); /***** Get number of courses *****/ row = mysql_fetch_row (mysql_res); if (sscanf (row[0],"%u",&NumCourses) != 1) Lay_ShowErrorAndExit ("Error when getting number of courses with attendance events."); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return NumCourses; } /*****************************************************************************/ /********************* Get number of attendance events ***********************/ /*****************************************************************************/ // Returns the number of attendance events // in this location (all the platform, current degree or current course) unsigned Att_GetNumAttEvents (Sco_Scope_t Scope,unsigned *NumNotif) { char Query[1024]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumAttEvents; /***** Get number of attendance events from database *****/ switch (Scope) { case Sco_SCOPE_PLATFORM: sprintf (Query,"SELECT COUNT(*),SUM(NumNotif)" " FROM att_events" " WHERE CrsCod>'0'"); break; case Sco_SCOPE_INSTITUTION: sprintf (Query,"SELECT COUNT(*),SUM(att_events.NumNotif)" " FROM centres,degrees,courses,att_events" " WHERE centres.InsCod='%ld'" " AND centres.CtrCod=degrees.CtrCod" " AND degrees.DegCod=courses.DegCod" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentIns.Ins.InsCod); break; case Sco_SCOPE_CENTRE: sprintf (Query,"SELECT COUNT(*),SUM(att_events.NumNotif)" " FROM degrees,courses,att_events" " WHERE degrees.CtrCod='%ld'" " AND degrees.DegCod=courses.DegCod" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentCtr.Ctr.CtrCod); break; case Sco_SCOPE_DEGREE: sprintf (Query,"SELECT COUNT(*),SUM(att_events.NumNotif)" " FROM courses,att_events" " WHERE courses.DegCod='%ld'" " AND courses.CrsCod=att_events.CrsCod", Gbl.CurrentDeg.Deg.DegCod); break; case Sco_SCOPE_COURSE: sprintf (Query,"SELECT COUNT(*),SUM(NumNotif)" " FROM att_events" " WHERE CrsCod='%ld'", Gbl.CurrentCrs.Crs.CrsCod); break; default: Lay_ShowErrorAndExit ("Wrong scope."); break; } DB_QuerySELECT (Query,&mysql_res,"can not get number of attendance events"); /***** Get number of attendance events *****/ row = mysql_fetch_row (mysql_res); if (sscanf (row[0],"%u",&NumAttEvents) != 1) Lay_ShowErrorAndExit ("Error when getting number of attendance events."); /***** Get number of notifications by e-mail *****/ if (row[1]) { if (sscanf (row[1],"%u",NumNotif) != 1) Lay_ShowErrorAndExit ("Error when getting number of notifications of attendance events."); } else *NumNotif = 0; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return NumAttEvents; } /*****************************************************************************/ /************************ Show one attendance event **************************/ /*****************************************************************************/ void Att_SeeOneAttEvent (void) { struct AttendanceEvent Att; /***** Get attendance event code *****/ if (Gbl.AttEvents.AttCod <= 0) if ((Gbl.AttEvents.AttCod = Att_GetParamAttCod ()) == -1L) Lay_ShowErrorAndExit ("Code of attendance event is missing."); /***** Get parameters *****/ Att_GetParamAttOrderType (); Grp_GetParamWhichGrps (); Pag_GetParamPagNum (Pag_ATT_EVENTS); /***** Show attendance *****/ Lay_StartRoundFrameTable10 (NULL,2,NULL); Att.AttCod = Gbl.AttEvents.AttCod; Att_ShowOneAttEvent (&Att,true); Lay_EndRoundFrameTable10 (); switch (Gbl.Usrs.Me.LoggedRole) { case Rol_ROLE_STUDENT: Att_ListAttOnlyMeAsStudent (&Att); break; case Rol_ROLE_TEACHER: case Rol_ROLE_SUPERUSER: /***** Show list of students *****/ Att_ListAttStudents (&Att); break; default: break; } } /*****************************************************************************/ /*********************** List me as student in one event *********************/ /*****************************************************************************/ // Att must be filled before calling this function static void Att_ListAttOnlyMeAsStudent (struct AttendanceEvent *Att) { extern const char *Txt_Student_comment; extern const char *Txt_Teachers_comment; extern const char *Txt_ROLES_SINGULAR_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Save; /***** Get my preference about photos in users' list for current course *****/ Usr_GetMyPrefAboutListWithPhotosFromDB (); /***** Form start *****/ if (Att->Open) { Act_FormStart (ActRecAttMe); Att_PutParamAttCod (Att->AttCod); } /***** List students' data *****/ /* Header */ Lay_StartRoundFrameTable10 (NULL,2,NULL); fprintf (Gbl.F.Out,"" "" "" ""); if (Gbl.Usrs.Listing.WithPhotos) fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"" "%s" "" "" "%s" "" "" "%s" "" "", Txt_ROLES_SINGULAR_Abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN], Txt_Student_comment, Txt_Teachers_comment); /* List of students (only me) */ Att_WriteRowStdToCallTheRoll (1,&Gbl.Usrs.Me.UsrDat,Att); /* Footer */ Lay_EndRoundFrameTable10 (); if (Att->Open) { /***** Send button *****/ Lay_PutSendButton (Txt_Save); fprintf (Gbl.F.Out,""); } } /*****************************************************************************/ /*************** List students who attended to one event *********************/ /*****************************************************************************/ // Att must be filled before calling this function static void Att_ListAttStudents (struct AttendanceEvent *Att) { extern const char *Txt_Student_comment; extern const char *Txt_Teachers_comment; extern const char *Txt_ROLES_SINGULAR_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Save; unsigned NumStd; struct UsrData UsrDat; /***** Form to select groups *****/ Grp_ShowFormToSelectSeveralGroups (ActSeeOneAtt); /***** Get and order list of students in this course *****/ Usr_GetUsrsLst (Rol_ROLE_STUDENT,Sco_SCOPE_COURSE,NULL,false); if (Gbl.Usrs.LstStds.NumUsrs) { /***** Get my preference about photos in users' list for current course *****/ Usr_GetMyPrefAboutListWithPhotosFromDB (); /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Form start *****/ Act_FormStart (ActRecAttStd); Att_PutParamAttCod (Att->AttCod); Grp_PutParamsCodGrps (); /***** List students' data *****/ /* Header */ Lay_StartRoundFrameTable10 (NULL,2,NULL); fprintf (Gbl.F.Out,"" "" "" ""); if (Gbl.Usrs.Listing.WithPhotos) fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"" "%s" "" "" "%s" "" "" "%s" "" "", Txt_ROLES_SINGULAR_Abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN], Txt_Student_comment, Txt_Teachers_comment); /* List of students */ for (NumStd = 0, Gbl.RowEvenOdd = 0; NumStd < Gbl.Usrs.LstStds.NumUsrs; NumStd++) { UsrDat.UsrCod = Gbl.Usrs.LstStds.Lst[NumStd].UsrCod; if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // If user's data exist... { UsrDat.Accepted = Gbl.Usrs.LstStds.Lst[NumStd].Accepted; Att_WriteRowStdToCallTheRoll (NumStd + 1,&UsrDat,Att); } } /* Footer */ Lay_EndRoundFrameTable10 (); /***** Send button *****/ Lay_PutSendButton (Txt_Save); fprintf (Gbl.F.Out,"" ""); /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } else Usr_ShowWarningNoUsersFound (Rol_ROLE_STUDENT); /***** Free memory for students list *****/ Usr_FreeUsrsList (&Gbl.Usrs.LstStds); /***** Free memory for list of selected groups *****/ Grp_FreeListCodSelectedGrps (); } /*****************************************************************************/ /************ Write a row of a table with the data of a student **************/ /*****************************************************************************/ static void Att_WriteRowStdToCallTheRoll (unsigned NumStd,struct UsrData *UsrDat,struct AttendanceEvent *Att) { extern const char *Txt_Present; extern const char *Txt_Absent; bool Present; const char *BgColor; char PhotoURL[PATH_MAX+1]; bool ShowPhoto; char CommentStd[Cns_MAX_BYTES_TEXT+1]; char CommentTch[Cns_MAX_BYTES_TEXT+1]; BgColor = Gbl.ColorRows[Gbl.RowEvenOdd]; /***** Check if this student is already registered in the current event *****/ Present = Att_CheckIfUsrIsPresentInAttEventAndGetComments (Att->AttCod,UsrDat->UsrCod,CommentStd,CommentTch); /***** Icon to show if the user is already registered *****/ fprintf (Gbl.F.Out,"" "" "\"\"" "", Gbl.Prefs.IconsURL, Present ? "check" : "check-empty", Present ? Txt_Present : Txt_Absent); /***** Checkbox to select user *****/ fprintf (Gbl.F.Out,"" "EncryptedUsrCod); if (Present) // This student has attended to the event? fprintf (Gbl.F.Out," checked=\"checked\""); if (Gbl.Usrs.Me.LoggedRole == Rol_ROLE_STUDENT) // A student can not change his attendance fprintf (Gbl.F.Out," disabled=\"disabled\""); fprintf (Gbl.F.Out," />" ""); /***** Write number of student in the list *****/ fprintf (Gbl.F.Out,"" "%u" "", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor, NumStd); /***** Show student's photo *****/ if (Gbl.Usrs.Listing.WithPhotos) { fprintf (Gbl.F.Out,"", BgColor); ShowPhoto = Pho_ShowUsrPhotoIsAllowed (UsrDat,PhotoURL); Pho_ShowUsrPhoto (UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO36x48",true); fprintf (Gbl.F.Out,""); } /***** Write user's ID ******/ fprintf (Gbl.F.Out,"", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor); ID_WriteUsrIDs (UsrDat,true); fprintf (Gbl.F.Out,""); /***** Write student's name *****/ fprintf (Gbl.F.Out,"%s", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor, UsrDat->Surname1); if (UsrDat->Surname2[0]) fprintf (Gbl.F.Out," %s",UsrDat->Surname2); fprintf (Gbl.F.Out,", %s", UsrDat->FirstName); /***** Student's comment: write form or text */ fprintf (Gbl.F.Out,"", BgColor); if (Gbl.Usrs.Me.LoggedRole == Rol_ROLE_STUDENT && Att->Open) // Show with form fprintf (Gbl.F.Out,"", UsrDat->UsrCod,CommentStd); else // Show without form { Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, CommentStd,Cns_MAX_BYTES_TEXT,false); fprintf (Gbl.F.Out,"%s",CommentStd); } fprintf (Gbl.F.Out,""); /***** Teacher's comment: write form, text or nothing */ fprintf (Gbl.F.Out,"", BgColor); if (Gbl.Usrs.Me.LoggedRole == Rol_ROLE_TEACHER) // Show with form fprintf (Gbl.F.Out,"", UsrDat->UsrCod,CommentTch); else if (Att->CommentTchVisible) // Show without form { Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, CommentTch,Cns_MAX_BYTES_TEXT,false); fprintf (Gbl.F.Out,"%s",CommentTch); } fprintf (Gbl.F.Out,"" ""); Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; } /*****************************************************************************/ /****** Put parameters with the default groups in an attendance event ********/ /*****************************************************************************/ static void Att_PutParamsCodGrps (long AttCod) { char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumGrp; unsigned NumGrps; /***** Get groups associated to an attendance event from database *****/ if (Gbl.CurrentCrs.Grps.NumGrps) { sprintf (Query,"SELECT GrpCod FROM att_grp WHERE att_grp.AttCod='%ld'", AttCod); NumGrps = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get groups of an attendance event"); } else NumGrps = 0; /***** Get groups *****/ if (NumGrps) // Groups found... { fprintf (Gbl.F.Out,""); } else /***** Write the boolean parameter that indicates if all the groups must be listed *****/ Par_PutHiddenParamChar ("AllGroups",'Y'); /***** Free structure that stores the query result *****/ if (Gbl.CurrentCrs.Grps.NumGrps) DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /*************** Save me as students who attended to an event ****************/ /*****************************************************************************/ void Att_RegisterMeAsStdInAttEvent (void) { extern const char *Txt_Your_comment_has_been_updated; struct AttendanceEvent Att; bool Present; char CommentParamName[10+10+1]; char CommentStd[Cns_MAX_BYTES_TEXT+1]; char CommentTch[Cns_MAX_BYTES_TEXT+1]; /***** Get attendance event code *****/ if ((Att.AttCod = Att_GetParamAttCod ()) == -1L) Lay_ShowErrorAndExit ("Code of attendance event is missing."); Att_GetDataOfAttEventByCodAndCheckCrs (&Att); // This checks that event belong to current course if (Att.Open) { /***** Get comments for this student *****/ Present = Att_CheckIfUsrIsPresentInAttEventAndGetComments (Att.AttCod,Gbl.Usrs.Me.UsrDat.UsrCod,CommentStd,CommentTch); sprintf (CommentParamName,"CommentStd%ld",Gbl.Usrs.Me.UsrDat.UsrCod); Par_GetParToHTML (CommentParamName,CommentStd,Cns_MAX_BYTES_TEXT); if (Present || CommentStd[0] || CommentTch[0]) /***** Register student *****/ Att_RegUsrInAttEventChangingComments (Att.AttCod,Gbl.Usrs.Me.UsrDat.UsrCod, Present,CommentStd,CommentTch); else /***** Remove student *****/ Att_RemoveUsrFromAttEvent (Att.AttCod,Gbl.Usrs.Me.UsrDat.UsrCod); /***** Write final message *****/ Lay_ShowAlert (Lay_SUCCESS,Txt_Your_comment_has_been_updated); } /***** Show the attendance event again *****/ Gbl.AttEvents.AttCod = Att.AttCod; Att_SeeOneAttEvent (); } /*****************************************************************************/ /***************** Save students who attended to an event ********************/ /*****************************************************************************/ /* Algorithm: 1. Get list of students in the groups selected: Gbl.Usrs.LstStds 2. Mark all students in the groups selected setting Remove=true 3. Get list of students marked as present by me: Gbl.Usrs.Select.Std 4. Loop over the list Gbl.Usrs.Select.Std, that holds the list of the students marked as present, marking the students in Gbl.Usrs.LstStds.Lst as Remove=false 5. Delete from att_usr all the students marked as Remove=true 6. Replace (insert without duplicated) into att_usr all the students marked as Remove=false */ void Att_RegisterStudentsInAttEvent (void) { extern const char *Txt_Presents; extern const char *Txt_Absents; extern const char *Txt_No_users_found[Rol_NUM_ROLES]; struct AttendanceEvent Att; char Format[256]; unsigned NumStd; const char *Ptr; bool Present; unsigned NumStdsPresent; unsigned NumStdsAbsent; struct UsrData UsrData; char CommentParamName[10+10+1]; char CommentStd[Cns_MAX_BYTES_TEXT+1]; char CommentTch[Cns_MAX_BYTES_TEXT+1]; /***** Get attendance event code *****/ if ((Att.AttCod = Att_GetParamAttCod ()) == -1L) Lay_ShowErrorAndExit ("Code of attendance event is missing."); Att_GetDataOfAttEventByCodAndCheckCrs (&Att); // This checks that event belong to current course /***** Get groups selected *****/ Grp_GetParCodsSeveralGrpsToShowUsrs (); /***** 1. Get list of students in the groups selected: Gbl.Usrs.LstStds *****/ /* Get list of students in the groups selected */ Usr_GetUsrsLst (Rol_ROLE_STUDENT,Sco_SCOPE_COURSE,NULL,false); if (Gbl.Usrs.LstStds.NumUsrs) // If there are students in the groups selected... { /***** 2. Mark all students in the groups selected setting Remove=true *****/ for (NumStd = 0; NumStd < Gbl.Usrs.LstStds.NumUsrs; NumStd++) Gbl.Usrs.LstStds.Lst[NumStd].Remove = true; /***** 3. Get list of students marked as present by me: Gbl.Usrs.Select.Std *****/ Usr_GetListSelectedUsrs (); /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrData); /***** 4. Loop over the list Gbl.Usrs.Select.Std, that holds the list of the students marked as present, marking the students in Gbl.Usrs.LstStds.Lst as Remove=false *****/ Ptr = Gbl.Usrs.Select.Std; while (*Ptr) { Par_GetNextStrUntilSeparParamMult (&Ptr,UsrData.EncryptedUsrCod,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64); Usr_GetUsrCodFromEncryptedUsrCod (&UsrData); if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrData)) // Get student's data from the database /***** Mark student to not be removed *****/ for (NumStd = 0; NumStd < Gbl.Usrs.LstStds.NumUsrs; NumStd++) if (Gbl.Usrs.LstStds.Lst[NumStd].UsrCod == UsrData.UsrCod) { Gbl.Usrs.LstStds.Lst[NumStd].Remove = false; break; // Found! Exit loop } } /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrData); /***** Free memory *****/ /* Free memory used for list of students */ Usr_FreeListsEncryptedUsrCods (); // 5. Delete from att_usr all the students marked as Remove=true // 6. Replace (insert without duplicated) into att_usr all the students marked as Remove=false for (NumStd = 0, NumStdsAbsent = NumStdsPresent = 0; NumStd < Gbl.Usrs.LstStds.NumUsrs; NumStd++) { /***** Get comments for this student *****/ Att_CheckIfUsrIsPresentInAttEventAndGetComments (Att.AttCod,Gbl.Usrs.LstStds.Lst[NumStd].UsrCod,CommentStd,CommentTch); sprintf (CommentParamName,"CommentTch%ld",Gbl.Usrs.LstStds.Lst[NumStd].UsrCod); Par_GetParToHTML (CommentParamName,CommentTch,Cns_MAX_BYTES_TEXT); Present = !Gbl.Usrs.LstStds.Lst[NumStd].Remove; if (Present || CommentStd[0] || CommentTch[0]) /***** Register student *****/ Att_RegUsrInAttEventChangingComments (Att.AttCod,Gbl.Usrs.LstStds.Lst[NumStd].UsrCod, Present,CommentStd,CommentTch); else /***** Remove student *****/ Att_RemoveUsrFromAttEvent (Att.AttCod,Gbl.Usrs.LstStds.Lst[NumStd].UsrCod); if (Present) NumStdsPresent++; else NumStdsAbsent++; } /***** Free memory for students list *****/ Usr_FreeUsrsList (&Gbl.Usrs.LstStds); /***** Write final message *****/ sprintf (Format,"%s: %%u
%s: %%u",Txt_Presents,Txt_Absents); sprintf (Gbl.Message,Format, NumStdsPresent,NumStdsAbsent); Lay_ShowAlert (Lay_INFO,Gbl.Message); } else // Gbl.Usrs.LstStds.NumUsrs == 0 Lay_ShowAlert (Lay_INFO,Txt_No_users_found[Rol_ROLE_STUDENT]); /***** Show the attendance event again *****/ Gbl.AttEvents.AttCod = Att.AttCod; Att_SeeOneAttEvent (); /***** Free memory for list of groups selected *****/ Grp_FreeListCodSelectedGrps (); } /*****************************************************************************/ /******* Get number of students from a list who attended to an event *********/ /*****************************************************************************/ static void Att_GetNumStdsTotalWhoAreInAttEvent (struct AttendanceEvent *Att) { char Query[128]; /***** Count number of students registered in an event in database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_usr" " WHERE AttCod='%ld' AND Present='Y'", Att->AttCod); Att->NumStdsTotal = (unsigned) DB_QueryCOUNT (Query,"can not get number of students who are registered in an event"); } /*****************************************************************************/ /******* Get number of students from a list who attended to an event *********/ /*****************************************************************************/ static unsigned Att_GetNumStdsFromAListWhoAreInAttEvent (long AttCod,long LstSelectedUsrCods[],unsigned NumStdsInList) { char *Query; char SubQuery[1+1+10+1]; unsigned NumStd; unsigned NumStdsInAttEvent = 0; if (NumStdsInList) { /***** Allocate space for query *****/ if ((Query = (char *) malloc ((size_t) (256+NumStdsInList*(1+1+10)))) == NULL) Lay_ShowErrorAndExit ("Not enough memory for query."); /***** Count number of students registered in an event in database *****/ sprintf (Query,"SELECT COUNT(*) FROM att_usr" " WHERE AttCod='%ld'" " AND UsrCod IN (", AttCod); for (NumStd = 0; NumStd < NumStdsInList; NumStd++) { sprintf (SubQuery, NumStd ? ",%ld" : "%ld", LstSelectedUsrCods[NumStd]); strcat (Query,SubQuery); } strcat (Query,") AND Present='Y'"); // Lay_ShowAlert (Lay_INFO,Query); NumStdsInAttEvent = (unsigned) DB_QueryCOUNT (Query,"can not get number of students from a list who are registered in an event"); /***** Free query *****/ free ((void *) Query); } return NumStdsInAttEvent; } /*****************************************************************************/ /***************** Check if a student attended to an event *******************/ /*****************************************************************************/ static bool Att_CheckIfUsrIsInTableAttUsr (long AttCod,long UsrCod,bool *Present) { char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumRows; bool InDBTable; /***** Check if a student is registered in an event in database *****/ sprintf (Query,"SELECT Present FROM att_usr" " WHERE AttCod='%ld' AND UsrCod='%ld'", AttCod,UsrCod); if ((NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get if a student is already registered in an event"))) { InDBTable = true; /* Get row */ row = mysql_fetch_row (mysql_res); /* Get if present (row[0]) */ *Present = (Str_ConvertToUpperLetter (row[0][0]) == 'Y'); } else // User is not present { InDBTable = false; *Present = false; } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return InDBTable; } /*****************************************************************************/ /***************** Check if a student attended to an event *******************/ /*****************************************************************************/ static bool Att_CheckIfUsrIsPresentInAttEvent (long AttCod,long UsrCod) { bool Present; Att_CheckIfUsrIsInTableAttUsr (AttCod,UsrCod,&Present); return Present; } /*****************************************************************************/ /***************** Check if a student attended to an event *******************/ /*****************************************************************************/ static bool Att_CheckIfUsrIsPresentInAttEventAndGetComments (long AttCod,long UsrCod,char *CommentStd,char *CommentTch) { char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumRows; bool Present; /***** Check if a students is registered in an event in database *****/ sprintf (Query,"SELECT Present,CommentStd,CommentTch FROM att_usr" " WHERE AttCod='%ld' AND UsrCod='%ld'", AttCod,UsrCod); if ((NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get if a student is already registered in an event"))) { /* Get row */ row = mysql_fetch_row (mysql_res); /* Get if present (row[0]) */ Present = (Str_ConvertToUpperLetter (row[0][0]) == 'Y'); /* Get student's comment (row[1]) */ strncpy (CommentStd,row[1],Cns_MAX_BYTES_TEXT); CommentStd[Cns_MAX_BYTES_TEXT] = '\0'; /* Get teacher's comment (row[2]) */ strncpy (CommentTch,row[2],Cns_MAX_BYTES_TEXT); CommentTch[Cns_MAX_BYTES_TEXT] = '\0'; } else // User is not present { Present = false; CommentStd[0] = CommentTch[0] = '\0'; } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return Present; } /*****************************************************************************/ /******* Register a user in an attendance event not changing comments ********/ /*****************************************************************************/ void Att_RegUsrInAttEventNotChangingComments (long AttCod,long UsrCod) { bool Present; char Query[128]; /***** Check if user is already in table att_usr (present or not) *****/ if (Att_CheckIfUsrIsInTableAttUsr (AttCod,UsrCod,&Present)) // User is in table att_usr { // If already present ==> nothing to do if (!Present) { /***** Set user as present in database *****/ sprintf (Query,"UPDATE att_usr SET Present='Y'" " WHERE AttCod='%ld' AND UsrCod='%ld'", AttCod,UsrCod); DB_QueryUPDATE (Query,"can not set user as present in an event"); } } else // User is not in table att_usr Att_RegUsrInAttEventChangingComments (AttCod,UsrCod,true,"",""); } /*****************************************************************************/ /********* Register a user in an attendance event changing comments **********/ /*****************************************************************************/ static void Att_RegUsrInAttEventChangingComments (long AttCod,long UsrCod,bool Present, const char *CommentStd,const char *CommentTch) { char Query[256+Cns_MAX_BYTES_TEXT*2]; /***** Register user as assistant to an event in database *****/ sprintf (Query,"REPLACE INTO att_usr (AttCod,UsrCod,Present,CommentStd,CommentTch)" " VALUES ('%ld','%ld','%c','%s','%s')", AttCod,UsrCod, Present ? 'Y' : 'N', CommentStd, CommentTch); DB_QueryREPLACE (Query,"can not register user in an event"); } /*****************************************************************************/ /********************** Remove a user from an event **************************/ /*****************************************************************************/ static void Att_RemoveUsrFromAttEvent (long AttCod,long UsrCod) { char Query[256]; /***** Remove user if there is no comment in database *****/ sprintf (Query,"DELETE FROM att_usr" " WHERE AttCod='%ld' AND UsrCod='%ld'", AttCod,UsrCod); DB_QueryREPLACE (Query,"can not remove student from an event"); } /*****************************************************************************/ /************ Remove users absent without comments from an event *************/ /*****************************************************************************/ void Att_RemoveUsrsAbsentWithoutCommentsFromAttEvent (long AttCod) { char Query[256]; /***** Clean table att_usr *****/ sprintf (Query,"DELETE FROM att_usr" " WHERE AttCod='%ld' AND Present='N'" " AND CommentStd='' AND CommentTch=''", AttCod); DB_QueryDELETE (Query,"can not remove users absent without comments from an event"); } /*****************************************************************************/ /********* Request listing attendance of students to several events **********/ /*****************************************************************************/ void Usr_ReqListAttendanceStdsCrs (void) { extern const char *Txt_Show_list; /***** Get and update type of list, number of columns in class photo and preference about view photos *****/ Usr_GetAndUpdatePrefsAboutUsrList (); /***** Form to select groups *****/ Grp_ShowFormToSelectSeveralGroups (ActReqLstAttStd); /***** Form to select type of list used for select several users *****/ Usr_ShowFormsToSelectUsrListType (ActReqLstAttStd); /***** Get and order lists of users from current course *****/ Usr_GetUsrsLst (Rol_ROLE_STUDENT,Sco_SCOPE_COURSE,NULL,false); if (Gbl.Usrs.LstStds.NumUsrs) { if (Usr_GetIfShowBigList (Gbl.Usrs.LstStds.NumUsrs)) { /***** Get list of selected users *****/ Usr_GetListSelectedUsrs (); /***** Draw a class photo with students of the course *****/ /* Form start */ fprintf (Gbl.F.Out,"
"); Act_FormStart (ActSeeLstAttStd); Grp_PutParamsCodGrps (); /* Write list of students to select some of them */ Lay_StartRoundFrameTable10 (NULL,0,NULL); Usr_ListUsersToSelect (Rol_ROLE_STUDENT); Lay_EndRoundFrameTable10 (); /* Free list of attendance events */ Att_FreeListAttEvents (); /* Send button */ Lay_PutSendButton (Txt_Show_list); fprintf (Gbl.F.Out,"" "
"); /***** Free memory used for by the list of users *****/ Usr_FreeListsEncryptedUsrCods (); } } else Usr_ShowWarningNoUsersFound (Rol_ROLE_STUDENT); /***** Free memory for students list *****/ Usr_FreeUsrsList (&Gbl.Usrs.LstStds); /***** Free memory for list of selected groups *****/ Grp_FreeListCodSelectedGrps (); } /*****************************************************************************/ /************* List attendance of students to several events *****************/ /*****************************************************************************/ void Usr_ListAttendanceStdsCrs (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_You_must_select_one_ore_more_students; unsigned NumStdsInList; long *LstSelectedUsrCods; unsigned NumAttEvent; char *StrAttCodsSelected; char YN[1+1]; bool ShowDetails; /***** Get list of attendance events *****/ Att_GetListAttEvents (Att_OLDEST_FIRST); /***** Get list of selected students *****/ Usr_GetListSelectedUsrs (); /* Check the number of students to list */ if ((NumStdsInList = Usr_CountNumUsrsInEncryptedList ())) { /***** Get boolean parameter that indicates if details must be shown *****/ Par_GetParToText ("ShowDetails",YN,1); ShowDetails = (Str_ConvertToUpperLetter (YN[0]) == 'Y'); /***** Get list of groups selected ******/ Grp_GetParCodsSeveralGrpsToShowUsrs (); /***** Get list of students selected to show their attendances *****/ Att_GetListSelectedUsrCods (NumStdsInList,&LstSelectedUsrCods); /***** Get number of students in each event *****/ for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) /* Get number of students in this event */ Gbl.AttEvents.Lst[NumAttEvent].NumStdsFromList = Att_GetNumStdsFromAListWhoAreInAttEvent (Gbl.AttEvents.Lst[NumAttEvent].AttCod, LstSelectedUsrCods,NumStdsInList); /***** Get list of attendance events selected *****/ Att_GetListSelectedAttCods (&StrAttCodsSelected); /***** Put link to print *****/ if (Gbl.CurrentAct == ActSeeLstAttStd) Att_PutFormToPrintListStds (ShowDetails,StrAttCodsSelected); /***** List events to select *****/ Att_ListEventsToSelect (); /***** Get my preference about photos in users' list for current course *****/ Usr_GetMyPrefAboutListWithPhotosFromDB (); /***** Show table with attendances for every student in list *****/ Att_ListStdsAttendanceTable (NumStdsInList,LstSelectedUsrCods); /***** Show details or put button to show details *****/ if (ShowDetails) Att_ListStdsWithAttEventsDetails (NumStdsInList,LstSelectedUsrCods); else if (Gbl.CurrentAct == ActSeeLstAttStd) Att_PutButtonToShowDetails (StrAttCodsSelected); /***** Free memory for list of attendance events selected *****/ free ((void *) StrAttCodsSelected); /***** Free list of user codes *****/ free ((void *) LstSelectedUsrCods); /***** Free list of groups selected *****/ Grp_FreeListCodSelectedGrps (); } else // No students selected { Lay_ShowAlert (Lay_WARNING,Txt_You_must_select_one_ore_more_students); Usr_ReqListAttendanceStdsCrs (); // ...show again the form } /***** Free memory used for by the list of users *****/ Usr_FreeListsEncryptedUsrCods (); /***** Free list of attendance events *****/ Att_FreeListAttEvents (); } /*****************************************************************************/ /********** Get list of students selected to show their attendances **********/ /*****************************************************************************/ static void Att_GetListSelectedUsrCods (unsigned NumStdsInList,long **LstSelectedUsrCods) { unsigned NumStd; const char *Ptr; struct UsrData UsrDat; /***** Create list of user codes *****/ if ((*LstSelectedUsrCods = (long *) calloc ((size_t) NumStdsInList,sizeof (long))) == NULL) Lay_ShowErrorAndExit ("Not enough memory to store list of user codes."); /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Loop over the list Gbl.Usrs.Select.All getting users' codes *****/ for (NumStd = 0, Ptr = Gbl.Usrs.Select.All; NumStd < NumStdsInList && *Ptr; NumStd++) { Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDat.EncryptedUsrCod,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64); Usr_GetUsrCodFromEncryptedUsrCod (&UsrDat); (*LstSelectedUsrCods)[NumStd] = UsrDat.UsrCod; } /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /****************** Get list of attendance events selected *******************/ /*****************************************************************************/ static void Att_GetListSelectedAttCods (char **StrAttCodsSelected) { unsigned MaxSizeListAttCodsSelected; unsigned NumAttEvent; const char *Ptr; long AttCod; char LongStr[1+10+1]; char Query[256]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned NumGrpsInThisEvent; unsigned NumGrpInThisEvent; long GrpCodInThisEvent; unsigned NumGrpSel; /***** Allocate memory for list of attendance events selected *****/ MaxSizeListAttCodsSelected = Gbl.AttEvents.Num * (1+10+1); if ((*StrAttCodsSelected = (char *) malloc (MaxSizeListAttCodsSelected+1)) == NULL) Lay_ShowErrorAndExit ("Not enough memory to store list of attendance events selected."); /***** Get parameter multiple with list of attendance events selected *****/ Par_GetParMultiToText ("AttCods",*StrAttCodsSelected,MaxSizeListAttCodsSelected); /***** Set which attendance events will be shown as selected (checkboxes on) *****/ if ((*StrAttCodsSelected)[0]) // There are events selected { /* Reset selection */ for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) Gbl.AttEvents.Lst[NumAttEvent].Selected = false; /* Set some events as selected */ for (Ptr = *StrAttCodsSelected; *Ptr; ) { /* Get next attendance event selected */ Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,1+10); AttCod = Str_ConvertStrCodToLongCod (LongStr); /* Set each event in *StrAttCodsSelected as selected */ for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) if (Gbl.AttEvents.Lst[NumAttEvent].AttCod == AttCod) Gbl.AttEvents.Lst[NumAttEvent].Selected = true; } } else // No events selected { /***** Set which events will be marked as selected by default *****/ if (!Gbl.CurrentCrs.Grps.NumGrps || // Course has no groups Gbl.Usrs.ClassPhoto.AllGroups) // All groups selected /* Set all events as selected */ for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) Gbl.AttEvents.Lst[NumAttEvent].Selected = true; else // Course has groups and not all of them are selected for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) { /* Reset selection */ Gbl.AttEvents.Lst[NumAttEvent].Selected = false; /* Set this event as selected? */ if (Gbl.AttEvents.Lst[NumAttEvent].NumStdsFromList) // Some students attended to this event Gbl.AttEvents.Lst[NumAttEvent].Selected = true; else // No students attended to this event { /***** Get groups associated to an attendance event from database *****/ sprintf (Query,"SELECT GrpCod FROM att_grp" \ " WHERE att_grp.AttCod='%ld'", Gbl.AttEvents.Lst[NumAttEvent].AttCod); NumGrpsInThisEvent = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get groups of an attendance event"); if (NumGrpsInThisEvent) // This event is associated to groups /* Get groups associated to this event */ for (NumGrpInThisEvent = 0; NumGrpInThisEvent < NumGrpsInThisEvent && !Gbl.AttEvents.Lst[NumAttEvent].Selected; NumGrpInThisEvent++) { /* Get next group associated to this event */ row = mysql_fetch_row (mysql_res); if ((GrpCodInThisEvent = Str_ConvertStrCodToLongCod (row[0])) > 0) /* Check if this group is selected */ for (NumGrpSel = 0; NumGrpSel < Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps && !Gbl.AttEvents.Lst[NumAttEvent].Selected; NumGrpSel++) if (Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod[NumGrpSel] == GrpCodInThisEvent) Gbl.AttEvents.Lst[NumAttEvent].Selected = true; } else // This event is not associated to groups Gbl.AttEvents.Lst[NumAttEvent].Selected = true; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } } } } /*****************************************************************************/ /**** Put a link (form) to list assistance of students to several events *****/ /*****************************************************************************/ static void Att_PutFormToPrintListStds (bool ShowDetails,char *StrAttCodsSelected) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Print_view; /***** Link to print view *****/ fprintf (Gbl.F.Out,"
"); Act_FormStart (ActPrnLstAttStd); if (ShowDetails) Par_PutHiddenParamChar ("ShowDetails",'Y'); Grp_PutParamsCodGrps (); Usr_PutHiddenParUsrCodAll (ActPrnLstAttStd,Gbl.Usrs.Select.All); if (StrAttCodsSelected[0]) Par_PutHiddenParamString ("AttCods",StrAttCodsSelected); Act_LinkFormSubmit (Txt_Print_view,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("print",Txt_Print_view,Txt_Print_view); fprintf (Gbl.F.Out,"" "
"); } /*****************************************************************************/ /**** Put a link (form) to list assistance of students to several events *****/ /*****************************************************************************/ static void Att_PutButtonToShowDetails (char *StrAttCodsSelected) { extern const char *Txt_Show_more_details; /***** Button to show more details *****/ fprintf (Gbl.F.Out,"
"); Act_FormStart (ActSeeLstAttStd); Par_PutHiddenParamChar ("ShowDetails",'Y'); Grp_PutParamsCodGrps (); Usr_PutHiddenParUsrCodAll (ActSeeLstAttStd,Gbl.Usrs.Select.All); if (StrAttCodsSelected[0]) Par_PutHiddenParamString ("AttCods",StrAttCodsSelected); Lay_PutSendButton (Txt_Show_more_details); fprintf (Gbl.F.Out,"" "
"); } /*****************************************************************************/ /********** Write list of those attendance events that have students *********/ /*****************************************************************************/ static void Att_ListEventsToSelect (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Events; extern const char *Txt_Event; extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Update_attendance_according_to_selected_events; extern const char *Txt_Update_attendance; const char *BgColor; unsigned NumAttEvent; /***** Start form to update the attendance depending on the events selected *****/ if (Gbl.CurrentAct == ActSeeLstAttStd) { Act_FormStart (ActSeeLstAttStd); Grp_PutParamsCodGrps (); Usr_PutHiddenParUsrCodAll (ActSeeLstAttStd,Gbl.Usrs.Select.All); } /***** Start frame *****/ Lay_StartRoundFrameTable10 (NULL,2,Txt_Events); /***** Heading row *****/ fprintf (Gbl.F.Out,"" "" "%s" "" "" "%s" "" "", Txt_Event, Txt_ROLES_PLURAL_Abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN]); /***** List the events *****/ for (NumAttEvent = 0, Gbl.RowEvenOdd = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) { BgColor = Gbl.ColorRows[Gbl.RowEvenOdd]; /* Get data of the attendance event from database */ Att_GetDataOfAttEventByCodAndCheckCrs (&Gbl.AttEvents.Lst[NumAttEvent]); Att_GetNumStdsTotalWhoAreInAttEvent (&Gbl.AttEvents.Lst[NumAttEvent]); /* Write a row for this event */ fprintf (Gbl.F.Out,"" "" "" "" "" "%u:" "" "" "%02u/%02u/%04u %02u:%02u h %s" "" "" "%u" "" "", BgColor, NumAttEvent + 1, BgColor, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Day, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Month, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Year, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Time.Hour, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Time.Minute, Gbl.AttEvents.Lst[NumAttEvent].Title, BgColor, Gbl.AttEvents.Lst[NumAttEvent].NumStdsTotal); Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; } /***** Put button to refresh *****/ if (Gbl.CurrentAct == ActSeeLstAttStd) { fprintf (Gbl.F.Out,"" ""); Act_LinkFormSubmit (Txt_Update_attendance_according_to_selected_events,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("recycle",Txt_Update_attendance_according_to_selected_events,Txt_Update_attendance); fprintf (Gbl.F.Out,"" ""); } /***** End frame *****/ Lay_EndRoundFrameTable10 (); /***** End form *****/ if (Gbl.CurrentAct == ActSeeLstAttStd) fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /*********** Show table with attendances for every student in list ***********/ /*****************************************************************************/ static void Att_ListStdsAttendanceTable (unsigned NumStdsInList,long *LstSelectedUsrCods) { extern const char *Txt_Attendance; extern const char *Txt_Number_of_students; struct UsrData UsrDat; unsigned NumStd; unsigned NumAttEvent; unsigned Total; /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Start frame *****/ Lay_StartRoundFrameTable10 (NULL,2,Txt_Attendance); /***** Heading row *****/ Att_WriteTableHeadSeveralAttEvents (); /***** List the students *****/ for (NumStd = 0, Gbl.RowEvenOdd = 0; NumStd < NumStdsInList; NumStd++) { UsrDat.UsrCod = LstSelectedUsrCods[NumStd]; if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // Get from the database the data of the student { UsrDat.Accepted = Usr_GetIfUserHasAcceptedEnrollmentInCurrentCrs (UsrDat.UsrCod); Att_WriteRowStdSeveralAttEvents (NumStd,&UsrDat); } } /***** Last row with the total of students present in each event *****/ fprintf (Gbl.F.Out,"" "" "%s:" "", Gbl.Usrs.Listing.WithPhotos ? 4 : 3, Txt_Number_of_students); for (NumAttEvent = 0, Total = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) if (Gbl.AttEvents.Lst[NumAttEvent].Selected) { fprintf (Gbl.F.Out,"" "%u" "", Gbl.AttEvents.Lst[NumAttEvent].NumStdsFromList); Total += Gbl.AttEvents.Lst[NumAttEvent].NumStdsFromList; } fprintf (Gbl.F.Out,"" "%u" "" "", Total); /***** End frame *****/ Lay_EndRoundFrameTable10 (); /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /* Write table heading for listing of students in several attendance events **/ /*****************************************************************************/ static void Att_WriteTableHeadSeveralAttEvents (void) { extern const char *Txt_ROLES_SINGULAR_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Attendance; unsigned NumAttEvent; fprintf (Gbl.F.Out,"" "" "%s" "", Gbl.Usrs.Listing.WithPhotos ? 4 : 3, Txt_ROLES_SINGULAR_Abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN]); for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) if (Gbl.AttEvents.Lst[NumAttEvent].Selected) { /***** Get data of this attendance event *****/ Att_GetDataOfAttEventByCodAndCheckCrs (&Gbl.AttEvents.Lst[NumAttEvent]); fprintf (Gbl.F.Out,"" "%u" "", Gbl.AttEvents.Lst[NumAttEvent].Title, NumAttEvent + 1); } fprintf (Gbl.F.Out,"" "%s" "" "", Txt_Attendance); } /*****************************************************************************/ /************ Write a row of a table with the data of a student **************/ /*****************************************************************************/ static void Att_WriteRowStdSeveralAttEvents (unsigned NumStd,struct UsrData *UsrDat) { extern const char *Txt_Present; extern const char *Txt_Absent; const char *BgColor; char PhotoURL[PATH_MAX+1]; bool ShowPhoto; unsigned NumAttEvent; bool Present; unsigned NumTimesPresent; BgColor = Gbl.ColorRows[Gbl.RowEvenOdd]; /***** Write number of student in the list *****/ fprintf (Gbl.F.Out,"" "" "%u" "", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor, NumStd + 1); /***** Show student's photo *****/ if (Gbl.Usrs.Listing.WithPhotos) { fprintf (Gbl.F.Out,"", BgColor); ShowPhoto = Pho_ShowUsrPhotoIsAllowed (UsrDat,PhotoURL); Pho_ShowUsrPhoto (UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO18x24", Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW); fprintf (Gbl.F.Out,""); } /***** Write user's ID ******/ fprintf (Gbl.F.Out,"", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor); ID_WriteUsrIDs (UsrDat,true); fprintf (Gbl.F.Out,""); /***** Write student's name *****/ fprintf (Gbl.F.Out,"" "%s", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor, UsrDat->Surname1); if (UsrDat->Surname2[0]) fprintf (Gbl.F.Out," %s",UsrDat->Surname2); fprintf (Gbl.F.Out,", %s", UsrDat->FirstName); /***** Icon to show if the user is already registered *****/ for (NumAttEvent = 0, NumTimesPresent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) if (Gbl.AttEvents.Lst[NumAttEvent].Selected) { /***** Check if this student is already registered in the current event *****/ // Here it is not necessary to get comments Present = Att_CheckIfUsrIsPresentInAttEvent (Gbl.AttEvents.Lst[NumAttEvent].AttCod,UsrDat->UsrCod); fprintf (Gbl.F.Out,"" "\"\"" "", Gbl.RowEvenOdd, Gbl.Prefs.IconsURL, Present ? "check" : "check-empty", Present ? Txt_Present : Txt_Absent); if (Present) NumTimesPresent++; } /***** Last column with the number of times this user is present *****/ fprintf (Gbl.F.Out,"" "%u" "" "", BgColor, NumTimesPresent); Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; } /*****************************************************************************/ /**************** List the students with details and comments ****************/ /*****************************************************************************/ static void Att_ListStdsWithAttEventsDetails (unsigned NumStdsInList,long *LstSelectedUsrCods) { extern const char *Txt_Details; struct UsrData UsrDat; unsigned NumStd; /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Start frame *****/ Lay_StartRoundFrameTable10 (NULL,2,Txt_Details); /***** List students with attendance details *****/ for (NumStd = 0, Gbl.RowEvenOdd = 0; NumStd < NumStdsInList; NumStd++) { UsrDat.UsrCod = LstSelectedUsrCods[NumStd]; if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // Get from the database the data of the student { UsrDat.Accepted = Usr_GetIfUserHasAcceptedEnrollmentInCurrentCrs (UsrDat.UsrCod); Att_ListAttEventsForAStd (NumStd,&UsrDat); } } /***** End frame *****/ Lay_EndRoundFrameTable10 (); /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /*************** Write list of attendance events for a student ***************/ /*****************************************************************************/ static void Att_ListAttEventsForAStd (unsigned NumStd,struct UsrData *UsrDat) { extern const char *Txt_Present; extern const char *Txt_Absent; extern const char *Txt_Student_comment; extern const char *Txt_Teachers_comment; const char *BgColor; char PhotoURL[PATH_MAX+1]; bool ShowPhoto; unsigned NumAttEvent; bool Present; char CommentStd[Cns_MAX_BYTES_TEXT+1]; char CommentTch[Cns_MAX_BYTES_TEXT+1]; BgColor = Gbl.ColorRows[Gbl.RowEvenOdd]; /***** Write number of student in the list *****/ fprintf (Gbl.F.Out,"" "" "%u:" "", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", BgColor, NumStd + 1); /***** Show student's photo *****/ fprintf (Gbl.F.Out,"", BgColor); ShowPhoto = Pho_ShowUsrPhotoIsAllowed (UsrDat,PhotoURL); Pho_ShowUsrPhoto (UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO18x24", Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW); fprintf (Gbl.F.Out,""); /***** Write user's ID ******/ fprintf (Gbl.F.Out,"" "" "" ""); /***** Write student's name *****/ fprintf (Gbl.F.Out,"" "" "
", BgColor, UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL"); ID_WriteUsrIDs (UsrDat,true); fprintf (Gbl.F.Out,"%s", UsrDat->Accepted ? "DAT_SMALL_N" : "DAT_SMALL", UsrDat->Surname1); if (UsrDat->Surname2[0]) fprintf (Gbl.F.Out," %s",UsrDat->Surname2); fprintf (Gbl.F.Out,", %s
" "" "", UsrDat->FirstName); /***** List the events with students *****/ for (NumAttEvent = 0; NumAttEvent < Gbl.AttEvents.Num; NumAttEvent++) if (Gbl.AttEvents.Lst[NumAttEvent].Selected) { /***** Get data of the attendance event from database *****/ Att_GetDataOfAttEventByCodAndCheckCrs (&Gbl.AttEvents.Lst[NumAttEvent]); Att_GetNumStdsTotalWhoAreInAttEvent (&Gbl.AttEvents.Lst[NumAttEvent]); /***** Get comments for this student *****/ Present = Att_CheckIfUsrIsPresentInAttEventAndGetComments (Gbl.AttEvents.Lst[NumAttEvent].AttCod,UsrDat->UsrCod,CommentStd,CommentTch); /***** Write a row for this event *****/ fprintf (Gbl.F.Out,"" "" "" "%u:" "" "" "\"\"" " %02u/%02u/%04u %02u:%02u h %s" "", BgColor, BgColor, NumAttEvent + 1, BgColor, Gbl.Prefs.IconsURL, Present ? "check" : "check-empty", Present ? Txt_Present : Txt_Absent, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Day, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Month, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Date.Year, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Time.Hour, Gbl.AttEvents.Lst[NumAttEvent].DateTimes[Att_START_TIME].Time.Minute, Gbl.AttEvents.Lst[NumAttEvent].Title); /***** Write comments for this student *****/ if (CommentStd[0] || CommentTch[0]) { fprintf (Gbl.F.Out,"" "" "" "" "
", BgColor, BgColor, BgColor); if (CommentStd[0]) { Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, CommentStd,Cns_MAX_BYTES_TEXT,false); fprintf (Gbl.F.Out,"
%s:
%s
", Txt_Student_comment, CommentStd); } if (CommentTch[0]) { Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, CommentTch,Cns_MAX_BYTES_TEXT,false); fprintf (Gbl.F.Out,"
%s:
%s
", Txt_Teachers_comment, CommentTch); } fprintf (Gbl.F.Out,"
" "" ""); } } Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; }