// swad_attendance_database.c: control of attendance operations with database /* 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-2024 Antonio Caņas Vargas This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /*****************************************************************************/ /********************************** Headers **********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // To access MySQL databases #include // For asprintf #include // For free #include "swad_attendance.h" #include "swad_attendance_database.h" #include "swad_database.h" #include "swad_error.h" #include "swad_global.h" #include "swad_hierarchy_type.h" #include "swad_user_database.h" /*****************************************************************************/ /*************** External global variables from others modules ***************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /******************************* Public variables ****************************/ /*****************************************************************************/ unsigned (*Att_DB_GetListAttEvents[Grp_NUM_WHICH_GROUPS]) (MYSQL_RES **mysql_res, Dat_StartEndTime_t SelectedOrder, Att_OrderNewestOldest_t OrderNewestOldest) = { [Grp_MY_GROUPS ] = Att_DB_GetListEventsMyGrps, [Grp_ALL_GROUPS] = Att_DB_GetListEventsAllGrps, }; /*****************************************************************************/ /****************************** Private constants ****************************/ /*****************************************************************************/ static const char *Att_DB_HiddenSubQuery[Rol_NUM_ROLES] = { [Rol_UNK ] = " AND Hidden='N'", [Rol_GST ] = " AND Hidden='N'", [Rol_USR ] = " AND Hidden='N'", [Rol_STD ] = " AND Hidden='N'", [Rol_NET ] = " AND Hidden='N'", [Rol_TCH ] = "", [Rol_DEG_ADM] = " AND Hidden='N'", [Rol_CTR_ADM] = " AND Hidden='N'", [Rol_INS_ADM] = " AND Hidden='N'", [Rol_SYS_ADM] = "", }; static const char *Att_DB_OrderBySubQuery[Dat_NUM_START_END_TIME][Att_NUM_ORDERS_NEWEST_OLDEST] = { [Dat_STR_TIME][Att_NEWEST_FIRST] = "StartTime DESC," "EndTime DESC," "Title DESC", [Dat_STR_TIME][Att_OLDEST_FIRST] = "StartTime," "EndTime," "Title", [Dat_END_TIME][Att_NEWEST_FIRST] = "EndTime DESC," "StartTime DESC," "Title DESC", [Dat_END_TIME][Att_OLDEST_FIRST] = "EndTime," "StartTime," "Title", }; /*****************************************************************************/ /**************** Get list of attendance events in my groups *****************/ /*****************************************************************************/ unsigned Att_DB_GetListEventsMyGrps (MYSQL_RES **mysql_res, Dat_StartEndTime_t SelectedOrder, Att_OrderNewestOldest_t OrderNewestOldest) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get attendance events", "SELECT AttCod" " FROM att_events" " WHERE CrsCod=%ld" "%s" " AND (AttCod NOT IN" " (SELECT AttCod" " FROM att_groups)" " OR" " AttCod IN" " (SELECT att_groups.AttCod" " FROM grp_users," "att_groups" " WHERE grp_users.UsrCod=%ld" " AND att_groups.GrpCod=grp_users.GrpCod))" " ORDER BY %s", Gbl.Hierarchy.Node[Hie_CRS].HieCod, Att_DB_HiddenSubQuery[Gbl.Usrs.Me.Role.Logged], Gbl.Usrs.Me.UsrDat.UsrCod, Att_DB_OrderBySubQuery[SelectedOrder][OrderNewestOldest]); } /*****************************************************************************/ /********************* Get list of all attendance events *********************/ /*****************************************************************************/ unsigned Att_DB_GetListEventsAllGrps (MYSQL_RES **mysql_res, Dat_StartEndTime_t SelectedOrder, Att_OrderNewestOldest_t OrderNewestOldest) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get attendance events", "SELECT AttCod" " FROM att_events" " WHERE CrsCod=%ld%s" " ORDER BY %s", Gbl.Hierarchy.Node[Hie_CRS].HieCod, Att_DB_HiddenSubQuery[Gbl.Usrs.Me.Role.Logged], Att_DB_OrderBySubQuery[SelectedOrder][OrderNewestOldest]); } /*****************************************************************************/ /********************* Get list of all attendance events *********************/ /*****************************************************************************/ unsigned Att_DB_GetAllEventsData (MYSQL_RES **mysql_res,long CrsCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get attendance events", "SELECT AttCod," // row[0] "CrsCod," // row[1] "Hidden," // row[2] "UsrCod," // row[3] "UNIX_TIMESTAMP(StartTime) AS ST," // row[4] "UNIX_TIMESTAMP(EndTime) AS ET," // row[5] "NOW() BETWEEN StartTime AND EndTime," // row[6] "CommentTchVisible," // row[7] "Title," // row[8] "Txt" // row[9] " FROM att_events" " WHERE CrsCod=%d" " ORDER BY ST DESC," "ET DESC," "Title DESC", CrsCod); } /*****************************************************************************/ /**************** Get attendance event data using its code *******************/ /*****************************************************************************/ unsigned Att_DB_GetEventDataByCod (MYSQL_RES **mysql_res,long AttCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get attendance event data", "SELECT AttCod," // row[0] "CrsCod," // row[1] "Hidden," // row[2] "UsrCod," // row[3] "UNIX_TIMESTAMP(StartTime)," // row[4] "UNIX_TIMESTAMP(EndTime)," // row[5] "NOW() BETWEEN StartTime AND EndTime," // row[6] "CommentTchVisible," // row[7] "Title" // row[8] " FROM att_events" " WHERE AttCod=%ld", AttCod); } /*****************************************************************************/ /***************** Get attendance event title from database ******************/ /*****************************************************************************/ void Att_DB_GetEventTitle (long AttCod,char *Title,size_t TitleSize) { DB_QuerySELECTString (Title,TitleSize,"can not get attendance event title", "SELECT Title" // row[0] " FROM att_events" " WHERE AttCod=%ld" " AND CrsCod=%ld", // Extra check AttCod, Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /***************** Get attendance event text from database *******************/ /*****************************************************************************/ void Att_DB_GetEventDescription (long AttCod,char Description[Cns_MAX_BYTES_TEXT + 1]) { DB_QuerySELECTString (Description,Cns_MAX_BYTES_TEXT,"can not get attendance event text", "SELECT Txt" // row[0] " FROM att_events" " WHERE AttCod=%ld" " AND CrsCod=%ld", // Extra check AttCod, Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /***** Check if the title or the folder of an attendance event exists ********/ /*****************************************************************************/ bool Att_DB_CheckIfSimilarEventExists (const char *Field,const char *Value,long AttCod) { return DB_QueryEXISTS ("can not check similar attendance events", "SELECT EXISTS" "(SELECT *" " FROM att_events" " WHERE CrsCod=%ld" " AND %s='%s'" " AND AttCod<>%ld)", Gbl.Hierarchy.Node[Hie_CRS].HieCod, Field,Value, AttCod); } /*****************************************************************************/ /********************* Create a new attendance event *************************/ /*****************************************************************************/ long Att_DB_CreateEvent (const struct Att_Event *Event,const char *Description) { extern const char HidVis_YN[HidVis_NUM_HIDDEN_VISIBLE]; return DB_QueryINSERTandReturnCode ("can not create new attendance event", "INSERT INTO att_events" " (CrsCod,Hidden,UsrCod," "StartTime,EndTime," "CommentTchVisible,Title,Txt)" " VALUES" " (%ld,'%c',%ld," "FROM_UNIXTIME(%ld),FROM_UNIXTIME(%ld)," "'%c','%s','%s')", Gbl.Hierarchy.Node[Hie_CRS].HieCod, HidVis_YN[Event->HiddenOrVisible], Gbl.Usrs.Me.UsrDat.UsrCod, Event->TimeUTC[Dat_STR_TIME], Event->TimeUTC[Dat_END_TIME], Event->CommentTchVisible ? 'Y' : 'N', Event->Title, Description); } /*****************************************************************************/ /****************** Update the data of an attendance event *******************/ /*****************************************************************************/ void Att_DB_UpdateEvent (const struct Att_Event *Event,const char *Description) { extern const char HidVis_YN[HidVis_NUM_HIDDEN_VISIBLE]; DB_QueryUPDATE ("can not update attendance event", "UPDATE att_events" " SET Hidden='%c'," "StartTime=FROM_UNIXTIME(%ld)," "EndTime=FROM_UNIXTIME(%ld)," "CommentTchVisible='%c'," "Title='%s'," "Txt='%s'" " WHERE AttCod=%ld" " AND CrsCod=%ld", // Extra check HidVis_YN[Event->HiddenOrVisible], Event->TimeUTC[Dat_STR_TIME], Event->TimeUTC[Dat_END_TIME], Event->CommentTchVisible ? 'Y' : 'N', Event->Title, Description, Event->AttCod, Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /********************** Hide/unhide an attendance event **********************/ /*****************************************************************************/ void Att_DB_HideOrUnhideEvent (long AttCod, HidVis_HiddenOrVisible_t HiddenOrVisible) { extern const char HidVis_YN[HidVis_NUM_HIDDEN_VISIBLE]; DB_QueryUPDATE ("can not hide/unhide assignment", "UPDATE att_events" " SET Hidden='%c'" " WHERE AttCod=%ld" " AND CrsCod=%ld", HidVis_YN[HiddenOrVisible], AttCod, Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /****************** Create group of an attendance event **********************/ /*****************************************************************************/ void Att_DB_CreateGroup (long AttCod,long GrpCod) { DB_QueryINSERT ("can not associate a group to an attendance event", "INSERT INTO att_groups" " (AttCod,GrpCod)" " VALUES" " (%ld,%ld)", AttCod, GrpCod); } /*****************************************************************************/ /************ Get group codes associated to an attendance event **************/ /*****************************************************************************/ unsigned Att_DB_GetGrpCodsAssociatedToEvent (MYSQL_RES **mysql_res,long AttCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get groups of an attendance event", "SELECT GrpCod" // row[0] " FROM att_groups" " WHERE AttCod=%ld", AttCod); } /*****************************************************************************/ /**************** Get groups associated to an attendance event ***************/ /*****************************************************************************/ unsigned Att_DB_GetGroupsAssociatedToEvent (MYSQL_RES **mysql_res,long AttCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get groups of an attendance event", "SELECT grp_types.GrpTypName," // row[0] "grp_groups.GrpName," // row[1] "roo_rooms.ShortName" // row[2] " FROM (att_groups," "grp_groups," "grp_types)" " LEFT JOIN roo_rooms" " ON grp_groups.RooCod=roo_rooms.RooCod" " WHERE att_groups.AttCod=%ld" " AND att_groups.GrpCod=grp_groups.GrpCod" " AND grp_groups.GrpTypCod=grp_types.GrpTypCod" " ORDER BY grp_types.GrpTypName," "grp_groups.GrpName", AttCod); } /*****************************************************************************/ /*************** Remove one group from all attendance events *****************/ /*****************************************************************************/ void Att_DB_RemoveGroup (long GrpCod) { /***** Remove group from all attendance events *****/ DB_QueryDELETE ("can not remove group from the associations" " between attendance events and groups", "DELETE FROM att_groups" " WHERE GrpCod=%ld", GrpCod); } /*****************************************************************************/ /********** Remove groups of one type from all attendance events *************/ /*****************************************************************************/ void Att_DB_RemoveGroupsOfType (long GrpTypCod) { /***** Remove group from all attendance events *****/ DB_QueryDELETE ("can not remove groups of a type from the associations" " between attendance events and groups", "DELETE FROM att_groups" " USING grp_groups," "att_groups" " WHERE grp_groups.GrpTypCod=%ld" " AND grp_groups.GrpCod=att_groups.GrpCod", GrpTypCod); } /*****************************************************************************/ /****************** Remove groups of an attendance event *********************/ /*****************************************************************************/ void Att_DB_RemoveGrpsAssociatedToAnEvent (long AttCod) { DB_QueryDELETE ("can not remove the groups" " associated to an attendance event", "DELETE FROM att_groups" " WHERE AttCod=%ld", AttCod); } /*****************************************************************************/ /******* Get number of students from a list who attended to an event *********/ /*****************************************************************************/ unsigned Att_DB_GetNumStdsTotalWhoAreInEvent (long AttCod) { return (unsigned) DB_QueryCOUNT ("can not get number of students registered in an event", "SELECT COUNT(*)" " FROM att_users" " WHERE AttCod=%ld" " AND Present='Y'", AttCod); } /*****************************************************************************/ /********** Get number of users from a list in an attendance event ***********/ /*****************************************************************************/ unsigned Att_DB_GetNumStdsFromListWhoAreInEvent (long AttCod,const char *SubQueryUsrs) { return (unsigned) DB_QueryCOUNT ("can not get number of students from a list" " who are registered in an event", "SELECT COUNT(*)" " FROM att_users" " WHERE AttCod=%ld" " AND UsrCod IN (%s)" " AND Present='Y'", AttCod,SubQueryUsrs); } /*****************************************************************************/ /******************* Check if a user attended to an event ********************/ /*****************************************************************************/ // Return if user is in table bool Att_DB_CheckIfUsrIsInTableAttUsr (long AttCod,long UsrCod,bool *Present) { char StrPresent[1 + 1]; /***** Check if a user is registered in an event in database *****/ DB_QuerySELECTString (StrPresent,1,"can not check if a user" " is already registered in an event", "SELECT Present" " FROM att_users" " WHERE AttCod=%ld" " AND UsrCod=%ld", AttCod, UsrCod); if (StrPresent[0]) { *Present = (StrPresent[0] == 'Y'); return true; // User is in table } *Present = false; return false; // User is not in table } /*****************************************************************************/ /********** Get if a student attended to an event and get comments ***********/ /*****************************************************************************/ unsigned Att_DB_GetPresentAndComments (MYSQL_RES **mysql_res,long AttCod,long UsrCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get if a student" " is already registered in an event", "SELECT Present," // row[0] "CommentStd," // row[1] "CommentTch" // row[2] " FROM att_users" " WHERE AttCod=%ld" " AND UsrCod=%ld", AttCod, UsrCod); } /*****************************************************************************/ /*********** Return a list with the users in an attendance event *************/ /*****************************************************************************/ unsigned Att_DB_GetListUsrsInEvent (MYSQL_RES **mysql_res, long AttCod,bool AttEventIsAsociatedToGrps) { char *SubQuery; unsigned NumUsrs; /***** Query list of attendance users *****/ if (AttEventIsAsociatedToGrps) { // Event for one or more groups // Subquery: list of users in groups of this attendance event... // ...who have no entry in attendance list of users if (asprintf (&SubQuery,"SELECT DISTINCT " "grp_users.UsrCod AS UsrCod," // row[0] "'N' AS Present" // row[1] " FROM att_groups," "grp_groups," "grp_types," "crs_users," "grp_users" " WHERE att_groups.AttCod=%ld" " AND att_groups.GrpCod=grp_groups.GrpCod" " AND grp_groups.GrpTypCod=grp_types.GrpTypCod" " AND grp_types.CrsCod=crs_users.CrsCod" " AND crs_users.Role=%u" " AND crs_users.UsrCod=grp_users.UsrCod" " AND grp_users.GrpCod=att_groups.GrpCod" " AND grp_users.UsrCod NOT IN" " (SELECT UsrCod" " FROM att_users" " WHERE AttCod=%ld)", AttCod, (unsigned) Rol_STD, AttCod) < 0) Err_NotEnoughMemoryExit (); } else { // Event for the whole course // Subquery: list of users in the course of this attendance event... // ...who have no entry in attendance list of users if (asprintf (&SubQuery,"SELECT crs_users.UsrCod AS UsrCod," // row[0] "'N' AS Present" // row[1] " FROM att_events," "crs_users" " WHERE att_events.AttCod=%ld" " AND att_events.CrsCod=crs_users.CrsCod" " AND crs_users.Role=%u" " AND crs_users.UsrCod NOT IN" " (SELECT UsrCod" " FROM att_users" " WHERE AttCod=%ld)", AttCod, (unsigned) Rol_STD, AttCod) < 0) Err_NotEnoughMemoryExit (); } // Query: list of users in attendance list + rest of users (subquery) NumUsrs = (unsigned) DB_QuerySELECT (mysql_res,"can not get users in an attendance event", "SELECT u.UsrCod," // row[0] "u.Present" // row[1] " FROM (SELECT UsrCod," "Present" " FROM att_users" " WHERE AttCod=%ld" " UNION %s) AS u," "usr_data" " WHERE u.UsrCod=usr_data.UsrCod" " ORDER BY usr_data.Surname1," "usr_data.Surname2," "usr_data.FirstName", AttCod, SubQuery); free (SubQuery); return NumUsrs; } /*****************************************************************************/ /********* Register a user in an attendance event changing comments **********/ /*****************************************************************************/ void Att_DB_RegUsrInEventChangingComments (long AttCod,long UsrCod, bool Present, const char *CommentStd, const char *CommentTch) { /***** Register user as assistant to an event in database *****/ DB_QueryREPLACE ("can not register user in an event", "REPLACE INTO att_users" " (AttCod,UsrCod,Present,CommentStd,CommentTch)" " VALUES" " (%ld,%ld,'%c','%s','%s')", AttCod, UsrCod, Present ? 'Y' : 'N', CommentStd, CommentTch); } /*****************************************************************************/ /**************** Set user as present in an attendance event *****************/ /*****************************************************************************/ void Att_DB_SetUsrAsPresent (long AttCod,long UsrCod) { DB_QueryUPDATE ("can not set user as present in an event", "UPDATE att_users" " SET Present='Y'" " WHERE AttCod=%ld" " AND UsrCod=%ld", AttCod, UsrCod); } /*****************************************************************************/ /**************** Set users as present in an attendance event ****************/ /*****************************************************************************/ void Att_DB_SetUsrsAsPresent (long AttCod,const char *ListUsrs,bool SetOthersAsAbsent) { const char *Ptr; char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1]; struct Usr_Data UsrDat; unsigned NumCodsInList; char *SubQueryAllUsrs = NULL; char SubQueryOneUsr[1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1]; bool Present; size_t Length = 0; // Initialized to avoid warning unsigned NumUsrsPresent = 0; /***** Initialize structure with user's data *****/ Usr_UsrDataConstructor (&UsrDat); /***** Build list of present users *****/ if (SetOthersAsAbsent) { /***** Count number of codes in list *****/ for (Ptr = ListUsrs, NumCodsInList = 0; *Ptr; NumCodsInList++) /* Find next string in text until comma (leading and trailing spaces are removed) */ Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG); /***** Allocate subquery used to mark not present users as absent *****/ Length = 256 + NumCodsInList * (1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1) - 1; if ((SubQueryAllUsrs = malloc (Length + 1)) == NULL) Err_NotEnoughMemoryExit (); SubQueryAllUsrs[0] = '\0'; } for (Ptr = ListUsrs; *Ptr; ) { /* Find next string in text until comma (leading and trailing spaces are removed) */ Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG); if ((UsrDat.UsrCod = Str_ConvertStrCodToLongCod (LongStr)) > 0) if (Usr_DB_ChkIfUsrCodExists (UsrDat.UsrCod)) // The user must belong to course, // but it's not necessary he/she belongs to groups associated to the event if (Enr_CheckIfUsrBelongsToCurrentCrs (&UsrDat) == Usr_BELONG) { /* Mark user as present */ if (Att_DB_CheckIfUsrIsInTableAttUsr (AttCod,UsrDat.UsrCod,&Present)) // User is in table att_users { if (!Present) // If already present ==> nothing to do /***** Set user as present in database *****/ Att_DB_SetUsrAsPresent (AttCod,UsrDat.UsrCod); } else // User is not in table att_users Att_DB_RegUsrInEventChangingComments (AttCod,UsrDat.UsrCod,true,"",""); /* Add this user to query used to mark not present users as absent */ if (SetOthersAsAbsent) { if (!NumUsrsPresent) // Begin building subquery snprintf (SubQueryAllUsrs,Length," AND UsrCod NOT IN (%ld", UsrDat.UsrCod); else // Continue building subquery { snprintf (SubQueryOneUsr,sizeof (SubQueryOneUsr),",%ld", UsrDat.UsrCod); Str_Concat (SubQueryAllUsrs,SubQueryOneUsr,Length); } } NumUsrsPresent++; } } if (NumUsrsPresent) // End building subquery Str_Concat (SubQueryAllUsrs,")",Length); /***** Mark not present users as absent in table of users *****/ if (SetOthersAsAbsent) { DB_QueryUPDATE ("can not set other users as absent", "UPDATE att_users" " SET Present='N'" " WHERE AttCod=%ld" "%s", AttCod, SubQueryAllUsrs); /* Free memory for subquery string */ free (SubQueryAllUsrs); } /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /*****************************************************************************/ /********************** Remove a user from an event **************************/ /*****************************************************************************/ void Att_DB_RemoveUsrFromEvent (long AttCod,long UsrCod) { DB_QueryDELETE ("can not remove student from an event", "DELETE FROM att_users" " WHERE AttCod=%ld" " AND UsrCod=%ld", AttCod,UsrCod); } /*****************************************************************************/ /************ Remove users absent without comments from an event *************/ /*****************************************************************************/ void Att_DB_RemoveUsrsAbsentWithoutCommentsFromEvent (long AttCod) { /***** Clean table att_users *****/ DB_QueryDELETE ("can not remove users absent" " without comments from an event", "DELETE FROM att_users" " WHERE AttCod=%ld" " AND Present='N'" " AND CommentStd=''" " AND CommentTch=''", AttCod); } /*****************************************************************************/ /*********** Remove all users registered in an attendance event **************/ /*****************************************************************************/ void Att_DB_RemoveAllUsrsFromAnEvent (long AttCod) { DB_QueryDELETE ("can not remove attendance event", "DELETE FROM att_users" " WHERE AttCod=%ld", AttCod); } /*****************************************************************************/ /*** Remove one user from all attendance events where he/she is registered ***/ /*****************************************************************************/ void Att_DB_RemoveUsrFromAllEvents (long UsrCod) { DB_QueryDELETE ("can not remove user from all attendance events", "DELETE FROM att_users" " WHERE UsrCod=%ld", UsrCod); } /*****************************************************************************/ /************* Remove one student from all attendance events *****************/ /*****************************************************************************/ void Att_DB_RemoveUsrFromCrsEvents (long UsrCod,long CrsCod) { DB_QueryDELETE ("can not remove user from attendance events of a course", "DELETE FROM att_users" " USING att_events," "att_users" " WHERE att_events.CrsCod=%ld" " AND att_events.AttCod=att_users.AttCod" " AND att_users.UsrCod=%ld", CrsCod,UsrCod); } /*****************************************************************************/ /*********************** Remove an attendance event **************************/ /*****************************************************************************/ void Att_DB_RemoveEventFromCurrentCrs (long AttCod) { DB_QueryDELETE ("can not remove attendance event", "DELETE FROM att_events" " WHERE AttCod=%ld AND CrsCod=%ld", AttCod,Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /************* Remove users in all attendance events of a course *************/ /*****************************************************************************/ void Att_DB_RemoveUsrsFromCrsEvents (long HieCod) { DB_QueryDELETE ("can not remove users registered" " in attendance events of a course", "DELETE FROM att_users" " USING att_events," "att_users" " WHERE att_events.CrsCod=%ld" " AND att_events.AttCod=att_users.AttCod", HieCod); } /*****************************************************************************/ /************ Remove groups in all attendance events of a course *************/ /*****************************************************************************/ void Att_DB_RemoveGrpsAssociatedToCrsEvents (long HieCod) { DB_QueryDELETE ("can not remove all groups associated" " to attendance events of a course", "DELETE FROM att_groups" " USING att_events," "att_groups" " WHERE att_events.CrsCod=%ld" " AND att_events.AttCod=att_groups.AttCod", HieCod); } /*****************************************************************************/ /***************** Remove all attendance events of a course ******************/ /*****************************************************************************/ void Att_DB_RemoveCrsEvents (long HieCod) { DB_QueryDELETE ("can not remove all attendance events of a course", "DELETE FROM att_events" " WHERE CrsCod=%ld", HieCod); } /*****************************************************************************/ /*************** Get number of attendance events in a course *****************/ /*****************************************************************************/ unsigned Att_DB_GetNumEventsInCrs (long HieCod) { /***** Get number of attendance events in a course from database *****/ return (unsigned) DB_QueryCOUNT ("can not get number of attendance events in course", "SELECT COUNT(*)" " FROM att_events" " WHERE CrsCod=%ld", HieCod); } /*****************************************************************************/ /*************** Get number of courses with attendance events ****************/ /*****************************************************************************/ // Returns the number of courses with attendance events // in this location (all the platform, the current degree or the current course) unsigned Att_DB_GetNumCoursesWithEvents (Hie_Level_t Level) { switch (Level) { case Hie_SYS: return DB_QueryCOUNT ("can not get number of courses with attendance events", "SELECT COUNT(DISTINCT CrsCod)" " FROM att_events" " WHERE CrsCod>0"); case Hie_INS: return DB_QueryCOUNT ("can not get number of courses with attendance events", "SELECT COUNT(DISTINCT att_events.CrsCod)" " FROM ctr_centers," "deg_degrees," "crs_courses," "att_events" " WHERE ctr_centers.InsCod=%ld" " AND ctr_centers.CtrCod=deg_degrees.CtrCod" " AND deg_degrees.DegCod=crs_courses.DegCod" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_INS].HieCod); case Hie_CTR: return DB_QueryCOUNT ("can not get number of courses with attendance events", "SELECT COUNT(DISTINCT att_events.CrsCod)" " FROM deg_degrees," "crs_courses," "att_events" " WHERE deg_degrees.CtrCod=%ld" " AND deg_degrees.DegCod=crs_courses.DegCod" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_CTR].HieCod); case Hie_DEG: return DB_QueryCOUNT ("can not get number of courses with attendance events", "SELECT COUNT(DISTINCT att_events.CrsCod)" " FROM crs_courses," "att_events" " WHERE crs_courses.DegCod=%ld" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_DEG].HieCod); case Hie_CRS: return DB_QueryCOUNT ("can not get number of courses with attendance events", "SELECT COUNT(DISTINCT CrsCod)" " FROM att_events" " WHERE CrsCod=%ld", Gbl.Hierarchy.Node[Hie_CRS].HieCod); default: Err_WrongHierarchyLevelExit (); return 0; // Not reached } } /*****************************************************************************/ /********************* Get number of attendance events ***********************/ /*****************************************************************************/ unsigned Att_DB_GetNumEvents (MYSQL_RES **mysql_res,Hie_Level_t Level) { switch (Level) { case Hie_SYS: return (unsigned) DB_QuerySELECT (mysql_res,"can not get number of attendance events", "SELECT COUNT(*)," // row[0] "SUM(NumNotif)" // row[1] " FROM att_events" " WHERE CrsCod>0"); case Hie_INS: return (unsigned) DB_QuerySELECT (mysql_res,"can not get number of attendance events", "SELECT COUNT(*)," // row[0] "SUM(att_events.NumNotif)" // row[1] " FROM ctr_centers," "deg_degrees," "crs_courses," "att_events" " WHERE ctr_centers.InsCod=%ld" " AND ctr_centers.CtrCod=deg_degrees.CtrCod" " AND deg_degrees.DegCod=crs_courses.DegCod" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_INS].HieCod); case Hie_CTR: return (unsigned) DB_QuerySELECT (mysql_res,"can not get number of attendance events", "SELECT COUNT(*)," // row[0] "SUM(att_events.NumNotif)" // row[1] " FROM deg_degrees," "crs_courses," "att_events" " WHERE deg_degrees.CtrCod=%ld" " AND deg_degrees.DegCod=crs_courses.DegCod" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_CTR].HieCod); case Hie_DEG: return (unsigned) DB_QuerySELECT (mysql_res,"can not get number of attendance events", "SELECT COUNT(*)," // row[0] "SUM(att_events.NumNotif)" // row[1] " FROM crs_courses," "att_events" " WHERE crs_courses.DegCod=%ld" " AND crs_courses.CrsCod=att_events.CrsCod", Gbl.Hierarchy.Node[Hie_DEG].HieCod); case Hie_CRS: return (unsigned) DB_QuerySELECT (mysql_res,"can not get number of attendance events", "SELECT COUNT(*)," // row[0] "SUM(NumNotif)" // row[1] " FROM att_events" " WHERE CrsCod=%ld", Gbl.Hierarchy.Node[Hie_CRS].HieCod); default: Err_WrongHierarchyLevelExit (); return 0; // Not reached } }