// swad_course_database.c: edition of courses 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 // For asprintf #include // For free #include "swad_course.h" #include "swad_course_config.h" #include "swad_database.h" #include "swad_error.h" #include "swad_global.h" #include "swad_hierarchy.h" #include "swad_hierarchy_database.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /************* Add a new requested course to pending requests ****************/ /*****************************************************************************/ void Crs_DB_CreateCourse (struct Hie_Node *Crs,Hie_Status_t Status) { /***** Insert new course into pending requests *****/ Crs->HieCod = DB_QueryINSERTandReturnCode ("can not create a new course", "INSERT INTO crs_courses" " (DegCod,Year,InsCrsCod,Status,RequesterUsrCod," "ShortName,FullName)" " VALUES" " (%ld,%u,'%s',%u,%ld," "'%s','%s')", Crs->PrtCod, Crs->Specific.Year, Crs->InstitutionalCod, (unsigned) Status, Gbl.Usrs.Me.UsrDat.UsrCod, Crs->ShrtName, Crs->FullName); } /*****************************************************************************/ /******************* Get courses of a degree from database *******************/ /*****************************************************************************/ unsigned Crs_DB_GetCrssInDeg (MYSQL_RES **mysql_res,long DegCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get courses of a degree", "SELECT CrsCod" " FROM crs_courses" " WHERE DegCod=%ld", DegCod); } /*****************************************************************************/ /******************** Get courses in current degree *********************/ /*****************************************************************************/ unsigned Crs_DB_GetCrssInCurrentDegBasic (MYSQL_RES **mysql_res) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get courses of a degree", "SELECT CrsCod," // row[0] "ShortName" // row[1] " FROM crs_courses" " WHERE DegCod=%ld" " ORDER BY ShortName", Gbl.Hierarchy.Node[Hie_DEG].HieCod); } /*****************************************************************************/ /******************** Get courses in current degree *********************/ /*****************************************************************************/ unsigned Crs_DB_GetCrssInCurrentDegFull (MYSQL_RES **mysql_res) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get courses of a degree", "SELECT CrsCod," // row[0] "DegCod," // row[1] "Year," // row[2] "InsCrsCod," // row[3] "Status," // row[4] "RequesterUsrCod," // row[5] "ShortName," // row[6] "FullName" // row[7] " FROM crs_courses" " WHERE DegCod=%ld" " AND (Status & %u)=0" " ORDER BY Year," "ShortName", Gbl.Hierarchy.Node[Hie_DEG].HieCod, (unsigned) Hie_STATUS_BIT_REMOVED); // All courses except those removed } /*****************************************************************************/ /********************* Get data of a course from its code ********************/ /*****************************************************************************/ unsigned Crs_DB_GetCourseDataByCod (MYSQL_RES **mysql_res,long CrsCod) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get data of a course", "SELECT CrsCod," // row[0] "DegCod," // row[1] "Year," // row[2] "InsCrsCod," // row[3] "Status," // row[4] "RequesterUsrCod," // row[5] "ShortName," // row[6] "FullName" // row[7] " FROM crs_courses" " WHERE CrsCod=%ld", CrsCod); } /*****************************************************************************/ /************* Get the degree code of a course from its code *****************/ /*****************************************************************************/ long Crs_DB_GetDegCodOfCourseByCod (long CrsCod) { /***** Trivial check: course code should be > 0 *****/ if (CrsCod <= 0) return -1L; /***** Get the degree code of a course from database *****/ return DB_QuerySELECTCode ("can not get the degree of a course", "SELECT DegCod" " FROM crs_courses" " WHERE CrsCod=%ld", CrsCod); } /*****************************************************************************/ /******* Get the short names of degree and course from a course code *********/ /*****************************************************************************/ void Crs_DB_GetShortNamesByCod (long CrsCod, char CrsShortName[Nam_MAX_BYTES_SHRT_NAME + 1], char DegShortName[Nam_MAX_BYTES_SHRT_NAME + 1]) { MYSQL_RES *mysql_res; MYSQL_ROW row; DegShortName[0] = CrsShortName[0] = '\0'; /***** Trivial check: course code should be > 0 *****/ if (CrsCod <= 0) return; /***** Get the short name of a degree from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get the short name of a course", "SELECT crs_courses.ShortName," // row[0] "deg_degrees.ShortName" // row[1] " FROM crs_courses," "deg_degrees" " WHERE crs_courses.CrsCod=%ld" " AND crs_courses.DegCod=deg_degrees.DegCod", CrsCod) == 1) { /***** Get the course short name and degree short name *****/ row = mysql_fetch_row (mysql_res); Str_Copy (CrsShortName,row[0],Nam_MAX_BYTES_SHRT_NAME); Str_Copy (DegShortName,row[1],Nam_MAX_BYTES_SHRT_NAME); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /************** Check if course code exists in existing courses **************/ /*****************************************************************************/ bool Crs_DB_CheckIfCrsCodExists (long CrsCod) { return DB_QueryEXISTS ("can not check if a course already existed", "SELECT EXISTS" "(SELECT *" " FROM crs_courses" " WHERE CrsCod=%ld)", CrsCod); } /*****************************************************************************/ /********** Check if the name of course exists in existing courses ***********/ /*****************************************************************************/ bool Crs_DB_CheckIfCrsNameExistsInYearOfDeg (const char *FldName,const char *Name, long Cod,long PrtCod,unsigned Year) { return DB_QueryEXISTS ("can not check if the name of a course already existed", "SELECT EXISTS" "(SELECT *" " FROM crs_courses" " WHERE DegCod=%ld" " AND Year=%u" " AND %s='%s'" " AND CrsCod<>%ld)", PrtCod, Year, FldName,Name, Cod); } /*****************************************************************************/ /************************** Write courses of a user **************************/ /*****************************************************************************/ unsigned Crs_DB_GetCrssOfAUsr (MYSQL_RES **mysql_res,long UsrCod,Rol_Role_t Role) { char *SubQuery; unsigned NumCrss; /***** Get courses of a user from database *****/ if (Role == Rol_UNK) // Role == Rol_UNK ==> any role { if (asprintf (&SubQuery,"%s","") < 0) Err_NotEnoughMemoryExit (); } else { if (asprintf (&SubQuery," AND crs_users.Role=%u",(unsigned) Role) < 0) Err_NotEnoughMemoryExit (); } NumCrss = (unsigned) DB_QuerySELECT (mysql_res,"can not get courses of a user", "SELECT deg_degrees.DegCod," // row[0] "crs_courses.CrsCod," // row[1] "deg_degrees.ShortName," // row[2] "deg_degrees.FullName," // row[3] "crs_courses.Year," // row[4] "crs_courses.FullName," // row[5] "ctr_centers.ShortName," // row[6] "crs_users.Accepted" // row[7] " FROM crs_users," "crs_courses," "deg_degrees," "ctr_centers" " WHERE crs_users.UsrCod=%ld%s" " AND crs_users.CrsCod=crs_courses.CrsCod" " AND crs_courses.DegCod=deg_degrees.DegCod" " AND deg_degrees.CtrCod=ctr_centers.CtrCod" " ORDER BY deg_degrees.FullName," "crs_courses.Year," "crs_courses.FullName", UsrCod,SubQuery); /***** Free allocated memory for subquery *****/ free (SubQuery); return NumCrss; } /*****************************************************************************/ /************************** Get old courses from database ********************/ /*****************************************************************************/ unsigned Crs_DB_GetOldCrss (MYSQL_RES **mysql_res,unsigned long SecondsWithoutAccess) { return (unsigned) DB_QuerySELECT (mysql_res,"can not get old courses", "SELECT CrsCod" " FROM crs_last" " WHERE LastTime 0) // Courses in a degree return (unsigned) DB_QuerySELECT (mysql_res,"can not get the courses a user belongs to", "SELECT crs_users.CrsCod," // row[0] "crs_users.Role," // row[1] "crs_courses.DegCod" // row[2] " FROM crs_users," "crs_courses" " WHERE crs_users.UsrCod=%ld" " AND crs_users.CrsCod=crs_courses.CrsCod" " AND crs_courses.DegCod=%ld" " ORDER BY crs_courses.ShortName", UsrCod, PrtCod); else // All the courses return (unsigned) DB_QuerySELECT (mysql_res,"can not get the courses a user belongs to", "SELECT crs_users.CrsCod," // row[0] "crs_users.Role," // row[1] "crs_courses.DegCod" // row[2] " FROM crs_users," "crs_courses," "deg_degrees" " WHERE crs_users.UsrCod=%ld" " AND crs_users.CrsCod=crs_courses.CrsCod" " AND crs_courses.DegCod=deg_degrees.DegCod" " ORDER BY deg_degrees.ShortName," "crs_courses.ShortName", UsrCod); } /*****************************************************************************/ /************* Change the institutional course code of a course **************/ /*****************************************************************************/ void Crs_DB_UpdateInstitutionalCrsCod (long CrsCod,const char *NewInstitutionalCrsCod) { DB_QueryUPDATE ("can not update the institutional code of a course", "UPDATE crs_courses" " SET InsCrsCod='%s'" " WHERE CrsCod=%ld", NewInstitutionalCrsCod, CrsCod); } /*****************************************************************************/ /****************** Change the year/semester of a course *********************/ /*****************************************************************************/ void Crs_DB_UpdateCrsYear (long CrsCod,unsigned NewYear) { DB_QueryUPDATE ("can not update the year of a course", "UPDATE crs_courses" " SET Year=%u" " WHERE CrsCod=%ld", NewYear, CrsCod); } /*****************************************************************************/ /***************** Update course name in table of courses ********************/ /*****************************************************************************/ void Crs_DB_UpdateCrsName (long CrsCod, const char *FldName,const char *NewCrsName) { DB_QueryUPDATE ("can not update the name of a course", "UPDATE crs_courses" " SET %s='%s'" " WHERE CrsCod=%ld", FldName,NewCrsName, CrsCod); } /*****************************************************************************/ /********************** Update degree in table of courses ********************/ /*****************************************************************************/ void Crs_DB_UpdateCrsDeg (long CrsCod,long DegCod) { DB_QueryUPDATE ("can not move course to another degree", "UPDATE crs_courses" " SET DegCod=%ld" " WHERE CrsCod=%ld", DegCod, CrsCod); } /*****************************************************************************/ /********************** Change the status of a course ************************/ /*****************************************************************************/ void Crs_DB_UpdateCrsStatus (long CrsCod,Hie_Status_t Status) { DB_QueryUPDATE ("can not update the status of a course", "UPDATE crs_courses" " SET Status=%u" " WHERE CrsCod=%ld", (unsigned) Status, CrsCod); } /*****************************************************************************/ /***************** Update my last click in current course ********************/ /*****************************************************************************/ void Crs_DB_UpdateCrsLastClick (void) { /***** Update last access to current course *****/ DB_QueryREPLACE ("can not update last access to current course", "REPLACE INTO crs_last" " (CrsCod,LastTime)" " VALUES" " (%ld,NOW())", Gbl.Hierarchy.Node[Hie_CRS].HieCod); } /*****************************************************************************/ /******************** Remove information about a course **********************/ /*****************************************************************************/ void Crs_DB_RemoveCrsInfo (long CrsCod) { /* Remove information source of the course */ DB_QueryDELETE ("can not remove info sources of a course", "DELETE FROM crs_info_src" " WHERE CrsCod=%ld", CrsCod); /* Remove information text of the course */ DB_QueryDELETE ("can not remove info of a course", "DELETE FROM crs_info_txt" " WHERE CrsCod=%ld", CrsCod); } /*****************************************************************************/ /********************** Remove timetable of a course *************************/ /*****************************************************************************/ void Crs_DB_RemoveCrsTimetable (long CrsCod) { DB_QueryDELETE ("can not remove the timetable of a course", "DELETE FROM tmt_courses" " WHERE CrsCod=%ld", CrsCod); } /*****************************************************************************/ /***** Remove course from table of last accesses to courses in database ******/ /*****************************************************************************/ void Crs_DB_RemoveCrsLast (long CrsCod) { DB_QueryDELETE ("can not remove a course", "DELETE FROM crs_last" " WHERE CrsCod=%ld", CrsCod); } /*****************************************************************************/ /************* Remove course from table of courses in database ***************/ /*****************************************************************************/ void Crs_DB_RemoveCrs (long CrsCod) { DB_QueryDELETE ("can not remove a course", "DELETE FROM crs_courses" " WHERE CrsCod=%ld", CrsCod); }