From 2520d5c8527c4a5b9c4c266e20d03f48cf7bcb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Thu, 20 Feb 2020 23:48:48 +0100 Subject: [PATCH] Version19.130 --- Makefile | 3 +- sql/swad.sql | 21 + swad_action.c | 24 +- swad_action.h | 205 +++--- swad_changelog.h | 9 + swad_database.c | 45 ++ swad_figure.c | 65 ++ swad_figure.h | 3 +- swad_global.c | 6 + swad_global.h | 9 + swad_help_URL.c | 63 ++ swad_menu.c | 2 +- swad_pagination.c | 38 + swad_pagination.h | 25 +- swad_program.c | 1701 ++++++++++++++++++++++++++++++++++++++++++++ swad_program.h | 90 +++ swad_text.c | 289 +++++++- swad_text_action.c | 2 +- 18 files changed, 2476 insertions(+), 124 deletions(-) create mode 100644 swad_program.c create mode 100644 swad_program.h diff --git a/Makefile b/Makefile index 00f26e45..74fb67da 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,8 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \ swad_message.o swad_MFU.o \ swad_network.o swad_nickname.o swad_notice.o swad_notification.o \ swad_pagination.o swad_parameter.o swad_password.o swad_photo.o \ - swad_place.o swad_plugin.o swad_privacy.o swad_profile.o swad_project.o \ + swad_place.o swad_plugin.o swad_privacy.o swad_profile.o \ + swad_program.o swad_project.o \ swad_QR.o \ swad_record.o swad_report.o swad_role.o swad_RSS.o \ swad_scope.o swad_search.o swad_session.o swad_setting.o \ diff --git a/sql/swad.sql b/sql/swad.sql index fc0a7766..33261a4c 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -1025,6 +1025,27 @@ CREATE TABLE IF NOT EXISTS plugins ( IP CHAR(15) NOT NULL, UNIQUE INDEX(PlgCod)); -- +-- Table prg_grp: stores the groups associated to each program item +-- +CREATE TABLE IF NOT EXISTS prg_grp ( + PrgIteCod INT NOT NULL, + GrpCod INT NOT NULL, + UNIQUE INDEX(PrgIteCod,GrpCod)); +-- +-- Table prg_items: stores the items of the course program +-- +CREATE TABLE IF NOT EXISTS prg_items ( + PrgIteCod INT NOT NULL AUTO_INCREMENT, + CrsCod INT NOT NULL DEFAULT -1, + Hidden ENUM('N','Y') NOT NULL DEFAULT 'N', + UsrCod INT NOT NULL, + StartTime DATETIME NOT NULL, + EndTime DATETIME NOT NULL, + Title VARCHAR(2047) NOT NULL, + Txt TEXT NOT NULL, + UNIQUE INDEX(PrgIteCod), + INDEX(CrsCod,Hidden)); +-- -- Table prj_config: stores the configuration of projects for each course -- CREATE TABLE IF NOT EXISTS prj_config ( diff --git a/swad_action.c b/swad_action.c index 95497a8f..f098d51c 100644 --- a/swad_action.c +++ b/swad_action.c @@ -73,6 +73,7 @@ #include "swad_photo.h" #include "swad_privacy.h" #include "swad_profile.h" +#include "swad_program.h" #include "swad_project.h" #include "swad_QR.h" #include "swad_report.h" @@ -380,7 +381,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = // TabCrs ****************************************************************** // Actions in menu: [ActSeeCrsInf ] = { 847, 0,TabCrs,ActSeeCrsInf ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Crs_ShowIntroduction ,"info" }, - [ActSeeScd ] = {1821, 1,TabCrs,ActSeeScd ,0x200,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Crs_ShowIntroduction ,"clipboard-list" }, + [ActSeePrg ] = {1821, 1,TabCrs,ActSeePrg ,0x200,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_SeeCourseProgram ,"clipboard-list" }, [ActSeeTchGui ] = { 784, 2,TabCrs,ActSeeTchGui ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_ShowInfo ,"book-open" }, [ActSeeSyl ] = {1242, 3,TabCrs,ActSeeSyl ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_ShowInfo ,"list-ol" }, [ActSeeBib ] = { 32, 4,TabCrs,ActSeeBib ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_ShowInfo ,"book" }, @@ -397,6 +398,16 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActChgCrsYeaCfg ] = {1573,-1,TabUnk,ActSeeCrsInf ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,CrsCfg_ChangeCrsYear ,CrsCfg_ContEditAfterChgCrs ,NULL}, [ActEdiCrsInf ] = { 848,-1,TabUnk,ActSeeCrsInf ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_FormsToSelSendInfo ,NULL}, + [ActFrmNewPrgIte ] = {1822,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_RequestCreatOrEditPrgItem ,NULL}, + [ActEdiOnePrgIte ] = {1823,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_RequestCreatOrEditPrgItem ,NULL}, + [ActPrnOnePrgIte ] = {1824,-1,TabUnk,ActSeePrg ,0x3F8,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_NEW_TAB,NULL ,Prg_PrintOnePrgItem ,NULL}, + [ActNewPrgIte ] = {1825,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_RecFormPrgItem ,NULL}, + [ActChgPrgIte ] = {1826,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_RecFormPrgItem ,NULL}, + [ActReqRemPrgIte ] = {1827,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ReqRemPrgItem ,NULL}, + [ActRemPrgIte ] = {1828,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_RemovePrgItem ,NULL}, + [ActHidPrgIte ] = {1829,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_HidePrgItem ,NULL}, + [ActShoPrgIte ] = {1830,-1,TabUnk,ActSeePrg ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prg_ShowPrgItem ,NULL}, + [ActEdiTchGui ] = { 785,-1,TabUnk,ActSeeTchGui ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_FormsToSelSendInfo ,NULL}, [ActSeeSylLec ] = { 28,-1,TabUnk,ActSeeSyl ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_ShowInfo ,NULL}, @@ -3536,7 +3547,16 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un ActSeeSysInf, // #1818 ActPrnSysInf, // #1819 ActMtn, // #1820 - ActSeeScd, // #1821 + ActSeePrg, // #1821 + ActFrmNewPrgIte, // #1822 + ActEdiOnePrgIte, // #1823 + ActPrnOnePrgIte, // #1824 + ActNewPrgIte, // #1825 + ActChgPrgIte, // #1826 + ActReqRemPrgIte, // #1827 + ActRemPrgIte, // #1828 + ActHidPrgIte, // #1829 + ActShoPrgIte, // #1830 }; /*****************************************************************************/ diff --git a/swad_action.h b/swad_action.h index b85b876c..3468353e 100644 --- a/swad_action.h +++ b/swad_action.h @@ -64,7 +64,7 @@ typedef enum typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to indicate obsolete action -#define Act_MAX_ACTION_COD 1821 +#define Act_MAX_ACTION_COD 1830 #define Act_MAX_OPTIONS_IN_MENU_PER_TAB 13 @@ -368,7 +368,7 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to /*****************************************************************************/ // Actions in menu #define ActSeeCrsInf (ActChgCrsSta + 1) -#define ActSeeScd (ActChgCrsSta + 2) +#define ActSeePrg (ActChgCrsSta + 2) #define ActSeeTchGui (ActChgCrsSta + 3) #define ActSeeSyl (ActChgCrsSta + 4) #define ActSeeBib (ActChgCrsSta + 5) @@ -384,107 +384,116 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to #define ActChgInsCrsCodCfg (ActChgCrsSta + 13) #define ActChgCrsYeaCfg (ActChgCrsSta + 14) #define ActEdiCrsInf (ActChgCrsSta + 15) -#define ActEdiTchGui (ActChgCrsSta + 16) -#define ActSeeSylLec (ActChgCrsSta + 17) -#define ActSeeSylPra (ActChgCrsSta + 18) -#define ActEdiSylLec (ActChgCrsSta + 19) -#define ActEdiSylPra (ActChgCrsSta + 20) -#define ActDelItmSylLec (ActChgCrsSta + 21) -#define ActDelItmSylPra (ActChgCrsSta + 22) -#define ActUp_IteSylLec (ActChgCrsSta + 23) -#define ActUp_IteSylPra (ActChgCrsSta + 24) -#define ActDwnIteSylLec (ActChgCrsSta + 25) -#define ActDwnIteSylPra (ActChgCrsSta + 26) -#define ActRgtIteSylLec (ActChgCrsSta + 27) -#define ActRgtIteSylPra (ActChgCrsSta + 28) -#define ActLftIteSylLec (ActChgCrsSta + 29) -#define ActLftIteSylPra (ActChgCrsSta + 30) -#define ActInsIteSylLec (ActChgCrsSta + 31) -#define ActInsIteSylPra (ActChgCrsSta + 32) -#define ActModIteSylLec (ActChgCrsSta + 33) -#define ActModIteSylPra (ActChgCrsSta + 34) +#define ActFrmNewPrgIte (ActChgCrsSta + 16) +#define ActEdiOnePrgIte (ActChgCrsSta + 17) +#define ActPrnOnePrgIte (ActChgCrsSta + 18) +#define ActNewPrgIte (ActChgCrsSta + 19) +#define ActChgPrgIte (ActChgCrsSta + 20) +#define ActReqRemPrgIte (ActChgCrsSta + 21) +#define ActRemPrgIte (ActChgCrsSta + 22) +#define ActHidPrgIte (ActChgCrsSta + 23) +#define ActShoPrgIte (ActChgCrsSta + 24) +#define ActEdiTchGui (ActChgCrsSta + 25) +#define ActSeeSylLec (ActChgCrsSta + 26) +#define ActSeeSylPra (ActChgCrsSta + 27) +#define ActEdiSylLec (ActChgCrsSta + 28) +#define ActEdiSylPra (ActChgCrsSta + 29) +#define ActDelItmSylLec (ActChgCrsSta + 30) +#define ActDelItmSylPra (ActChgCrsSta + 31) +#define ActUp_IteSylLec (ActChgCrsSta + 32) +#define ActUp_IteSylPra (ActChgCrsSta + 33) +#define ActDwnIteSylLec (ActChgCrsSta + 34) +#define ActDwnIteSylPra (ActChgCrsSta + 35) +#define ActRgtIteSylLec (ActChgCrsSta + 36) +#define ActRgtIteSylPra (ActChgCrsSta + 37) +#define ActLftIteSylLec (ActChgCrsSta + 38) +#define ActLftIteSylPra (ActChgCrsSta + 39) +#define ActInsIteSylLec (ActChgCrsSta + 40) +#define ActInsIteSylPra (ActChgCrsSta + 41) +#define ActModIteSylLec (ActChgCrsSta + 42) +#define ActModIteSylPra (ActChgCrsSta + 43) -#define ActEdiBib (ActChgCrsSta + 35) -#define ActEdiFAQ (ActChgCrsSta + 36) -#define ActEdiCrsLnk (ActChgCrsSta + 37) +#define ActEdiBib (ActChgCrsSta + 44) +#define ActEdiFAQ (ActChgCrsSta + 45) +#define ActEdiCrsLnk (ActChgCrsSta + 46) -#define ActChgFrcReaCrsInf (ActChgCrsSta + 38) -#define ActChgFrcReaTchGui (ActChgCrsSta + 39) -#define ActChgFrcReaSylLec (ActChgCrsSta + 40) -#define ActChgFrcReaSylPra (ActChgCrsSta + 41) -#define ActChgFrcReaBib (ActChgCrsSta + 42) -#define ActChgFrcReaFAQ (ActChgCrsSta + 43) -#define ActChgFrcReaCrsLnk (ActChgCrsSta + 44) +#define ActChgFrcReaCrsInf (ActChgCrsSta + 47) +#define ActChgFrcReaTchGui (ActChgCrsSta + 48) +#define ActChgFrcReaSylLec (ActChgCrsSta + 49) +#define ActChgFrcReaSylPra (ActChgCrsSta + 50) +#define ActChgFrcReaBib (ActChgCrsSta + 51) +#define ActChgFrcReaFAQ (ActChgCrsSta + 52) +#define ActChgFrcReaCrsLnk (ActChgCrsSta + 53) -#define ActChgHavReaCrsInf (ActChgCrsSta + 45) -#define ActChgHavReaTchGui (ActChgCrsSta + 46) -#define ActChgHavReaSylLec (ActChgCrsSta + 47) -#define ActChgHavReaSylPra (ActChgCrsSta + 48) -#define ActChgHavReaBib (ActChgCrsSta + 49) -#define ActChgHavReaFAQ (ActChgCrsSta + 50) -#define ActChgHavReaCrsLnk (ActChgCrsSta + 51) +#define ActChgHavReaCrsInf (ActChgCrsSta + 54) +#define ActChgHavReaTchGui (ActChgCrsSta + 55) +#define ActChgHavReaSylLec (ActChgCrsSta + 56) +#define ActChgHavReaSylPra (ActChgCrsSta + 57) +#define ActChgHavReaBib (ActChgCrsSta + 58) +#define ActChgHavReaFAQ (ActChgCrsSta + 59) +#define ActChgHavReaCrsLnk (ActChgCrsSta + 60) -#define ActSelInfSrcCrsInf (ActChgCrsSta + 52) -#define ActSelInfSrcTchGui (ActChgCrsSta + 53) -#define ActSelInfSrcSylLec (ActChgCrsSta + 54) -#define ActSelInfSrcSylPra (ActChgCrsSta + 55) -#define ActSelInfSrcBib (ActChgCrsSta + 56) -#define ActSelInfSrcFAQ (ActChgCrsSta + 57) -#define ActSelInfSrcCrsLnk (ActChgCrsSta + 58) -#define ActRcvURLCrsInf (ActChgCrsSta + 59) -#define ActRcvURLTchGui (ActChgCrsSta + 60) -#define ActRcvURLSylLec (ActChgCrsSta + 61) -#define ActRcvURLSylPra (ActChgCrsSta + 62) -#define ActRcvURLBib (ActChgCrsSta + 63) -#define ActRcvURLFAQ (ActChgCrsSta + 64) -#define ActRcvURLCrsLnk (ActChgCrsSta + 65) -#define ActRcvPagCrsInf (ActChgCrsSta + 66) -#define ActRcvPagTchGui (ActChgCrsSta + 67) -#define ActRcvPagSylLec (ActChgCrsSta + 68) -#define ActRcvPagSylPra (ActChgCrsSta + 69) -#define ActRcvPagBib (ActChgCrsSta + 70) -#define ActRcvPagFAQ (ActChgCrsSta + 71) -#define ActRcvPagCrsLnk (ActChgCrsSta + 72) -#define ActEditorCrsInf (ActChgCrsSta + 73) -#define ActEditorTchGui (ActChgCrsSta + 74) -#define ActEditorSylLec (ActChgCrsSta + 75) -#define ActEditorSylPra (ActChgCrsSta + 76) -#define ActEditorBib (ActChgCrsSta + 77) -#define ActEditorFAQ (ActChgCrsSta + 78) -#define ActEditorCrsLnk (ActChgCrsSta + 79) -#define ActPlaTxtEdiCrsInf (ActChgCrsSta + 80) -#define ActPlaTxtEdiTchGui (ActChgCrsSta + 81) -#define ActPlaTxtEdiSylLec (ActChgCrsSta + 82) -#define ActPlaTxtEdiSylPra (ActChgCrsSta + 83) -#define ActPlaTxtEdiBib (ActChgCrsSta + 84) -#define ActPlaTxtEdiFAQ (ActChgCrsSta + 85) -#define ActPlaTxtEdiCrsLnk (ActChgCrsSta + 86) -#define ActRchTxtEdiCrsInf (ActChgCrsSta + 87) -#define ActRchTxtEdiTchGui (ActChgCrsSta + 88) -#define ActRchTxtEdiSylLec (ActChgCrsSta + 89) -#define ActRchTxtEdiSylPra (ActChgCrsSta + 90) -#define ActRchTxtEdiBib (ActChgCrsSta + 91) -#define ActRchTxtEdiFAQ (ActChgCrsSta + 92) -#define ActRchTxtEdiCrsLnk (ActChgCrsSta + 93) -#define ActRcvPlaTxtCrsInf (ActChgCrsSta + 94) -#define ActRcvPlaTxtTchGui (ActChgCrsSta + 95) -#define ActRcvPlaTxtSylLec (ActChgCrsSta + 96) -#define ActRcvPlaTxtSylPra (ActChgCrsSta + 97) -#define ActRcvPlaTxtBib (ActChgCrsSta + 98) -#define ActRcvPlaTxtFAQ (ActChgCrsSta + 99) -#define ActRcvPlaTxtCrsLnk (ActChgCrsSta + 100) -#define ActRcvRchTxtCrsInf (ActChgCrsSta + 101) -#define ActRcvRchTxtTchGui (ActChgCrsSta + 102) -#define ActRcvRchTxtSylLec (ActChgCrsSta + 103) -#define ActRcvRchTxtSylPra (ActChgCrsSta + 104) -#define ActRcvRchTxtBib (ActChgCrsSta + 105) -#define ActRcvRchTxtFAQ (ActChgCrsSta + 106) -#define ActRcvRchTxtCrsLnk (ActChgCrsSta + 107) +#define ActSelInfSrcCrsInf (ActChgCrsSta + 61) +#define ActSelInfSrcTchGui (ActChgCrsSta + 62) +#define ActSelInfSrcSylLec (ActChgCrsSta + 63) +#define ActSelInfSrcSylPra (ActChgCrsSta + 64) +#define ActSelInfSrcBib (ActChgCrsSta + 65) +#define ActSelInfSrcFAQ (ActChgCrsSta + 66) +#define ActSelInfSrcCrsLnk (ActChgCrsSta + 67) +#define ActRcvURLCrsInf (ActChgCrsSta + 68) +#define ActRcvURLTchGui (ActChgCrsSta + 69) +#define ActRcvURLSylLec (ActChgCrsSta + 70) +#define ActRcvURLSylPra (ActChgCrsSta + 71) +#define ActRcvURLBib (ActChgCrsSta + 72) +#define ActRcvURLFAQ (ActChgCrsSta + 73) +#define ActRcvURLCrsLnk (ActChgCrsSta + 74) +#define ActRcvPagCrsInf (ActChgCrsSta + 75) +#define ActRcvPagTchGui (ActChgCrsSta + 76) +#define ActRcvPagSylLec (ActChgCrsSta + 77) +#define ActRcvPagSylPra (ActChgCrsSta + 78) +#define ActRcvPagBib (ActChgCrsSta + 79) +#define ActRcvPagFAQ (ActChgCrsSta + 80) +#define ActRcvPagCrsLnk (ActChgCrsSta + 81) +#define ActEditorCrsInf (ActChgCrsSta + 82) +#define ActEditorTchGui (ActChgCrsSta + 83) +#define ActEditorSylLec (ActChgCrsSta + 84) +#define ActEditorSylPra (ActChgCrsSta + 85) +#define ActEditorBib (ActChgCrsSta + 86) +#define ActEditorFAQ (ActChgCrsSta + 87) +#define ActEditorCrsLnk (ActChgCrsSta + 88) +#define ActPlaTxtEdiCrsInf (ActChgCrsSta + 89) +#define ActPlaTxtEdiTchGui (ActChgCrsSta + 90) +#define ActPlaTxtEdiSylLec (ActChgCrsSta + 91) +#define ActPlaTxtEdiSylPra (ActChgCrsSta + 92) +#define ActPlaTxtEdiBib (ActChgCrsSta + 93) +#define ActPlaTxtEdiFAQ (ActChgCrsSta + 94) +#define ActPlaTxtEdiCrsLnk (ActChgCrsSta + 95) +#define ActRchTxtEdiCrsInf (ActChgCrsSta + 96) +#define ActRchTxtEdiTchGui (ActChgCrsSta + 97) +#define ActRchTxtEdiSylLec (ActChgCrsSta + 98) +#define ActRchTxtEdiSylPra (ActChgCrsSta + 99) +#define ActRchTxtEdiBib (ActChgCrsSta + 100) +#define ActRchTxtEdiFAQ (ActChgCrsSta + 101) +#define ActRchTxtEdiCrsLnk (ActChgCrsSta + 102) +#define ActRcvPlaTxtCrsInf (ActChgCrsSta + 103) +#define ActRcvPlaTxtTchGui (ActChgCrsSta + 104) +#define ActRcvPlaTxtSylLec (ActChgCrsSta + 105) +#define ActRcvPlaTxtSylPra (ActChgCrsSta + 106) +#define ActRcvPlaTxtBib (ActChgCrsSta + 107) +#define ActRcvPlaTxtFAQ (ActChgCrsSta + 108) +#define ActRcvPlaTxtCrsLnk (ActChgCrsSta + 109) +#define ActRcvRchTxtCrsInf (ActChgCrsSta + 110) +#define ActRcvRchTxtTchGui (ActChgCrsSta + 111) +#define ActRcvRchTxtSylLec (ActChgCrsSta + 112) +#define ActRcvRchTxtSylPra (ActChgCrsSta + 113) +#define ActRcvRchTxtBib (ActChgCrsSta + 114) +#define ActRcvRchTxtFAQ (ActChgCrsSta + 115) +#define ActRcvRchTxtCrsLnk (ActChgCrsSta + 116) -#define ActPrnCrsTT (ActChgCrsSta + 108) -#define ActEdiCrsTT (ActChgCrsSta + 109) -#define ActChgCrsTT (ActChgCrsSta + 110) -#define ActChgCrsTT1stDay (ActChgCrsSta + 111) +#define ActPrnCrsTT (ActChgCrsSta + 117) +#define ActEdiCrsTT (ActChgCrsSta + 118) +#define ActChgCrsTT (ActChgCrsSta + 119) +#define ActChgCrsTT1stDay (ActChgCrsSta + 120) /*****************************************************************************/ /***************************** Assessment tab ********************************/ diff --git a/swad_changelog.h b/swad_changelog.h index 9bac175b..a357088d 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -520,6 +520,15 @@ Param // TODO: Impedir la creación y edición de proyectos si no son editables. // TODO: No se puede entrar con DNI '1' suponiendo que no tenga password ¿por qué? // TODO: En la lista de conectados central, poner el logo de la institución a la que pertenece el usuario +// TODO: Miguel Damas: por defecto, marcar "Permitir que los profesores..." en los test (que ya esté marcado en lugar de desmarcado) +// TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo +// TODO: Análisis > Informe: "Informe de uso de SWAD" sale descentrado +// TODO: Fig_GetAndShowCourseProgramStats + + Version 19.130: Feb 20, 2020 New module swad_program. (281273 lines) + 2 changes necessary in database: +CREATE TABLE IF NOT EXISTS prg_grp (PrgIteCod INT NOT NULL,GrpCod INT NOT NULL,UNIQUE INDEX(PrgIteCod,GrpCod)); +CREATE TABLE IF NOT EXISTS prg_items (PrgIteCod INT NOT NULL AUTO_INCREMENT,CrsCod INT NOT NULL DEFAULT -1,Hidden ENUM('N','Y') NOT NULL DEFAULT 'N',UsrCod INT NOT NULL,StartTime DATETIME NOT NULL,EndTime DATETIME NOT NULL,Title VARCHAR(2047) NOT NULL,Txt TEXT NOT NULL,UNIQUE INDEX(PrgIteCod),INDEX(CrsCod,Hidden)); Version 19.129: Feb 20, 2020 New option for schedule in course. (279240 lines) Copy the following icons to icon public directory: diff --git a/swad_database.c b/swad_database.c index bd969c03..f443fc39 100644 --- a/swad_database.c +++ b/swad_database.c @@ -2188,6 +2188,51 @@ mysql> DESCRIBE plugins; "IP CHAR(15) NOT NULL," // Cns_MAX_BYTES_IP "UNIQUE INDEX(PlgCod))"); + /***** Table prg_grp *****/ +/* +mysql> DESCRIBE prg_grp; ++-----------+---------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++-----------+---------+------+-----+---------+-------+ +| PrgIteCod | int(11) | NO | PRI | NULL | | +| GrpCod | int(11) | NO | PRI | NULL | | ++-----------+---------+------+-----+---------+-------+ +2 rows in set (0.06 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS prg_grp (" + "PrgIteCod INT NOT NULL," + "GrpCod INT NOT NULL," + "UNIQUE INDEX(PrgIteCod,GrpCod))"); + + /***** Table prg_items *****/ +/* +mysql> DESCRIBE prg_items; ++-----------+---------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++-----------+---------------+------+-----+---------+----------------+ +| PrgIteCod | int(11) | NO | PRI | NULL | auto_increment | +| CrsCod | int(11) | NO | MUL | -1 | | +| Hidden | enum('N','Y') | NO | | N | | +| UsrCod | int(11) | NO | | NULL | | +| StartTime | datetime | NO | | NULL | | +| EndTime | datetime | NO | | NULL | | +| Title | varchar(2047) | NO | | NULL | | +| Txt | text | NO | | NULL | | ++-----------+---------------+------+-----+---------+----------------+ +8 rows in set (0.01 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS prg_items (" + "PrgIteCod INT NOT NULL AUTO_INCREMENT," + "CrsCod INT NOT NULL DEFAULT -1," + "Hidden ENUM('N','Y') NOT NULL DEFAULT 'N'," + "UsrCod INT NOT NULL," + "StartTime DATETIME NOT NULL," + "EndTime DATETIME NOT NULL," + "Title VARCHAR(2047) NOT NULL," // Prg_MAX_BYTES_PROGRAM_ITEM_TITLE + "Txt TEXT NOT NULL," // Cns_MAX_BYTES_TEXT + "UNIQUE INDEX(PrgIteCod)," + "INDEX(CrsCod,Hidden))"); + /***** Table prj_config *****/ /* mysql> DESCRIBE prj_config; diff --git a/swad_figure.c b/swad_figure.c index 3347892a..2527b852 100644 --- a/swad_figure.c +++ b/swad_figure.c @@ -145,6 +145,8 @@ static void Fig_WriteRowStatsFileBrowsers3 (const char *NameOfFileZones, static void Fig_GetAndShowOERsStats (void); static void Fig_GetNumberOfOERsFromDB (Hie_Level_t Scope,Brw_License_t License,unsigned long NumFiles[2]); +static void Fig_GetAndShowCourseProgramStats (void); // TODO: Change function from assignments to schedule + static void Fig_GetAndShowAssignmentsStats (void); static void Fig_GetAndShowProjectsStats (void); static void Fig_GetAndShowTestsStats (void); @@ -315,6 +317,7 @@ void Fig_ShowFigures (void) [Fig_DEGREE_TYPES ] = Fig_GetAndShowDegreeTypesStats, [Fig_FOLDERS_AND_FILES] = Fig_GetAndShowFileBrowsersStats, [Fig_OER ] = Fig_GetAndShowOERsStats, + [Fig_COURSE_PROGRAM ] = Fig_GetAndShowCourseProgramStats, [Fig_ASSIGNMENTS ] = Fig_GetAndShowAssignmentsStats, [Fig_PROJECTS ] = Fig_GetAndShowProjectsStats, [Fig_TESTS ] = Fig_GetAndShowTestsStats, @@ -2936,6 +2939,68 @@ static void Fig_GetNumberOfOERsFromDB (Hie_Level_t Scope,Brw_License_t License,u DB_FreeMySQLResult (&mysql_res); } +/*****************************************************************************/ +/********************** Show stats about schedule items **********************/ +/*****************************************************************************/ + +static void Fig_GetAndShowCourseProgramStats (void) // TODO: Change function from assignments to course program items + { + extern const char *Hlp_ANALYTICS_Figures_assignments; + extern const char *Txt_FIGURE_TYPES[Fig_NUM_FIGURES]; + extern const char *Txt_Number_of_BR_assignments; + extern const char *Txt_Number_of_BR_courses_with_BR_assignments; + extern const char *Txt_Average_number_BR_of_ASSIG_BR_per_course; + extern const char *Txt_Number_of_BR_notifications; + unsigned NumAssignments; + unsigned NumNotif; + unsigned NumCoursesWithAssignments = 0; + double NumAssignmentsPerCourse = 0.0; + + /***** Get the number of assignments from this location *****/ + if ((NumAssignments = Asg_GetNumAssignments (Gbl.Scope.Current,&NumNotif))) + if ((NumCoursesWithAssignments = Asg_GetNumCoursesWithAssignments (Gbl.Scope.Current)) != 0) + NumAssignmentsPerCourse = (double) NumAssignments / + (double) NumCoursesWithAssignments; + + /***** Begin box and table *****/ + Box_BoxTableBegin (NULL,Txt_FIGURE_TYPES[Fig_ASSIGNMENTS],NULL, + Hlp_ANALYTICS_Figures_assignments,Box_NOT_CLOSABLE,2); + + /***** Write table heading *****/ + HTM_TR_Begin (NULL); + + HTM_TH (1,1,"RM",Txt_Number_of_BR_assignments); + HTM_TH (1,1,"RM",Txt_Number_of_BR_courses_with_BR_assignments); + HTM_TH (1,1,"RM",Txt_Average_number_BR_of_ASSIG_BR_per_course); + HTM_TH (1,1,"RM",Txt_Number_of_BR_notifications); + + HTM_TR_End (); + + /***** Write number of assignments *****/ + HTM_TR_Begin (NULL); + + HTM_TD_Begin ("class=\"DAT RM\""); + HTM_Unsigned (NumAssignments); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"DAT RM\""); + HTM_Unsigned (NumCoursesWithAssignments); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"DAT RM\""); + HTM_Double2Decimals (NumAssignmentsPerCourse); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"DAT RM\""); + HTM_Unsigned (NumNotif); + HTM_TD_End (); + + HTM_TR_End (); + + /***** End table and box *****/ + Box_BoxTableEnd (); + } + /*****************************************************************************/ /************************ Show stats about assignments ***********************/ /*****************************************************************************/ diff --git a/swad_figure.h b/swad_figure.h index e6e15325..73aeadd8 100644 --- a/swad_figure.h +++ b/swad_figure.h @@ -31,7 +31,7 @@ /************************** Public types and constants ***********************/ /*****************************************************************************/ -#define Fig_NUM_FIGURES 28 +#define Fig_NUM_FIGURES 29 typedef enum { Fig_USERS, // Number of users @@ -41,6 +41,7 @@ typedef enum Fig_DEGREE_TYPES, // Number of degrees in each type of degree Fig_FOLDERS_AND_FILES, // Number of folders and files Fig_OER, // Number of OERs (Open Educational Resources) + Fig_COURSE_PROGRAM, // Number of program items Fig_ASSIGNMENTS, // Number of assignments Fig_PROJECTS, // Number of projects Fig_TESTS, // Number of test questions diff --git a/swad_global.c b/swad_global.c index b7879a08..0d9488e0 100644 --- a/swad_global.c +++ b/swad_global.c @@ -44,6 +44,7 @@ #include "swad_global.h" #include "swad_icon.h" #include "swad_parameter.h" +#include "swad_program.h" #include "swad_project.h" #include "swad_role.h" #include "swad_setting.h" @@ -296,6 +297,11 @@ void Gbl_InitializeGlobals (void) Gbl.Search.Str[0] = '\0'; Gbl.Search.LogSearch = false; + Gbl.Prg.LstIsRead = false; // List is not read + Gbl.Prg.Num = 0; + Gbl.Prg.LstPrgIteCods = NULL; + Gbl.Prg.SelectedOrder = Prg_ORDER_DEFAULT; + Gbl.Asgs.LstIsRead = false; // List is not read Gbl.Asgs.Num = 0; Gbl.Asgs.LstAsgCods = NULL; diff --git a/swad_global.h b/swad_global.h index 3854864a..362c6801 100644 --- a/swad_global.h +++ b/swad_global.h @@ -540,6 +540,15 @@ struct Globals char TmpDir[NAME_MAX + 1]; } ZIP; } FileBrowser; // Struct used for a file browser + struct + { + bool LstIsRead; // Is the list already read from database, or it needs to be read? + unsigned Num; // Number of schedule items + long *LstPrgIteCods; // List of schedule items codes + Dat_StartEndTime_t SelectedOrder; + long PrgIteCodToEdit; // Used as parameter in contextual links + unsigned CurrentPage; + } Prg; struct { bool LstIsRead; // Is the list already read from database, or it needs to be read? diff --git a/swad_help_URL.c b/swad_help_URL.c index b6f2dbea..ba1f904d 100644 --- a/swad_help_URL.c +++ b/swad_help_URL.c @@ -778,6 +778,69 @@ const char *Hlp_COURSE_Information_edit = "COURSE.Information.en#edit"; #endif +const char *Hlp_COURSE_Program = +#if L==1 + "COURSE.Program.es"; +#elif L==2 + "COURSE.Program.en"; +#elif L==3 + "COURSE.Program.en"; +#elif L==4 + "COURSE.Program.es"; +#elif L==5 + "COURSE.Program.en"; +#elif L==6 + "COURSE.Program.es"; +#elif L==7 + "COURSE.Program.en"; +#elif L==8 + "COURSE.Program.en"; +#elif L==9 + "COURSE.Program.en"; +#endif + +const char *Hlp_COURSE_Program_new_item = +#if L==1 + "COURSE.Program.es#nuevo-item"; +#elif L==2 + "COURSE.Program.en#new-item"; +#elif L==3 + "COURSE.Program.en#new-item"; +#elif L==4 + "COURSE.Program.es#nuevo-item"; +#elif L==5 + "COURSE.Program.en#new-item"; +#elif L==6 + "COURSE.Program.es#nuevo-item"; +#elif L==7 + "COURSE.Program.en#new-item"; +#elif L==8 + "COURSE.Program.en#new-item"; +#elif L==9 + "COURSE.Program.en#new-item"; +#endif + +const char *Hlp_COURSE_Program_edit_item = +#if L==1 + "COURSE.Program.es#editar-item"; +#elif L==2 + "COURSE.Program.en#edit-item"; +#elif L==3 + "COURSE.Program.en#edit-item"; +#elif L==4 + "COURSE.Program.es#editar-item"; +#elif L==5 + "COURSE.Program.en#edit-item"; +#elif L==6 + "COURSE.Program.es#editar-item"; +#elif L==7 + "COURSE.Program.en#edit-item"; +#elif L==8 + "COURSE.Program.en#edit-item"; +#elif L==9 + "COURSE.Program.en#edit-item"; +#endif + const char *Hlp_COURSE_Guide = #if L==1 "COURSE.Guide.es"; diff --git a/swad_menu.c b/swad_menu.c index c66b9510..afb38064 100644 --- a/swad_menu.c +++ b/swad_menu.c @@ -101,7 +101,7 @@ static const Act_Action_t Mnu_MenuActions[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_ }, [TabCrs] = { [ 0] = ActSeeCrsInf, - [ 1] = ActSeeScd, + [ 1] = ActSeePrg, [ 2] = ActSeeTchGui, [ 3] = ActSeeSyl, [ 4] = ActSeeBib, diff --git a/swad_pagination.c b/swad_pagination.c index 45fe8896..b31b68f4 100644 --- a/swad_pagination.c +++ b/swad_pagination.c @@ -37,6 +37,7 @@ #include "swad_global.h" #include "swad_HTML.h" #include "swad_parameter.h" +#include "swad_program.h" #include "swad_project.h" /*****************************************************************************/ @@ -53,6 +54,7 @@ extern const Act_Action_t For_ActionsSeePstFor[For_NUM_TYPES_FORUM]; static const char *Pag_ParamNumPag[Pag_NUM_WHAT_PAGINATE] = { + [Pag_COURSE_PROGRAM ] = "NumPagPrg", [Pag_ASSIGNMENTS ] = "NumPagAsg", [Pag_PROJECTS ] = "NumPagPrj", [Pag_GAMES ] = "NumPagGam", @@ -165,6 +167,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, { switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,1); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,1); @@ -279,6 +287,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, { switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,1); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,1); @@ -379,6 +393,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, { switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->LeftPage); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->LeftPage); @@ -491,6 +511,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, { switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,NumPage); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,NumPage); @@ -590,6 +616,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, } switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->RightPage); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->RightPage); @@ -690,6 +722,12 @@ void Pag_WriteLinksToPages (Pag_WhatPaginate_t WhatPaginate, } switch (WhatPaginate) { + case Pag_COURSE_PROGRAM: + Frm_StartFormAnchor (ActSeePrg,Pagination->Anchor); + Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->NumPags); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + break; case Pag_ASSIGNMENTS: Frm_StartFormAnchor (ActSeeAsg,Pagination->Anchor); Pag_PutHiddenParamPagNum (WhatPaginate,Pagination->NumPags); diff --git a/swad_pagination.h b/swad_pagination.h index 18e99487..a7493d1a 100644 --- a/swad_pagination.h +++ b/swad_pagination.h @@ -37,20 +37,21 @@ /******************************** Public types *******************************/ /*****************************************************************************/ -#define Pag_NUM_WHAT_PAGINATE 11 +#define Pag_NUM_WHAT_PAGINATE 12 typedef enum { - Pag_ASSIGNMENTS = 0, - Pag_PROJECTS = 1, - Pag_GAMES = 2, - Pag_SURVEYS = 3, - Pag_ATT_EVENTS = 4, - Pag_THREADS_FORUM = 5, - Pag_POSTS_FORUM = 6, - Pag_MESSAGES_RECEIVED = 7, - Pag_MESSAGES_SENT = 8, - Pag_MY_AGENDA = 9, - Pag_ANOTHER_AGENDA = 10, + Pag_COURSE_PROGRAM = 0, + Pag_ASSIGNMENTS = 1, + Pag_PROJECTS = 2, + Pag_GAMES = 3, + Pag_SURVEYS = 4, + Pag_ATT_EVENTS = 5, + Pag_THREADS_FORUM = 6, + Pag_POSTS_FORUM = 7, + Pag_MESSAGES_RECEIVED = 8, + Pag_MESSAGES_SENT = 9, + Pag_MY_AGENDA = 10, + Pag_ANOTHER_AGENDA = 11, } Pag_WhatPaginate_t; struct Pagination // Used for threads and messages pagination diff --git a/swad_program.c b/swad_program.c new file mode 100644 index 00000000..2a123a1e --- /dev/null +++ b/swad_program.c @@ -0,0 +1,1701 @@ +// swad_program.c: course program + +/* + 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-2020 Antonio Cañas Vargas + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/*****************************************************************************/ +/********************************* Headers ***********************************/ +/*****************************************************************************/ + +#define _GNU_SOURCE // For asprintf +#include // For PATH_MAX +#include // For NULL +#include // For asprintf +#include // For calloc +#include // For string functions + +#include "swad_box.h" +#include "swad_database.h" +#include "swad_figure.h" +#include "swad_form.h" +#include "swad_global.h" +#include "swad_group.h" +#include "swad_HTML.h" +#include "swad_notification.h" +#include "swad_pagination.h" +#include "swad_parameter.h" +#include "swad_photo.h" +#include "swad_program.h" +#include "swad_role.h" +#include "swad_setting.h" +#include "swad_string.h" + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/***************************** Private constants *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/******************************* Private types *******************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private variables *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ****************************/ +/*****************************************************************************/ + +static void Prg_ShowAllPrgItems (void); +static void Prg_PutHeadForSeeing (bool PrintView); +static bool Prg_CheckIfICanCreatePrgItems (void); +static void Prg_PutIconsListPrgItems (void); +static void Prg_PutIconToCreateNewPrgItem (void); +static void Prg_PutButtonToCreateNewPrgItem (void); +static void Prg_ParamsWhichGroupsToShow (void); +static void Prg_ShowOnePrgItem (long PrgIteCod,bool PrintView); +static void Prg_WritePrgItemAuthor (struct ProgramItem *PrgItem); +static void Prg_GetParamPrgOrder (void); + +static void Prg_PutFormsToRemEditOnePrgItem (const struct ProgramItem *PrgItem, + const char *Anchor); +static void Prg_PutParams (void); +static void Prg_GetDataOfPrgItem (struct ProgramItem *PrgItem, + MYSQL_RES **mysql_res, + unsigned long NumRows); +static void Prg_ResetPrgItem (struct ProgramItem *PrgItem); +static void Prg_GetPrgItemTxtFromDB (long PrgIteCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); +static void Prg_PutParamPrgItemCod (long PrgIteCod); +static bool Prg_CheckIfSimilarPrgItemExists (const char *Field,const char *Value,long PrgIteCod); +static void Prg_ShowLstGrpsToEditPrgItem (long PrgIteCod); +static void Prg_CreatePrgItem (struct ProgramItem *PrgItem,const char *Txt); +static void Prg_UpdatePrgItem (struct ProgramItem *PrgItem,const char *Txt); +static bool Prg_CheckIfPrgItemIsAssociatedToGrps (long PrgIteCod); +static void Prg_RemoveAllTheGrpsAssociatedToAPrgItem (long PrgIteCod); +static void Prg_CreateGrps (long PrgIteCod); +static void Prg_GetAndWriteNamesOfGrpsAssociatedToPrgItem (struct ProgramItem *PrgItem); +static bool Prg_CheckIfIBelongToCrsOrGrpsThisPrgItem (long PrgIteCod); + +/*****************************************************************************/ +/************************ List all the program items *************************/ +/*****************************************************************************/ + +void Prg_SeeCourseProgram (void) + { + /***** Get parameters *****/ + Prg_GetParamPrgOrder (); + Grp_GetParamWhichGrps (); + Gbl.Prg.CurrentPage = Pag_GetParamPagNum (Pag_COURSE_PROGRAM); + + /***** Show all the program items *****/ + Prg_ShowAllPrgItems (); + } + +/*****************************************************************************/ +/*********************** Show all the program items **************************/ +/*****************************************************************************/ + +static void Prg_ShowAllPrgItems (void) + { + extern const char *Hlp_COURSE_Program; + extern const char *Txt_Course_program; + extern const char *Txt_No_items; + struct Pagination Pagination; + unsigned NumAsg; + + /***** Get list of program items *****/ + Prg_GetListPrgItems (); + + /***** Compute variables related to pagination *****/ + Pagination.NumItems = Gbl.Prg.Num; + Pagination.CurrentPage = (int) Gbl.Prg.CurrentPage; + Pag_CalculatePagination (&Pagination); + Gbl.Prg.CurrentPage = (unsigned) Pagination.CurrentPage; + + /***** Begin box *****/ + Box_BoxBegin ("100%",Txt_Course_program,Prg_PutIconsListPrgItems, + Hlp_COURSE_Program,Box_NOT_CLOSABLE); + + /***** Select whether show only my groups or all groups *****/ + if (Gbl.Crs.Grps.NumGrps) + { + Set_StartSettingsHead (); + Grp_ShowFormToSelWhichGrps (ActSeePrg,Prg_ParamsWhichGroupsToShow); + Set_EndSettingsHead (); + } + + /***** Write links to pages *****/ + Pag_WriteLinksToPagesCentered (Pag_COURSE_PROGRAM, + &Pagination, + 0); + + if (Gbl.Prg.Num) + { + /***** Table head *****/ + HTM_TABLE_BeginWideMarginPadding (2); + Prg_PutHeadForSeeing (false); // Not print view + + /***** Write all the program items *****/ + for (NumAsg = Pagination.FirstItemVisible; + NumAsg <= Pagination.LastItemVisible; + NumAsg++) + Prg_ShowOnePrgItem (Gbl.Prg.LstPrgIteCods[NumAsg - 1], + false); // Not print view + + /***** End table *****/ + HTM_TABLE_End (); + } + else // No program items created + Ale_ShowAlert (Ale_INFO,Txt_No_items); + + /***** Write again links to pages *****/ + Pag_WriteLinksToPagesCentered (Pag_COURSE_PROGRAM, + &Pagination, + 0); + + /***** Button to create a new program item *****/ + if (Prg_CheckIfICanCreatePrgItems ()) + Prg_PutButtonToCreateNewPrgItem (); + + /***** End box *****/ + Box_BoxEnd (); + + /***** Free list of program items *****/ + Prg_FreeListPrgItems (); + } + +/*****************************************************************************/ +/***************** Write header with fields of a program item ****************/ +/*****************************************************************************/ + +static void Prg_PutHeadForSeeing (bool PrintView) + { + extern const char *Txt_START_END_TIME_HELP[Dat_NUM_START_END_TIME]; + extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME]; + extern const char *Txt_Item; + Dat_StartEndTime_t Order; + + HTM_TR_Begin (NULL); + + HTM_TH (1,1,"CONTEXT_COL",NULL); // Column for contextual icons + for (Order = Dat_START_TIME; + Order <= Dat_END_TIME; + Order++) + { + HTM_TH_Begin (1,1,"LM"); + + if (!PrintView) + { + Frm_StartForm (ActSeePrg); + Grp_PutParamWhichGrps (); + Pag_PutHiddenParamPagNum (Pag_COURSE_PROGRAM,Gbl.Prg.CurrentPage); + Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Order); + HTM_BUTTON_SUBMIT_Begin (Txt_START_END_TIME_HELP[Order],"BT_LINK TIT_TBL",NULL); + if (Order == Gbl.Prg.SelectedOrder) + HTM_U_Begin (); + } + HTM_Txt (Txt_START_END_TIME[Order]); + if (!PrintView) + { + if (Order == Gbl.Prg.SelectedOrder) + HTM_U_End (); + HTM_BUTTON_End (); + Frm_EndForm (); + } + + HTM_TH_End (); + } + HTM_TH (1,1,"LM",Txt_Item); + + HTM_TR_End (); + } + +/*****************************************************************************/ +/******************* Check if I can create program items *********************/ +/*****************************************************************************/ + +static bool Prg_CheckIfICanCreatePrgItems (void) + { + return (bool) (Gbl.Usrs.Me.Role.Logged == Rol_TCH || + Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM); + } + +/*****************************************************************************/ +/************** Put contextual icons in list of program items ****************/ +/*****************************************************************************/ + +static void Prg_PutIconsListPrgItems (void) + { + /***** Put icon to create a new program item *****/ + if (Prg_CheckIfICanCreatePrgItems ()) + Prg_PutIconToCreateNewPrgItem (); + + /***** Put icon to show a figure *****/ + Gbl.Figures.FigureType = Fig_COURSE_PROGRAM; + Fig_PutIconToShowFigure (); + } + +/*****************************************************************************/ +/****************** Put icon to create a new program item ********************/ +/*****************************************************************************/ + +static void Prg_PutIconToCreateNewPrgItem (void) + { + extern const char *Txt_New_item; + + /***** Put form to create a new program item *****/ + Gbl.Prg.PrgIteCodToEdit = -1L; + Ico_PutContextualIconToAdd (ActFrmNewPrgIte,NULL,Prg_PutParams, + Txt_New_item); + } + +/*****************************************************************************/ +/***************** Put button to create a new program item *******************/ +/*****************************************************************************/ + +static void Prg_PutButtonToCreateNewPrgItem (void) + { + extern const char *Txt_New_item; + + Gbl.Prg.PrgIteCodToEdit = -1L; + Frm_StartForm (ActFrmNewPrgIte); + Prg_PutParams (); + Btn_PutConfirmButton (Txt_New_item); + Frm_EndForm (); + } + +/*****************************************************************************/ +/**************** Put params to select which groups to show ******************/ +/*****************************************************************************/ + +static void Prg_ParamsWhichGroupsToShow (void) + { + Prg_PutHiddenParamPrgOrder (); + Pag_PutHiddenParamPagNum (Pag_COURSE_PROGRAM,Gbl.Prg.CurrentPage); + } + +/*****************************************************************************/ +/******************* Show print view of one program item *********************/ +/*****************************************************************************/ + +void Prg_PrintOnePrgItem (void) + { + long PrgIteCod; + + /***** Get the code of the program item *****/ + PrgIteCod = Prg_GetParamPrgItemCod (); + + /***** Write header *****/ + Lay_WriteHeaderClassPhoto (true,false, + Gbl.Hierarchy.Ins.InsCod, + Gbl.Hierarchy.Deg.DegCod, + Gbl.Hierarchy.Crs.CrsCod); + + /***** Table head *****/ + HTM_TABLE_BeginWideMarginPadding (2); + Prg_PutHeadForSeeing (true); // Print view + + /***** Write program item *****/ + Prg_ShowOnePrgItem (PrgIteCod, + true); // Print view + + /***** End table *****/ + HTM_TABLE_End (); + } + +/*****************************************************************************/ +/************************** Show one program item ****************************/ +/*****************************************************************************/ + +static void Prg_ShowOnePrgItem (long PrgIteCod,bool PrintView) + { + char *Anchor = NULL; + static unsigned UniqueId = 0; + char *Id; + struct ProgramItem PrgItem; + Dat_StartEndTime_t StartEndTime; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Get data of this program item *****/ + PrgItem.PrgIteCod = PrgIteCod; + Prg_GetDataOfPrgItemByCod (&PrgItem); + + /***** Set anchor string *****/ + Frm_SetAnchorStr (PrgItem.PrgIteCod,&Anchor); + + /***** Write first row of data of this program item *****/ + HTM_TR_Begin (NULL); + + /* Forms to remove/edit this program item */ + if (PrintView) + HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL\""); + else + { + HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL COLOR%u\"",Gbl.RowEvenOdd); + Prg_PutFormsToRemEditOnePrgItem (&PrgItem,Anchor); + } + HTM_TD_End (); + + /* Start/end date/time */ + UniqueId++; + + for (StartEndTime = (Dat_StartEndTime_t) 0; + StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); + StartEndTime++) + { + if (asprintf (&Id,"scd_date_%u_%u",(unsigned) StartEndTime,UniqueId) < 0) + Lay_NotEnoughMemoryExit (); + if (PrintView) + HTM_TD_Begin ("id=\"%s\" class=\"%s LB\"", + Id, + PrgItem.Hidden ? (PrgItem.Open ? "DATE_GREEN_LIGHT" : + "DATE_RED_LIGHT") : + (PrgItem.Open ? "DATE_GREEN" : + "DATE_RED")); + else + HTM_TD_Begin ("id=\"%s\" class=\"%s LB COLOR%u\"", + Id, + PrgItem.Hidden ? (PrgItem.Open ? "DATE_GREEN_LIGHT" : + "DATE_RED_LIGHT") : + (PrgItem.Open ? "DATE_GREEN" : + "DATE_RED"), + Gbl.RowEvenOdd); + Dat_WriteLocalDateHMSFromUTC (Id,PrgItem.TimeUTC[StartEndTime], + Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, + true,true,true,0x7); + HTM_TD_End (); + free (Id); + } + + /* Schedule item title */ + if (PrintView) + HTM_TD_Begin ("class=\"%s LT\"", + PrgItem.Hidden ? "ASG_TITLE_LIGHT" : + "ASG_TITLE"); + else + HTM_TD_Begin ("class=\"%s LT COLOR%u\"", + PrgItem.Hidden ? "ASG_TITLE_LIGHT" : + "ASG_TITLE", + Gbl.RowEvenOdd); + HTM_ARTICLE_Begin (Anchor); + HTM_Txt (PrgItem.Title); + HTM_ARTICLE_End (); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Write second row of data of this program item *****/ + HTM_TR_Begin (NULL); + + /* Author of the program item */ + if (PrintView) + HTM_TD_Begin ("colspan=\"2\" class=\"LT\""); + else + HTM_TD_Begin ("colspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + Prg_WritePrgItemAuthor (&PrgItem); + HTM_TD_End (); + + /* Text of the program item */ + Prg_GetPrgItemTxtFromDB (PrgItem.PrgIteCod,Txt); + Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, + Txt,Cns_MAX_BYTES_TEXT,false); // Convert from HTML to recpectful HTML + Str_InsertLinks (Txt,Cns_MAX_BYTES_TEXT,60); // Insert links + if (PrintView) + HTM_TD_Begin ("colspan=\"2\" class=\"LT\""); + else + HTM_TD_Begin ("colspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + if (Gbl.Crs.Grps.NumGrps) + Prg_GetAndWriteNamesOfGrpsAssociatedToPrgItem (&PrgItem); + HTM_DIV_Begin ("class=\"PAR %s\"",PrgItem.Hidden ? "DAT_LIGHT" : + "DAT"); + HTM_Txt (Txt); + HTM_DIV_End (); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Free anchor string *****/ + Frm_FreeAnchorStr (Anchor); + + Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; + + /***** Mark possible notification as seen *****/ + Ntf_MarkNotifAsSeen (Ntf_EVENT_ASSIGNMENT, + PrgIteCod,Gbl.Hierarchy.Crs.CrsCod, + Gbl.Usrs.Me.UsrDat.UsrCod); + } + +/*****************************************************************************/ +/********************* Write the author of a program item ********************/ +/*****************************************************************************/ + +static void Prg_WritePrgItemAuthor (struct ProgramItem *PrgItem) + { + Usr_WriteAuthor1Line (PrgItem->UsrCod,PrgItem->Hidden); + } + +/*****************************************************************************/ +/******* Get parameter with the type or order in list of program items *******/ +/*****************************************************************************/ + +static void Prg_GetParamPrgOrder (void) + { + Gbl.Prg.SelectedOrder = (Dat_StartEndTime_t) + Par_GetParToUnsignedLong ("Order", + 0, + Dat_NUM_START_END_TIME - 1, + (unsigned long) Prg_ORDER_DEFAULT); + } + +/*****************************************************************************/ +/** Put a hidden parameter with the type of order in list of program items ***/ +/*****************************************************************************/ + +void Prg_PutHiddenParamPrgOrder (void) + { + Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Gbl.Prg.SelectedOrder); + } + +/*****************************************************************************/ +/**************** Put a link (form) to edit one program item *****************/ +/*****************************************************************************/ + +static void Prg_PutFormsToRemEditOnePrgItem (const struct ProgramItem *PrgItem, + const char *Anchor) + { + Gbl.Prg.PrgIteCodToEdit = PrgItem->PrgIteCod; // Used as parameter in contextual links + + switch (Gbl.Usrs.Me.Role.Logged) + { + case Rol_TCH: + case Rol_SYS_ADM: + /***** Put form to remove program item *****/ + Ico_PutContextualIconToRemove (ActReqRemAsg,Prg_PutParams); + + /***** Put form to hide/show program item *****/ + if (PrgItem->Hidden) + Ico_PutContextualIconToUnhide (ActShoAsg,Anchor,Prg_PutParams); + else + Ico_PutContextualIconToHide (ActHidAsg,Anchor,Prg_PutParams); + + /***** Put form to edit program item *****/ + Ico_PutContextualIconToEdit (ActEdiOneAsg,Prg_PutParams); + /* falls through */ + /* no break */ + case Rol_STD: + case Rol_NET: + /***** Put form to print program item *****/ + Ico_PutContextualIconToPrint (ActPrnOneAsg,Prg_PutParams); + break; + default: + break; + } + } + +/*****************************************************************************/ +/******************** Params used to edit a program item *********************/ +/*****************************************************************************/ + +static void Prg_PutParams (void) + { + if (Gbl.Prg.PrgIteCodToEdit > 0) + Prg_PutParamPrgItemCod (Gbl.Prg.PrgIteCodToEdit); + Prg_PutHiddenParamPrgOrder (); + Grp_PutParamWhichGrps (); + Pag_PutHiddenParamPagNum (Pag_COURSE_PROGRAM,Gbl.Prg.CurrentPage); + } + +/*****************************************************************************/ +/*********************** List all the program items **************************/ +/*****************************************************************************/ + +void Prg_GetListPrgItems (void) + { + static const char *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 *OrderBySubQuery[Dat_NUM_START_END_TIME] = + { + [Dat_START_TIME] = "StartTime DESC,EndTime DESC,Title DESC", + [Dat_END_TIME ] = "EndTime DESC,StartTime DESC,Title DESC", + }; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned long NumRows; + unsigned NumAsg; + + if (Gbl.Prg.LstIsRead) + Prg_FreeListPrgItems (); + + /***** Get list of program items from database *****/ + if (Gbl.Crs.Grps.WhichGrps == Grp_MY_GROUPS) + NumRows = DB_QuerySELECT (&mysql_res,"can not get program items", + "SELECT PrgIteCod" + " FROM prg_items" + " WHERE CrsCod=%ld%s" + " AND (PrgIteCod NOT IN (SELECT PrgIteCod FROM prg_grp) OR" + " PrgIteCod IN (SELECT prg_grp.PrgIteCod FROM prg_grp,crs_grp_usr" + " WHERE crs_grp_usr.UsrCod=%ld AND prg_grp.GrpCod=crs_grp_usr.GrpCod))" + " ORDER BY %s", + Gbl.Hierarchy.Crs.CrsCod, + HiddenSubQuery[Gbl.Usrs.Me.Role.Logged], + Gbl.Usrs.Me.UsrDat.UsrCod, + OrderBySubQuery[Gbl.Prg.SelectedOrder]); + else // Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS + NumRows = DB_QuerySELECT (&mysql_res,"can not get program items", + "SELECT PrgIteCod" + " FROM prg_items" + " WHERE CrsCod=%ld%s" + " ORDER BY %s", + Gbl.Hierarchy.Crs.CrsCod, + HiddenSubQuery[Gbl.Usrs.Me.Role.Logged], + OrderBySubQuery[Gbl.Prg.SelectedOrder]); + + if (NumRows) // Assignments found... + { + Gbl.Prg.Num = (unsigned) NumRows; + + /***** Create list of program items *****/ + if ((Gbl.Prg.LstPrgIteCods = (long *) calloc (NumRows,sizeof (long))) == NULL) + Lay_NotEnoughMemoryExit (); + + /***** Get the program items codes *****/ + for (NumAsg = 0; + NumAsg < Gbl.Prg.Num; + NumAsg++) + { + /* Get next program item code */ + row = mysql_fetch_row (mysql_res); + if ((Gbl.Prg.LstPrgIteCods[NumAsg] = Str_ConvertStrCodToLongCod (row[0])) < 0) + Lay_ShowErrorAndExit ("Error: wrong program item code."); + } + } + else + Gbl.Prg.Num = 0; + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + Gbl.Prg.LstIsRead = true; + } + +/*****************************************************************************/ +/****************** Get program item data using its code *********************/ +/*****************************************************************************/ + +void Prg_GetDataOfPrgItemByCod (struct ProgramItem *PrgItem) + { + MYSQL_RES *mysql_res; + unsigned long NumRows; + + if (PrgItem->PrgIteCod > 0) + { + /***** Build query *****/ + NumRows = DB_QuerySELECT (&mysql_res,"can not get program item data", + "SELECT PrgIteCod,Hidden,UsrCod," + "UNIX_TIMESTAMP(StartTime)," + "UNIX_TIMESTAMP(EndTime)," + "NOW() BETWEEN StartTime AND EndTime," + "Title" + " FROM prg_items" + " WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgItem->PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** Get data of program item *****/ + Prg_GetDataOfPrgItem (PrgItem,&mysql_res,NumRows); + } + else + { + /***** Clear all program item data *****/ + PrgItem->PrgIteCod = -1L; + Prg_ResetPrgItem (PrgItem); + } + } + +/*****************************************************************************/ +/************************* Get program item data *****************************/ +/*****************************************************************************/ + +static void Prg_GetDataOfPrgItem (struct ProgramItem *PrgItem, + MYSQL_RES **mysql_res, + unsigned long NumRows) + { + MYSQL_ROW row; + + /***** Clear all program item data *****/ + Prg_ResetPrgItem (PrgItem); + + /***** Get data of program item from database *****/ + if (NumRows) // Schedule item found... + { + /* Get row */ + row = mysql_fetch_row (*mysql_res); + + /* Get code of the program item (row[0]) */ + PrgItem->PrgIteCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get whether the program item is hidden or not (row[1]) */ + PrgItem->Hidden = (row[1][0] == 'Y'); + + /* Get author of the program item (row[2]) */ + PrgItem->UsrCod = Str_ConvertStrCodToLongCod (row[2]); + + /* Get start date (row[3] holds the start UTC time) */ + PrgItem->TimeUTC[Dat_START_TIME] = Dat_GetUNIXTimeFromStr (row[3]); + + /* Get end date (row[4] holds the end UTC time) */ + PrgItem->TimeUTC[Dat_END_TIME ] = Dat_GetUNIXTimeFromStr (row[4]); + + /* Get whether the program item is open or closed (row(5)) */ + PrgItem->Open = (row[5][0] == '1'); + + /* Get the title of the program item (row[6]) */ + Str_Copy (PrgItem->Title,row[6], + Prg_MAX_BYTES_PROGRAM_ITEM_TITLE); + + /* Can I do this program item? */ + PrgItem->IBelongToCrsOrGrps = Prg_CheckIfIBelongToCrsOrGrpsThisPrgItem (PrgItem->PrgIteCod); + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (mysql_res); + } + +/*****************************************************************************/ +/************************ Clear all program item data ************************/ +/*****************************************************************************/ + +static void Prg_ResetPrgItem (struct ProgramItem *PrgItem) + { + if (PrgItem->PrgIteCod <= 0) // If > 0 ==> keep value + PrgItem->PrgIteCod = -1L; + PrgItem->PrgIteCod = -1L; + PrgItem->Hidden = false; + PrgItem->UsrCod = -1L; + PrgItem->TimeUTC[Dat_START_TIME] = + PrgItem->TimeUTC[Dat_END_TIME ] = (time_t) 0; + PrgItem->Open = false; + PrgItem->Title[0] = '\0'; + PrgItem->IBelongToCrsOrGrps = false; + } + +/*****************************************************************************/ +/************************ Free list of program items *************************/ +/*****************************************************************************/ + +void Prg_FreeListPrgItems (void) + { + if (Gbl.Prg.LstIsRead && Gbl.Prg.LstPrgIteCods) + { + /***** Free memory used by the list of program items *****/ + free (Gbl.Prg.LstPrgIteCods); + Gbl.Prg.LstPrgIteCods = NULL; + Gbl.Prg.Num = 0; + Gbl.Prg.LstIsRead = false; + } + } + +/*****************************************************************************/ +/******************* Get program item text from database *********************/ +/*****************************************************************************/ + +static void Prg_GetPrgItemTxtFromDB (long PrgIteCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned long NumRows; + + /***** Get text of program item from database *****/ + NumRows = DB_QuerySELECT (&mysql_res,"can not get program item text", + "SELECT Txt FROM prg_items" + " WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** The result of the query must have one row or none *****/ + if (NumRows == 1) + { + /* Get info text */ + row = mysql_fetch_row (mysql_res); + Str_Copy (Txt,row[0], + Cns_MAX_BYTES_TEXT); + } + else + Txt[0] = '\0'; + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + if (NumRows > 1) + Lay_ShowErrorAndExit ("Error when getting program item text."); + } + +/*****************************************************************************/ +/***************** Get summary and content of a program item ****************/ +/*****************************************************************************/ +// This function may be called inside a web service + +void Prg_GetNotifPrgItem (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], + char **ContentStr, + long PrgIteCod,bool GetContent) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned long NumRows; + size_t Length; + + SummaryStr[0] = '\0'; // Return nothing on error + + /***** Build query *****/ + NumRows = DB_QuerySELECT (&mysql_res,"can not get program item title and text", + "SELECT Title,Txt FROM prg_items" + " WHERE PrgIteCod=%ld", + PrgIteCod); + + /***** Result should have a unique row *****/ + if (NumRows == 1) + { + /***** Get row *****/ + row = mysql_fetch_row (mysql_res); + + /***** Get summary *****/ + Str_Copy (SummaryStr,row[0], + Ntf_MAX_BYTES_SUMMARY); + + /***** Get content *****/ + if (GetContent) + { + Length = strlen (row[1]); + if ((*ContentStr = (char *) malloc (Length + 1)) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory for notification content."); + Str_Copy (*ContentStr,row[1], + Length); + } + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + } + +/*****************************************************************************/ +/**************** Write parameter with code of program item ******************/ +/*****************************************************************************/ + +static void Prg_PutParamPrgItemCod (long PrgIteCod) + { + Par_PutHiddenParamLong (NULL,"PrgIteCod",PrgIteCod); + } + +/*****************************************************************************/ +/***************** Get parameter with code of program item *******************/ +/*****************************************************************************/ + +long Prg_GetParamPrgItemCod (void) + { + /***** Get code of program item *****/ + return Par_GetParToLong ("PrgIteCod"); + } + +/*****************************************************************************/ +/************* Ask for confirmation of removing a program item ***************/ +/*****************************************************************************/ + +void Prg_ReqRemPrgItem (void) + { + extern const char *Txt_Do_you_really_want_to_remove_the_item_X; + extern const char *Txt_Remove_item; + struct ProgramItem PrgItem; + + /***** Get parameters *****/ + Prg_GetParamPrgOrder (); + Grp_GetParamWhichGrps (); + Gbl.Prg.CurrentPage = Pag_GetParamPagNum (Pag_COURSE_PROGRAM); + + /***** Get program item code *****/ + if ((PrgItem.PrgIteCod = Prg_GetParamPrgItemCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of program item is missing."); + + /***** Get data of the program item from database *****/ + Prg_GetDataOfPrgItemByCod (&PrgItem); + + /***** Show question and button to remove the program item *****/ + Gbl.Prg.PrgIteCodToEdit = PrgItem.PrgIteCod; + Ale_ShowAlertAndButton (ActRemAsg,NULL,NULL,Prg_PutParams, + Btn_REMOVE_BUTTON,Txt_Remove_item, + Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_item_X, + PrgItem.Title); + + /***** Show program items again *****/ + Prg_SeeCourseProgram (); + } + +/*****************************************************************************/ +/*************************** Remove a program item ***************************/ +/*****************************************************************************/ + +void Prg_RemovePrgItem (void) + { + extern const char *Txt_Assignment_X_removed; + struct ProgramItem PrgItem; + + /***** Get program item code *****/ + if ((PrgItem.PrgIteCod = Prg_GetParamPrgItemCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of program item is missing."); + + /***** Get data of the program item from database *****/ + Prg_GetDataOfPrgItemByCod (&PrgItem); // Inside this function, the course is checked to be the current one + + /***** Remove all the groups of this program item *****/ + Prg_RemoveAllTheGrpsAssociatedToAPrgItem (PrgItem.PrgIteCod); + + /***** Remove program item *****/ + DB_QueryDELETE ("can not remove program item", + "DELETE FROM prg_items WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgItem.PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** Mark possible notifications as removed *****/ + Ntf_MarkNotifAsRemoved (Ntf_EVENT_ASSIGNMENT,PrgItem.PrgIteCod); + + /***** Write message to show the change made *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Assignment_X_removed, + PrgItem.Title); + + /***** Show program items again *****/ + Prg_SeeCourseProgram (); + } + +/*****************************************************************************/ +/***************************** Hide a program item ***************************/ +/*****************************************************************************/ + +void Prg_HidePrgItem (void) + { + struct ProgramItem PrgItem; + + /***** Get program item code *****/ + if ((PrgItem.PrgIteCod = Prg_GetParamPrgItemCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of program item is missing."); + + /***** Get data of the program item from database *****/ + Prg_GetDataOfPrgItemByCod (&PrgItem); + + /***** Hide program item *****/ + DB_QueryUPDATE ("can not hide program item", + "UPDATE prg_items SET Hidden='Y'" + " WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgItem.PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** Show program items again *****/ + Prg_SeeCourseProgram (); + } + +/*****************************************************************************/ +/***************************** Show a program item ***************************/ +/*****************************************************************************/ + +void Prg_ShowPrgItem (void) + { + struct ProgramItem PrgItem; + + /***** Get program item code *****/ + if ((PrgItem.PrgIteCod = Prg_GetParamPrgItemCod ()) == -1L) + Lay_ShowErrorAndExit ("Code of program item is missing."); + + /***** Get data of the program item from database *****/ + Prg_GetDataOfPrgItemByCod (&PrgItem); + + /***** Hide program item *****/ + DB_QueryUPDATE ("can not show program item", + "UPDATE prg_items SET Hidden='N'" + " WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgItem.PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** Show program items again *****/ + Prg_SeeCourseProgram (); + } + +/*****************************************************************************/ +/*************** Check if the title of a program item exists *****************/ +/*****************************************************************************/ + +static bool Prg_CheckIfSimilarPrgItemExists (const char *Field,const char *Value,long PrgIteCod) + { + /***** Get number of program items with a field value from database *****/ + return (DB_QueryCOUNT ("can not get similar program items", + "SELECT COUNT(*) FROM prg_items" + " WHERE CrsCod=%ld" + " AND %s='%s' AND PrgIteCod<>%ld", + Gbl.Hierarchy.Crs.CrsCod, + Field,Value,PrgIteCod) != 0); + } + +/*****************************************************************************/ +/***************** Put a form to create a new program item *******************/ +/*****************************************************************************/ + +void Prg_RequestCreatOrEditPrgItem (void) + { + extern const char *Hlp_COURSE_Program_new_item; + extern const char *Hlp_COURSE_Program_edit_item; + extern const char *Txt_New_item; + extern const char *Txt_Edit_item; + extern const char *Txt_Title; + extern const char *Txt_Description; + extern const char *Txt_Create_item; + extern const char *Txt_Save_changes; + struct ProgramItem PrgItem; + bool ItsANewPrgItem; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Get parameters *****/ + Prg_GetParamPrgOrder (); + Grp_GetParamWhichGrps (); + Gbl.Prg.CurrentPage = Pag_GetParamPagNum (Pag_COURSE_PROGRAM); + + /***** Get the code of the program item *****/ + ItsANewPrgItem = ((PrgItem.PrgIteCod = Prg_GetParamPrgItemCod ()) == -1L); + + /***** Get from the database the data of the program item *****/ + if (ItsANewPrgItem) + { + /* Initialize to empty program item */ + PrgItem.PrgIteCod = -1L; + PrgItem.TimeUTC[Dat_START_TIME] = Gbl.StartExecutionTimeUTC; + PrgItem.TimeUTC[Dat_END_TIME ] = Gbl.StartExecutionTimeUTC + (2 * 60 * 60); // +2 hours + PrgItem.Open = true; + PrgItem.Title[0] = '\0'; + PrgItem.IBelongToCrsOrGrps = false; + } + else + { + /* Get data of the program item from database */ + Prg_GetDataOfPrgItemByCod (&PrgItem); + + /* Get text of the program item from database */ + Prg_GetPrgItemTxtFromDB (PrgItem.PrgIteCod,Txt); + } + + /***** Begin form *****/ + if (ItsANewPrgItem) + { + Frm_StartForm (ActNewPrgIte); + Gbl.Prg.PrgIteCodToEdit = -1L; + } + else + { + Frm_StartForm (ActChgPrgIte); + Gbl.Prg.PrgIteCodToEdit = PrgItem.PrgIteCod; + } + Prg_PutParams (); + + /***** Begin box and table *****/ + if (ItsANewPrgItem) + Box_BoxTableBegin (NULL,Txt_New_item,NULL, + Hlp_COURSE_Program_new_item,Box_NOT_CLOSABLE,2); + else + Box_BoxTableBegin (NULL, + PrgItem.Title[0] ? PrgItem.Title : + Txt_Edit_item, + NULL, + Hlp_COURSE_Program_edit_item,Box_NOT_CLOSABLE,2); + + + /***** Schedule item title *****/ + HTM_TR_Begin (NULL); + + /* Label */ + Frm_LabelColumn ("RM","Title",Txt_Title); + + /* Data */ + HTM_TD_Begin ("class=\"LM\""); + HTM_INPUT_TEXT ("Title",Prg_MAX_CHARS_PROGRAM_ITEM_TITLE,PrgItem.Title,false, + "id=\"Title\" required=\"required\"" + " class=\"TITLE_DESCRIPTION_WIDTH\""); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Schedule item start and end dates *****/ + Dat_PutFormStartEndClientLocalDateTimes (PrgItem.TimeUTC,Dat_FORM_SECONDS_ON); + + /***** Schedule item text *****/ + HTM_TR_Begin (NULL); + + /* Label */ + Frm_LabelColumn ("RT","Txt",Txt_Description); + + /* Data */ + HTM_TD_Begin ("class=\"LT\""); + HTM_TEXTAREA_Begin ("id=\"Txt\" name=\"Txt\" rows=\"10\"" + " class=\"TITLE_DESCRIPTION_WIDTH\""); + if (!ItsANewPrgItem) + HTM_Txt (Txt); + HTM_TEXTAREA_End (); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Groups *****/ + Prg_ShowLstGrpsToEditPrgItem (PrgItem.PrgIteCod); + + /***** End table, send button and end box *****/ + if (ItsANewPrgItem) + Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_item); + else + Box_BoxTableWithButtonEnd (Btn_CONFIRM_BUTTON,Txt_Save_changes); + + /***** End form *****/ + Frm_EndForm (); + + /***** Show current program items, if any *****/ + Prg_ShowAllPrgItems (); + } + +/*****************************************************************************/ +/*************** Show list of groups to edit and program item ****************/ +/*****************************************************************************/ + +static void Prg_ShowLstGrpsToEditPrgItem (long PrgIteCod) + { + extern const char *Hlp_USERS_Groups; + extern const char *The_ClassFormInBox[The_NUM_THEMES]; + 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.Crs.Grps.GrpTypes.Num) + { + /***** Begin box and table *****/ + HTM_TR_Begin (NULL); + + HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]); + HTM_TxtF ("%s:",Txt_Groups); + HTM_TD_End (); + + HTM_TD_Begin ("class=\"LT\""); + Box_BoxTableBegin ("100%",NULL,NULL, + Hlp_USERS_Groups,Box_NOT_CLOSABLE,0); + + /***** First row: checkbox to select the whole course *****/ + HTM_TR_Begin (NULL); + + HTM_TD_Begin ("colspan=\"7\" class=\"DAT LM\""); + HTM_LABEL_Begin (NULL); + HTM_INPUT_CHECKBOX ("WholeCrs",false, + "id=\"WholeCrs\" value=\"Y\"%s" + " onclick=\"uncheckChildren(this,'GrpCods')\"", + Prg_CheckIfPrgItemIsAssociatedToGrps (PrgIteCod) ? "" : + " checked=\"checked\""); + HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName); + HTM_LABEL_End (); + HTM_TD_End (); + + HTM_TR_End (); + + /***** List the groups for each group type *****/ + for (NumGrpTyp = 0; + NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num; + NumGrpTyp++) + if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps) + Grp_ListGrpsToEditAsgAttSvyMch (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp], + PrgIteCod,Grp_ASSIGNMENT); + + /***** End table and box *****/ + Box_BoxTableEnd (); + HTM_TD_End (); + + HTM_TR_End (); + } + + /***** Free list of groups types and groups in this course *****/ + Grp_FreeListGrpTypesAndGrps (); + } + +/*****************************************************************************/ +/***************** Receive form to create a new program item *****************/ +/*****************************************************************************/ + +void Prg_RecFormPrgItem (void) + { + extern const char *Txt_Already_existed_an_item_with_the_title_X; + extern const char *Txt_You_must_specify_the_title_of_the_item; + extern const char *Txt_Created_new_item_X; + extern const char *Txt_The_item_has_been_modified; + struct ProgramItem OldPrgItem; // Current program item data in database + struct ProgramItem NewPrgItem; // Schedule item data received from form + bool ItsANewPrgItem; + bool NewPrgItemIsCorrect = true; + char Description[Cns_MAX_BYTES_TEXT + 1]; + + /***** Get the code of the program item *****/ + NewPrgItem.PrgIteCod = Prg_GetParamPrgItemCod (); + ItsANewPrgItem = (NewPrgItem.PrgIteCod < 0); + + if (ItsANewPrgItem) + { + /***** Reset old (current, not existing) program item data *****/ + OldPrgItem.PrgIteCod = -1L; + Prg_ResetPrgItem (&OldPrgItem); + } + else + { + /***** Get data of the old (current) program item from database *****/ + OldPrgItem.PrgIteCod = NewPrgItem.PrgIteCod; + Prg_GetDataOfPrgItemByCod (&OldPrgItem); + } + + /***** Get start/end date-times *****/ + NewPrgItem.TimeUTC[Dat_START_TIME] = Dat_GetTimeUTCFromForm ("StartTimeUTC"); + NewPrgItem.TimeUTC[Dat_END_TIME ] = Dat_GetTimeUTCFromForm ("EndTimeUTC" ); + + /***** Get program item title *****/ + Par_GetParToText ("Title",NewPrgItem.Title,Prg_MAX_BYTES_PROGRAM_ITEM_TITLE); + + /***** Get program item text *****/ + Par_GetParToHTML ("Txt",Description,Cns_MAX_BYTES_TEXT); // Store in HTML format (not rigorous) + + /***** Adjust dates *****/ + if (NewPrgItem.TimeUTC[Dat_START_TIME] == 0) + NewPrgItem.TimeUTC[Dat_START_TIME] = Gbl.StartExecutionTimeUTC; + if (NewPrgItem.TimeUTC[Dat_END_TIME] == 0) + NewPrgItem.TimeUTC[Dat_END_TIME] = NewPrgItem.TimeUTC[Dat_START_TIME] + 2 * 60 * 60; // +2 hours + + /***** Check if title is correct *****/ + if (NewPrgItem.Title[0]) // If there's a program item title + { + /* If title of program item was in database... */ + if (Prg_CheckIfSimilarPrgItemExists ("Title",NewPrgItem.Title,NewPrgItem.PrgIteCod)) + { + NewPrgItemIsCorrect = false; + + Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_an_item_with_the_title_X, + NewPrgItem.Title); + } + } + else // If there is not a program item title + { + NewPrgItemIsCorrect = false; + Ale_ShowAlert (Ale_WARNING,Txt_You_must_specify_the_title_of_the_item); + } + + /***** Create a new program item or update an existing one *****/ + if (NewPrgItemIsCorrect) + { + /* Get groups for this program items */ + Grp_GetParCodsSeveralGrps (); + + if (ItsANewPrgItem) + { + Prg_CreatePrgItem (&NewPrgItem,Description); // Add new program item to database + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_item_X, + NewPrgItem.Title); + } + else + { + Prg_UpdatePrgItem (&NewPrgItem,Description); + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_The_item_has_been_modified); + } + + /* Free memory for list of selected groups */ + Grp_FreeListCodSelectedGrps (); + + /***** Show program items again *****/ + Prg_SeeCourseProgram (); + } + else + // TODO: The form should be filled with partial data, now is always empty + Prg_RequestCreatOrEditPrgItem (); + } + +/*****************************************************************************/ +/************************ Create a new program item **************************/ +/*****************************************************************************/ + +static void Prg_CreatePrgItem (struct ProgramItem *PrgItem,const char *Txt) + { + /***** Create a new program item *****/ + PrgItem->PrgIteCod = + DB_QueryINSERTandReturnCode ("can not create new program item", + "INSERT INTO prg_items" + " (CrsCod,UsrCod,StartTime,EndTime,Title,Txt)" + " VALUES" + " (%ld,%ld,FROM_UNIXTIME(%ld),FROM_UNIXTIME(%ld)," + "'%s','%s')", + Gbl.Hierarchy.Crs.CrsCod, + Gbl.Usrs.Me.UsrDat.UsrCod, + PrgItem->TimeUTC[Dat_START_TIME], + PrgItem->TimeUTC[Dat_END_TIME ], + PrgItem->Title, + Txt); + + /***** Create groups *****/ + if (Gbl.Crs.Grps.LstGrpsSel.NumGrps) + Prg_CreateGrps (PrgItem->PrgIteCod); + } + +/*****************************************************************************/ +/******************** Update an existing program item ************************/ +/*****************************************************************************/ + +static void Prg_UpdatePrgItem (struct ProgramItem *PrgItem,const char *Txt) + { + /***** Update the data of the program item *****/ + DB_QueryUPDATE ("can not update program item", + "UPDATE prg_items SET " + "StartTime=FROM_UNIXTIME(%ld)," + "EndTime=FROM_UNIXTIME(%ld)," + "Title='%s',Txt='%s'" + " WHERE PrgIteCod=%ld AND CrsCod=%ld", + PrgItem->TimeUTC[Dat_START_TIME], + PrgItem->TimeUTC[Dat_END_TIME ], + PrgItem->Title, + Txt, + PrgItem->PrgIteCod,Gbl.Hierarchy.Crs.CrsCod); + + /***** Update groups *****/ + /* Remove old groups */ + Prg_RemoveAllTheGrpsAssociatedToAPrgItem (PrgItem->PrgIteCod); + + /* Create new groups */ + if (Gbl.Crs.Grps.LstGrpsSel.NumGrps) + Prg_CreateGrps (PrgItem->PrgIteCod); + } + +/*****************************************************************************/ +/*********** Check if a program item is associated to any group **************/ +/*****************************************************************************/ + +static bool Prg_CheckIfPrgItemIsAssociatedToGrps (long PrgIteCod) + { + /***** Get if a program item is associated to a group from database *****/ + return (DB_QueryCOUNT ("can not check if a program item" + " is associated to groups", + "SELECT COUNT(*) FROM prg_grp WHERE PrgIteCod=%ld", + PrgIteCod) != 0); + } + +/*****************************************************************************/ +/************ Check if a program item is associated to a group ***************/ +/*****************************************************************************/ + +bool Prg_CheckIfPrgItemIsAssociatedToGrp (long PrgIteCod,long GrpCod) + { + /***** Get if a program item is associated to a group from database *****/ + return (DB_QueryCOUNT ("can not check if a program item" + " is associated to a group", + "SELECT COUNT(*) FROM prg_grp" + " WHERE PrgIteCod=%ld AND GrpCod=%ld", + PrgIteCod,GrpCod) != 0); + } + +/*****************************************************************************/ +/********************* Remove groups of a program item ***********************/ +/*****************************************************************************/ + +static void Prg_RemoveAllTheGrpsAssociatedToAPrgItem (long PrgIteCod) + { + /***** Remove groups of the program item *****/ + DB_QueryDELETE ("can not remove the groups associated to a program item", + "DELETE FROM prg_grp WHERE PrgIteCod=%ld", + PrgIteCod); + } + +/*****************************************************************************/ +/*************** Remove one group from all the program items *****************/ +/*****************************************************************************/ + +void Prg_RemoveGroup (long GrpCod) + { + /***** Remove group from all the program items *****/ + DB_QueryDELETE ("can not remove group from the associations" + " between program items and groups", + "DELETE FROM prg_grp WHERE GrpCod=%ld", + GrpCod); + } + +/*****************************************************************************/ +/********** Remove groups of one type from all the program items *************/ +/*****************************************************************************/ + +void Prg_RemoveGroupsOfType (long GrpTypCod) + { + /***** Remove group from all the program items *****/ + DB_QueryDELETE ("can not remove groups of a type from the associations" + " between program items and groups", + "DELETE FROM prg_grp USING crs_grp,prg_grp" + " WHERE crs_grp.GrpTypCod=%ld" + " AND crs_grp.GrpCod=prg_grp.GrpCod", + GrpTypCod); + } + +/*****************************************************************************/ +/********************* Create groups of a program item ***********************/ +/*****************************************************************************/ + +static void Prg_CreateGrps (long PrgIteCod) + { + unsigned NumGrpSel; + + /***** Create groups of the program item *****/ + for (NumGrpSel = 0; + NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps; + NumGrpSel++) + /* Create group */ + DB_QueryINSERT ("can not associate a group to a program item", + "INSERT INTO prg_grp" + " (PrgIteCod,GrpCod)" + " VALUES" + " (%ld,%ld)", + PrgIteCod, + Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]); + } + +/*****************************************************************************/ +/********* Get and write the names of the groups of a program item ***********/ +/*****************************************************************************/ + +static void Prg_GetAndWriteNamesOfGrpsAssociatedToPrgItem (struct ProgramItem *PrgItem) + { + extern const char *Txt_Group; + extern const char *Txt_Groups; + extern const char *Txt_and; + extern const char *Txt_The_whole_course; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned long NumRow; + unsigned long NumRows; + + /***** Get groups associated to a program item from database *****/ + NumRows = DB_QuerySELECT (&mysql_res,"can not get groups of a program item", + "SELECT crs_grp_types.GrpTypName,crs_grp.GrpName" + " FROM prg_grp,crs_grp,crs_grp_types" + " WHERE prg_grp.PrgIteCod=%ld" + " AND prg_grp.GrpCod=crs_grp.GrpCod" + " AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod" + " ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName", + PrgItem->PrgIteCod); + + /***** Write heading *****/ + HTM_DIV_Begin ("class=\"%s\"",PrgItem->Hidden ? "ASG_GRP_LIGHT" : + "ASG_GRP"); + HTM_TxtColonNBSP (NumRows == 1 ? Txt_Group : + Txt_Groups); + + /***** Write groups *****/ + if (NumRows) // Groups found... + { + /* Get and write the group types and names */ + for (NumRow = 0; + NumRow < NumRows; + NumRow++) + { + /* Get next group */ + row = mysql_fetch_row (mysql_res); + + /* Write group type name and group name */ + HTM_TxtF ("%s %s",row[0],row[1]); + + if (NumRows >= 2) + { + if (NumRow == NumRows-2) + HTM_TxtF (" %s ",Txt_and); + if (NumRows >= 3) + if (NumRow < NumRows-2) + HTM_Txt (", "); + } + } + } + else + HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName); + + HTM_DIV_End (); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + } + +/*****************************************************************************/ +/***************** Remove all the program items of a course ******************/ +/*****************************************************************************/ + +void Prg_RemoveCrsPrgItems (long CrsCod) + { + /***** Remove groups *****/ + DB_QueryDELETE ("can not remove all the groups associated" + " to program items of a course", + "DELETE FROM prg_grp USING prg_items,prg_grp" + " WHERE prg_items.CrsCod=%ld" + " AND prg_items.PrgIteCod=prg_grp.PrgIteCod", + CrsCod); + + /***** Remove program items *****/ + DB_QueryDELETE ("can not remove all the program items of a course", + "DELETE FROM prg_items WHERE CrsCod=%ld", + CrsCod); + } + +/*****************************************************************************/ +/******** Check if I belong to any of the groups of a program item ***********/ +/*****************************************************************************/ + +static bool Prg_CheckIfIBelongToCrsOrGrpsThisPrgItem (long PrgIteCod) + { + switch (Gbl.Usrs.Me.Role.Logged) + { + case Rol_STD: + case Rol_NET: + case Rol_TCH: + // Students and teachers can do program items depending on groups + /***** Get if I can do a program item from database *****/ + return (DB_QueryCOUNT ("can not check if I can do a program item", + "SELECT COUNT(*) FROM prg_items" + " WHERE PrgIteCod=%ld" + " AND " + "(" + // Schedule item is for the whole course + "PrgIteCod NOT IN (SELECT PrgIteCod FROM prg_grp)" + " OR " + // Schedule item is for specific groups + "PrgIteCod IN" + " (SELECT prg_grp.PrgIteCod FROM prg_grp,crs_grp_usr" + " WHERE crs_grp_usr.UsrCod=%ld" + " AND prg_grp.GrpCod=crs_grp_usr.GrpCod)" + ")", + PrgIteCod,Gbl.Usrs.Me.UsrDat.UsrCod) != 0); + case Rol_SYS_ADM: + return true; + default: + return false; + } + } + +/*****************************************************************************/ +/***************** Get number of program items in a course *******************/ +/*****************************************************************************/ + +unsigned Prg_GetNumPrgItemsInCrs (long CrsCod) + { + /***** Get number of program items in a course from database *****/ + return + (unsigned) DB_QueryCOUNT ("can not get number of program items in course", + "SELECT COUNT(*) FROM prg_items" + " WHERE CrsCod=%ld", + CrsCod); + } + +/*****************************************************************************/ +/****************** Get number of courses with program items *****************/ +/*****************************************************************************/ +// Returns the number of courses with program items +// in this location (all the platform, current degree or current course) + +unsigned Prg_GetNumCoursesWithPrgItems (Hie_Level_t Scope) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumCourses; + + /***** Get number of courses with program items from database *****/ + switch (Scope) + { + case Hie_SYS: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT CrsCod)" + " FROM prg_items" + " WHERE CrsCod>0"); + break; + case Hie_CTY: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT prg_items.CrsCod)" + " FROM institutions,centres,degrees,courses,prg_items" + " WHERE institutions.CtyCod=%ld" + " AND institutions.InsCod=centres.InsCod" + " AND centres.CtrCod=degrees.CtrCod" + " AND degrees.DegCod=courses.DegCod" + " AND courses.Status=0" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Cty.CtyCod); + break; + case Hie_INS: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT prg_items.CrsCod)" + " FROM centres,degrees,courses,prg_items" + " WHERE centres.InsCod=%ld" + " AND centres.CtrCod=degrees.CtrCod" + " AND degrees.DegCod=courses.DegCod" + " AND courses.Status=0" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Ins.InsCod); + break; + case Hie_CTR: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT prg_items.CrsCod)" + " FROM degrees,courses,prg_items" + " WHERE degrees.CtrCod=%ld" + " AND degrees.DegCod=courses.DegCod" + " AND courses.Status=0" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Ctr.CtrCod); + break; + case Hie_DEG: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT prg_items.CrsCod)" + " FROM courses,prg_items" + " WHERE courses.DegCod=%ld" + " AND courses.Status=0" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Deg.DegCod); + break; + case Hie_CRS: + DB_QuerySELECT (&mysql_res,"can not get number of courses with program items", + "SELECT COUNT(DISTINCT CrsCod)" + " FROM prg_items" + " WHERE CrsCod=%ld", + Gbl.Hierarchy.Crs.CrsCod); + break; + default: + Lay_WrongScopeExit (); + break; + } + + /***** 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 program items."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NumCourses; + } + +/*****************************************************************************/ +/************************ Get number of program items ************************/ +/*****************************************************************************/ +// Returns the number of program items +// in this location (all the platform, current degree or current course) + +unsigned Prg_GetNumPrgItems (Hie_Level_t Scope,unsigned *NumNotif) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumPrgItems; + + /***** Get number of program items from database *****/ + switch (Scope) + { + case Hie_SYS: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(NumNotif)" + " FROM prg_items" + " WHERE CrsCod>0"); + break; + case Hie_CTY: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(prg_items.NumNotif)" + " FROM institutions,centres,degrees,courses,prg_items" + " WHERE institutions.CtyCod=%ld" + " AND institutions.InsCod=centres.InsCod" + " AND centres.CtrCod=degrees.CtrCod" + " AND degrees.DegCod=courses.DegCod" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Cty.CtyCod); + break; + case Hie_INS: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(prg_items.NumNotif)" + " FROM centres,degrees,courses,prg_items" + " WHERE centres.InsCod=%ld" + " AND centres.CtrCod=degrees.CtrCod" + " AND degrees.DegCod=courses.DegCod" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Ins.InsCod); + break; + case Hie_CTR: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(prg_items.NumNotif)" + " FROM degrees,courses,prg_items" + " WHERE degrees.CtrCod=%ld" + " AND degrees.DegCod=courses.DegCod" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Ctr.CtrCod); + break; + case Hie_DEG: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(prg_items.NumNotif)" + " FROM courses,prg_items" + " WHERE courses.DegCod=%ld" + " AND courses.CrsCod=prg_items.CrsCod", + Gbl.Hierarchy.Deg.DegCod); + break; + case Hie_CRS: + DB_QuerySELECT (&mysql_res,"can not get number of program items", + "SELECT COUNT(*),SUM(NumNotif)" + " FROM prg_items" + " WHERE CrsCod=%ld", + Gbl.Hierarchy.Crs.CrsCod); + break; + default: + Lay_WrongScopeExit (); + break; + } + + /***** Get number of program items *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%u",&NumPrgItems) != 1) + Lay_ShowErrorAndExit ("Error when getting number of program items."); + + /***** Get number of notifications by email *****/ + if (row[1]) + { + if (sscanf (row[1],"%u",NumNotif) != 1) + Lay_ShowErrorAndExit ("Error when getting number of notifications of program items."); + } + else + *NumNotif = 0; + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NumPrgItems; + } diff --git a/swad_program.h b/swad_program.h new file mode 100644 index 00000000..02999fd8 --- /dev/null +++ b/swad_program.h @@ -0,0 +1,90 @@ +// swad_program.h: course program + +#ifndef _SWAD_PRG +#define _SWAD_PRG +/* + 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-2020 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 "swad_date.h" +#include "swad_file_browser.h" +#include "swad_notification.h" +#include "swad_user.h" + +/*****************************************************************************/ +/************************** Public types and constants ***********************/ +/*****************************************************************************/ + +#define Prg_MAX_CHARS_PROGRAM_ITEM_TITLE (128 - 1) // 127 +#define Prg_MAX_BYTES_PROGRAM_ITEM_TITLE ((Prg_MAX_CHARS_PROGRAM_ITEM_TITLE + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 + +struct ProgramItem + { + long PrgIteCod; + bool Hidden; + long UsrCod; + time_t TimeUTC[Dat_NUM_START_END_TIME]; + bool Open; + char Title[Prg_MAX_BYTES_PROGRAM_ITEM_TITLE + 1]; + bool IBelongToCrsOrGrps; // I can do this program item + // (it is associated to no groups + // or, if associated to groups, + // I belong to any of the groups) + }; + +#define Prg_ORDER_DEFAULT Dat_START_TIME + +/*****************************************************************************/ +/***************************** Public prototypes *****************************/ +/*****************************************************************************/ + +void Prg_SeeCourseProgram (void); +void Prg_PrintOnePrgItem (void); + +void Prg_PutHiddenParamPrgOrder (void); +void Prg_RequestCreatOrEditPrgItem (void); +void Prg_GetListPrgItems (void); +void Prg_GetDataOfPrgItemByCod (struct ProgramItem *PrgItem); +void Prg_FreeListPrgItems (void); + +void Prg_GetNotifPrgItem (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], + char **ContentStr, + long PrgIteCod,bool GetContent); + +long Prg_GetParamPrgItemCod (void); +void Prg_ReqRemPrgItem (void); +void Prg_RemovePrgItem (void); +void Prg_HidePrgItem (void); +void Prg_ShowPrgItem (void); +void Prg_RecFormPrgItem (void); +bool Prg_CheckIfPrgItemIsAssociatedToGrp (long PrgIteCod,long GrpCod); +void Prg_RemoveGroup (long GrpCod); +void Prg_RemoveGroupsOfType (long GrpTypCod); +void Prg_RemoveCrsPrgItems (long CrsCod); +unsigned Prg_GetNumPrgItemsInCrs(long CrsCod); + +unsigned Prg_GetNumCoursesWithPrgItems (Hie_Level_t Scope); +unsigned Prg_GetNumPrgItems (Hie_Level_t Scope,unsigned *NumNotif); + +#endif diff --git a/swad_text.c b/swad_text.c index e2a82e50..c8b8ceae 100644 --- a/swad_text.c +++ b/swad_text.c @@ -1506,6 +1506,27 @@ const char *Txt_Already_existed_an_event_with_the_title_X = // Warning: it is ve "Já existe um evento com o título %s."; #endif +const char *Txt_Already_existed_an_item_with_the_title_X = // Warning: it is very important to include %s in the following sentences +#if L==1 // ca + "Ja existia un ítem amb el títol %s."; +#elif L==2 // de + "Es gibt bereits einen Artikel mit dem Namen %s."; +#elif L==3 // en + "Already existed an item with the title %s."; +#elif L==4 // es + "Ya existía un ítem con el título %s."; +#elif L==5 // fr + "Il existe déjà un article du titre %s."; +#elif L==6 // gn + "Ya existía un ítem con el título %s."; // Okoteve traducción +#elif L==7 // it + "Esiste già un articolo con il titolo %s."; +#elif L==8 // pl + "Istniala juz przedmiot z tytulu %s."; +#elif L==9 // pt + "Já existe um item com o título %s."; +#endif + const char *Txt_Altitude = #if L==1 // ca "Altitud"; @@ -5182,6 +5203,27 @@ const char *Txt_course = "disciplina"; #endif +const char *Txt_Course_program = +#if L==1 // ca + "Programa de l'assignatura"; +#elif L==2 // de + "Kursprogramm"; +#elif L==3 // en + "Course program"; +#elif L==4 // es + "Programa de la asignatura"; +#elif L==5 // fr + "Programme de la matière"; +#elif L==6 // gn + "Programa de la asignatura"; // Okoteve traducción +#elif L==7 // it + "Programma del corso"; +#elif L==8 // pl + "Program kursu"; +#elif L==9 // pt + "Programa da disciplina"; +#endif + const char *Txt_COURSE_STATUS[Crs_NUM_STATUS_TXT] = { [Crs_STATUS_UNKNOWN] = @@ -5941,6 +5983,27 @@ const char *Txt_Create_institution = "Criar institução"; #endif +const char *Txt_Create_item = +#if L==1 // ca + "Crear ítem"; +#elif L==2 // de + "Artikel eingeben"; +#elif L==3 // en + "Create item"; +#elif L==4 // es + "Crear ítem"; +#elif L==5 // fr + "Créer article"; +#elif L==6 // gn + "Crear ítem"; // Okoteve traducción +#elif L==7 // it + "Crea articolo"; +#elif L==8 // pl + "Utwórz przedmiot"; +#elif L==9 // pt + "Criar item"; +#endif + const char *Txt_Create_link = #if L==1 // ca "Crear enllaç"; @@ -6529,6 +6592,27 @@ const char *Txt_Created_new_institution_X = // Warning: it is very important to "Criada nova institução %s."; #endif +const char *Txt_Created_new_item_X = // Warning: it is very important to include %s in the following sentences +#if L==1 // ca + "Creado nuevo ítem %s."; // Necessita traduccio +#elif L==2 // de + "Neue Artikel %s eingegeben."; +#elif L==3 // en + "Created new item %s."; +#elif L==4 // es + "Creado nuevo ítem %s."; +#elif L==5 // fr + "Créée nouvel article %s."; +#elif L==6 // gn + "Creado nuevo ítem %s."; // Okoteve traducción +#elif L==7 // it + "Creato nuovo articolo %s."; +#elif L==8 // pl + "Utworzono nowa przedmiot %s."; +#elif L==9 // pt + "Criado novo item %s."; +#endif + const char *Txt_Created_new_link_X = // Warning: it is very important to include %s in the following sentences #if L==1 // ca "Creado nuevo enlace %s."; // Necessita traduccio @@ -9080,6 +9164,27 @@ const char *Txt_Do_you_really_want_to_remove_the_group_X_Y_students_ = // Warnin "Ao fazer isso, você removerá %u estudantes desse grupo."; #endif +const char *Txt_Do_you_really_want_to_remove_the_item_X = // Warning: it is very important to include %s in the following sentences +#if L==1 // ca + "De veres voleu eliminar l'ítem %s?"; +#elif L==2 // de + "Wollen Sie die Artikel %s wirklich entfernen?"; +#elif L==3 // en + "Do you really want to remove the item %s?"; +#elif L==4 // es + "¿Realmente desea eliminar el ítem %s?"; +#elif L==5 // fr + "Voulez-vous vraiment supprimer l'article %s?"; +#elif L==6 // gn + "¿Realmente desea eliminar el ítem %s?"; // Okoteve traducción +#elif L==7 // it + "Vuoi realmente rimuovere il articolo %s?"; +#elif L==8 // pl + "Czy na pewno chcesz usunac przedmiot %s?"; +#elif L==9 // pt + "Você realmente deseja remover o item %s?"; +#endif + const char *Txt_Do_you_really_want_to_remove_the_match_X = // Warning: it is very important to include %s in the following sentences #if L==1 // ca "De veres voleu eliminar la partida %s?"; @@ -9145,7 +9250,7 @@ const char *Txt_Do_you_really_want_to_remove_the_project_X = // Warning: it is v const char *Txt_Do_you_really_want_to_remove_the_question_X = // Warning: it is very important to include %ld in the following sentences #if L==1 // ca - "De veres voleu eliminar pregunta %ld?"; + "De veres voleu eliminar la pregunta %ld?"; #elif L==2 // de "Wollen Sie die Frage %ld wirklich entfernen?"; #elif L==3 // en @@ -9896,6 +10001,27 @@ const char *Txt_Edit_game = "Editar jogo"; #endif +const char *Txt_Edit_item = +#if L==1 // ca + "Editar ítem"; +#elif L==2 // de + "Artikel bearbeiten"; +#elif L==3 // en + "Edit item"; +#elif L==4 // es + "Editar ítem"; +#elif L==5 // fr + "Éditer article"; +#elif L==6 // gn + "Editar ítem"; // Okoteve traducción +#elif L==7 // it + "Editare articolo"; +#elif L==8 // pl + "Edycja przedmiot"; +#elif L==9 // pt + "Editar item"; +#endif + const char *Txt_Edit_my_personal_data = #if L==1 // ca "Edita meves dades personals"; @@ -15912,7 +16038,7 @@ const char *Txt_INFO_TITLE[Inf_NUM_INFO_TYPES] = #elif L==2 // de "Studienplan (Vorlesungen)" #elif L==3 // en - "Syllabus (lectures)" + "Topics (lectures)" #elif L==4 // es "Temario teoría" #elif L==5 // fr @@ -15933,7 +16059,7 @@ const char *Txt_INFO_TITLE[Inf_NUM_INFO_TYPES] = #elif L==2 // de "Studienplan (Übungen)" #elif L==3 // en - "Syllabus (practicals)" + "Topics (practicals)" #elif L==4 // es "Temario prácticas" #elif L==5 // fr @@ -17083,6 +17209,27 @@ const char *Txt_It_is_optional_to_choose_a_group = "Escolher um grupo é voluntário"; #endif +const char *Txt_Item = +#if L==1 // ca + "Ítem"; +#elif L==2 // de + "Artikel"; +#elif L==3 // en + "Item"; +#elif L==4 // es + "Ítem"; +#elif L==5 // fr + "Article"; +#elif L==6 // gn + "Ítem"; // Okoteve traducción +#elif L==7 // it + "Articolo"; +#elif L==8 // pl + "Pozycja"; +#elif L==9 // pt + "Item"; +#endif + const char *Txt_Its_me = #if L==1 // ca "Sóc jo!"; @@ -19223,13 +19370,13 @@ const char *Txt_MENU_TITLE[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB] = "Informação" #endif , - // 1: ActSeeScd + // 1: ActSeePrg #if L==1 // ca "Programa" #elif L==2 // de "Programm" #elif L==3 // en - "Schedule" + "Program" #elif L==4 // es "Programa" #elif L==5 // fr @@ -19271,7 +19418,7 @@ const char *Txt_MENU_TITLE[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB] = #elif L==2 // de "Studienplan" #elif L==3 // en - "Syllabus" + "Topics" #elif L==4 // es "Temario" #elif L==5 // fr @@ -21079,7 +21226,7 @@ const char *Txt_MENU_SUBTITLE[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB] = "Informação desta disciplina" #endif , - // 1: ActSeeScd + // 1: ActSeePrg #if L==1 // ca "Programació didàctica de l'assignatura" #elif L==2 // de @@ -21127,7 +21274,7 @@ const char *Txt_MENU_SUBTITLE[Tab_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB] = #elif L==2 // de "Studienplan" #elif L==3 // en - "Syllabus" + "Topics" #elif L==4 // es "Temario de la asignatura" #elif L==5 // fr @@ -24463,6 +24610,27 @@ const char *Txt_New_institution = "Nova institução (universidade, faculdade, escola, academia, organização, empresa...)"; #endif +const char *Txt_New_item = +#if L==1 // ca + "Nou ítem"; +#elif L==2 // de + "Neuer Artikel"; +#elif L==3 // en + "New item"; +#elif L==4 // es + "Nuevo ítem"; +#elif L==5 // fr + "Nouvel article"; +#elif L==6 // gn + "Nuevo ítem"; // Okoteve traducción +#elif L==7 // it + "Nuovo articolo"; +#elif L==8 // pl + "Nowa pozycja"; +#elif L==9 // pt + "Novo item"; +#endif + const char *Txt_New_link = #if L==1 // ca "Nuevo enlace"; // Necessita traduccio @@ -25510,6 +25678,27 @@ const char *Txt_No_institutions = "Não há instituções."; #endif +const char *Txt_No_items = +#if L==1 // ca + "No hi ha items"; +#elif L==2 // de + "Keine Artikel"; +#elif L==3 // en + "No items"; +#elif L==4 // es + "No hay items"; +#elif L==5 // fr + "Il n'y a pas d'articles"; +#elif L==6 // gn + "No hay items"; // Okoteve traducción +#elif L==7 // it + "Non ci sono articoli"; +#elif L==8 // pl + "Brak przedmiotów"; +#elif L==9 // pt + "Não há itens"; +#endif + const char *Txt_No_links = #if L==1 // ca "No hi ha enllaços."; @@ -32859,6 +33048,27 @@ const char *Txt_Remove_group = "Remover grupo"; #endif +const char *Txt_Remove_item = +#if L==1 // ca + "Eliminar ítem"; +#elif L==2 // de + "Entfernen Artikel"; +#elif L==3 // en + "Remove item"; +#elif L==4 // es + "Eliminar ítem"; +#elif L==5 // fr + "Supprimer article"; +#elif L==6 // gn + "Eliminar ítem"; // Okoteve traducción +#elif L==7 // it + "Rimuovere articolo"; +#elif L==8 // pl + "Usuń przedmiot"; +#elif L==9 // pt + "Remover item"; +#endif + const char *Txt_Remove_link = #if L==1 // ca "Eliminar enllaç"; @@ -41681,6 +41891,27 @@ const char *Txt_FIGURE_TYPES[Fig_NUM_FIGURES] = "Otwarte Zasoby Edukacyjne (OER)" #elif L==9 // pt "Recursos Educacionais Abertos (OER)" +#endif + , + [Fig_COURSE_PROGRAM] = +#if L==1 // ca + "Programa" +#elif L==2 // de + "Programm" +#elif L==3 // en + "Program" +#elif L==4 // es + "Programa" +#elif L==5 // fr + "Programme" +#elif L==6 // gn + "Programa" // Okoteve traducción +#elif L==7 // it + "Programma" +#elif L==8 // pl + "Program" +#elif L==9 // pt + "Programa" #endif , [Fig_ASSIGNMENTS] = @@ -45894,6 +46125,27 @@ const char *Txt_The_integrated_editor_is_not_yet_available = "O editor integrado ainda não está disponível."; #endif +const char *Txt_The_item_has_been_modified = +#if L==1 // ca + "El ítem ha estat modificat."; +#elif L==2 // de + "Das Artikel wurde geändert."; +#elif L==3 // en + "The item has been modified."; +#elif L==4 // es + "El ítem ha sido modificado."; +#elif L==5 // fr + "L'article a été modifié."; +#elif L==6 // gn + "El ítem ha sido modificado."; // Okoteve traducción +#elif L==7 // it + "Il articolo è stato modificato."; +#elif L==8 // pl + "Gra przedmiot zmodyfikowane."; +#elif L==9 // pt + "O item foi modificado."; +#endif + const char *Txt_The_link_X_already_exists = // Warning: it is very important to include %s in the following sentences #if L==1 // ca "El enlace %s ya existe."; // Necessita traduccio @@ -56821,6 +57073,27 @@ const char *Txt_You_must_specify_the_title_of_the_game = "Você deve especificar o título do jogo."; #endif +const char *Txt_You_must_specify_the_title_of_the_item = +#if L==1 // ca + "Cal especificar el títol del ítem."; +#elif L==2 // de + "Die Artikel muss angegeben werden."; +#elif L==3 // en + "You must specify the title of the item."; +#elif L==4 // es + "Debe especificar el título del ítem."; +#elif L==5 // fr + "Vous devez spécifier le titre du article."; +#elif L==6 // gn + "Debe especificar el título del ítem."; // Okoteve traducción +#elif L==7 // it + "È necessario specificare il titolo del articolo."; +#elif L==8 // pl + "Musisz podać tytuł przedmiot."; +#elif L==9 // pt + "Você deve especificar o título do item."; +#endif + const char *Txt_You_must_specify_the_title_of_the_project = #if L==1 // ca "Cal especificar el títol del projecte."; diff --git a/swad_text_action.c b/swad_text_action.c index b5926e30..1a16ee7f 100644 --- a/swad_text_action.c +++ b/swad_text_action.c @@ -4766,7 +4766,7 @@ const char *Txt_Actions[Act_NUM_ACTIONS] = "" // Precisa de tradução #endif , - [ActSeeScd] = + [ActSeePrg] = #if L==1 // ca "" // Necessita traducció #elif L==2 // de