From 79d93babfa4ad2eaaa29ab86099a3c72ed73213a Mon Sep 17 00:00:00 2001 From: acanas Date: Mon, 19 Sep 2022 09:11:45 +0200 Subject: [PATCH] Version 22.9: Sep 19, 2022 Links to exams in program. --- swad_action.c | 2 + swad_action.h | 202 ++++++++++++++++++++-------------------- swad_browser.c | 178 ++++++++++++++++++++--------------- swad_browser.h | 10 +- swad_browser_database.c | 17 +--- swad_browser_database.h | 1 + swad_changelog.h | 3 +- swad_exam.c | 91 ++++++++++++++++++ swad_exam.h | 5 + swad_exam_database.c | 15 +++ swad_exam_database.h | 1 + swad_game.c | 24 +++-- swad_game_database.c | 2 +- swad_program_resource.c | 7 +- swad_text_action.c | 23 +++++ 15 files changed, 373 insertions(+), 208 deletions(-) diff --git a/swad_action.c b/swad_action.c index 9b0fc973..77940ce6 100644 --- a/swad_action.c +++ b/swad_action.c @@ -725,6 +725,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActRemExa ] = {1882,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RemoveExam ,NULL}, [ActHidExa ] = {1883,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_HideExam ,NULL}, [ActUnhExa ] = {1884,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_UnhideExam ,NULL}, + [ActReqLnkExa ] = {1936,-1,TabUnk,ActSeeAllExa ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_GetLinkToExam ,NULL}, [ActFrmNewExaSet ] = {1892,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,ExaSet_RequestCreatOrEditSet ,NULL}, [ActNewExaSet ] = {1898,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaSet_ReceiveFormSet ,NULL}, @@ -3781,6 +3782,7 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un ActChgLnkPrgRsc, // #1933 ActReqLnkCfe, // #1934 ActReqLnkGam, // #1935 + ActReqLnkExa, // #1936 }; /*****************************************************************************/ diff --git a/swad_action.h b/swad_action.h index 53523862..589bdaa4 100644 --- a/swad_action.h +++ b/swad_action.h @@ -65,7 +65,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 1935 +#define Act_MAX_ACTION_COD 1936 #define Act_MAX_OPTIONS_IN_MENU_PER_TAB 13 @@ -683,117 +683,119 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to #define ActRemExa (ActChgCrsTT1stDay + 140) #define ActHidExa (ActChgCrsTT1stDay + 141) #define ActUnhExa (ActChgCrsTT1stDay + 142) -#define ActFrmNewExaSet (ActChgCrsTT1stDay + 143) -#define ActNewExaSet (ActChgCrsTT1stDay + 144) -#define ActReqRemExaSet (ActChgCrsTT1stDay + 145) -#define ActRemExaSet (ActChgCrsTT1stDay + 146) -#define ActUp_ExaSet (ActChgCrsTT1stDay + 147) -#define ActDwnExaSet (ActChgCrsTT1stDay + 148) -#define ActChgTitExaSet (ActChgCrsTT1stDay + 149) -#define ActChgNumQstExaSet (ActChgCrsTT1stDay + 150) +#define ActReqLnkExa (ActChgCrsTT1stDay + 143) -#define ActReqAddQstExaSet (ActChgCrsTT1stDay + 151) -#define ActLstTstQstForSet (ActChgCrsTT1stDay + 152) -#define ActAddQstToExa (ActChgCrsTT1stDay + 153) -#define ActReqRemSetQst (ActChgCrsTT1stDay + 154) -#define ActRemExaQst (ActChgCrsTT1stDay + 155) -#define ActValSetQst (ActChgCrsTT1stDay + 156) -#define ActInvSetQst (ActChgCrsTT1stDay + 157) +#define ActFrmNewExaSet (ActChgCrsTT1stDay + 144) +#define ActNewExaSet (ActChgCrsTT1stDay + 145) +#define ActReqRemExaSet (ActChgCrsTT1stDay + 146) +#define ActRemExaSet (ActChgCrsTT1stDay + 147) +#define ActUp_ExaSet (ActChgCrsTT1stDay + 148) +#define ActDwnExaSet (ActChgCrsTT1stDay + 149) +#define ActChgTitExaSet (ActChgCrsTT1stDay + 150) +#define ActChgNumQstExaSet (ActChgCrsTT1stDay + 151) -#define ActReqNewExaSes (ActChgCrsTT1stDay + 158) -#define ActEdiOneExaSes (ActChgCrsTT1stDay + 159) -#define ActNewExaSes (ActChgCrsTT1stDay + 160) -#define ActChgExaSes (ActChgCrsTT1stDay + 161) -#define ActReqRemExaSes (ActChgCrsTT1stDay + 162) -#define ActRemExaSes (ActChgCrsTT1stDay + 163) -#define ActHidExaSes (ActChgCrsTT1stDay + 164) -#define ActUnhExaSes (ActChgCrsTT1stDay + 165) +#define ActReqAddQstExaSet (ActChgCrsTT1stDay + 152) +#define ActLstTstQstForSet (ActChgCrsTT1stDay + 153) +#define ActAddQstToExa (ActChgCrsTT1stDay + 154) +#define ActReqRemSetQst (ActChgCrsTT1stDay + 155) +#define ActRemExaQst (ActChgCrsTT1stDay + 156) +#define ActValSetQst (ActChgCrsTT1stDay + 157) +#define ActInvSetQst (ActChgCrsTT1stDay + 158) -#define ActSeeExaPrn (ActChgCrsTT1stDay + 166) -#define ActAnsExaPrn (ActChgCrsTT1stDay + 167) -#define ActEndExaPrn (ActChgCrsTT1stDay + 168) +#define ActReqNewExaSes (ActChgCrsTT1stDay + 159) +#define ActEdiOneExaSes (ActChgCrsTT1stDay + 160) +#define ActNewExaSes (ActChgCrsTT1stDay + 161) +#define ActChgExaSes (ActChgCrsTT1stDay + 162) +#define ActReqRemExaSes (ActChgCrsTT1stDay + 163) +#define ActRemExaSes (ActChgCrsTT1stDay + 164) +#define ActHidExaSes (ActChgCrsTT1stDay + 165) +#define ActUnhExaSes (ActChgCrsTT1stDay + 166) -#define ActSeeMyExaResCrs (ActChgCrsTT1stDay + 169) -#define ActSeeMyExaResExa (ActChgCrsTT1stDay + 170) -#define ActSeeMyExaResSes (ActChgCrsTT1stDay + 171) -#define ActSeeOneExaResMe (ActChgCrsTT1stDay + 172) -#define ActReqSeeUsrExaRes (ActChgCrsTT1stDay + 173) -#define ActSeeUsrExaResCrs (ActChgCrsTT1stDay + 174) -#define ActSeeUsrExaResExa (ActChgCrsTT1stDay + 175) -#define ActSeeUsrExaResSes (ActChgCrsTT1stDay + 176) -#define ActSeeOneExaResOth (ActChgCrsTT1stDay + 177) -#define ActChgVisExaRes (ActChgCrsTT1stDay + 178) +#define ActSeeExaPrn (ActChgCrsTT1stDay + 167) +#define ActAnsExaPrn (ActChgCrsTT1stDay + 168) +#define ActEndExaPrn (ActChgCrsTT1stDay + 169) -#define ActSeeGam (ActChgCrsTT1stDay + 179) -#define ActReqRemMch (ActChgCrsTT1stDay + 180) -#define ActRemMch (ActChgCrsTT1stDay + 181) -#define ActEdiMch (ActChgCrsTT1stDay + 182) -#define ActChgMch (ActChgCrsTT1stDay + 183) -#define ActReqNewMch (ActChgCrsTT1stDay + 184) -#define ActNewMch (ActChgCrsTT1stDay + 185) -#define ActResMch (ActChgCrsTT1stDay + 186) -#define ActBckMch (ActChgCrsTT1stDay + 187) -#define ActPlyPauMch (ActChgCrsTT1stDay + 188) -#define ActFwdMch (ActChgCrsTT1stDay + 189) -#define ActChgNumColMch (ActChgCrsTT1stDay + 190) -#define ActChgVisResMchQst (ActChgCrsTT1stDay + 191) -#define ActMchCntDwn (ActChgCrsTT1stDay + 192) -#define ActRefMchTch (ActChgCrsTT1stDay + 193) +#define ActSeeMyExaResCrs (ActChgCrsTT1stDay + 170) +#define ActSeeMyExaResExa (ActChgCrsTT1stDay + 171) +#define ActSeeMyExaResSes (ActChgCrsTT1stDay + 172) +#define ActSeeOneExaResMe (ActChgCrsTT1stDay + 173) +#define ActReqSeeUsrExaRes (ActChgCrsTT1stDay + 174) +#define ActSeeUsrExaResCrs (ActChgCrsTT1stDay + 175) +#define ActSeeUsrExaResExa (ActChgCrsTT1stDay + 176) +#define ActSeeUsrExaResSes (ActChgCrsTT1stDay + 177) +#define ActSeeOneExaResOth (ActChgCrsTT1stDay + 178) +#define ActChgVisExaRes (ActChgCrsTT1stDay + 179) -#define ActJoiMch (ActChgCrsTT1stDay + 194) -#define ActSeeMchAnsQstStd (ActChgCrsTT1stDay + 195) -#define ActRemMchAnsQstStd (ActChgCrsTT1stDay + 196) -#define ActAnsMchQstStd (ActChgCrsTT1stDay + 197) -#define ActRefMchStd (ActChgCrsTT1stDay + 198) +#define ActSeeGam (ActChgCrsTT1stDay + 180) +#define ActReqRemMch (ActChgCrsTT1stDay + 181) +#define ActRemMch (ActChgCrsTT1stDay + 182) +#define ActEdiMch (ActChgCrsTT1stDay + 183) +#define ActChgMch (ActChgCrsTT1stDay + 184) +#define ActReqNewMch (ActChgCrsTT1stDay + 185) +#define ActNewMch (ActChgCrsTT1stDay + 186) +#define ActResMch (ActChgCrsTT1stDay + 187) +#define ActBckMch (ActChgCrsTT1stDay + 188) +#define ActPlyPauMch (ActChgCrsTT1stDay + 189) +#define ActFwdMch (ActChgCrsTT1stDay + 190) +#define ActChgNumColMch (ActChgCrsTT1stDay + 191) +#define ActChgVisResMchQst (ActChgCrsTT1stDay + 192) +#define ActMchCntDwn (ActChgCrsTT1stDay + 193) +#define ActRefMchTch (ActChgCrsTT1stDay + 194) -#define ActSeeMyMchResCrs (ActChgCrsTT1stDay + 199) -#define ActSeeMyMchResGam (ActChgCrsTT1stDay + 200) -#define ActSeeMyMchResMch (ActChgCrsTT1stDay + 201) -#define ActSeeOneMchResMe (ActChgCrsTT1stDay + 202) +#define ActJoiMch (ActChgCrsTT1stDay + 195) +#define ActSeeMchAnsQstStd (ActChgCrsTT1stDay + 196) +#define ActRemMchAnsQstStd (ActChgCrsTT1stDay + 197) +#define ActAnsMchQstStd (ActChgCrsTT1stDay + 198) +#define ActRefMchStd (ActChgCrsTT1stDay + 199) -#define ActReqSeeUsrMchRes (ActChgCrsTT1stDay + 203) -#define ActSeeUsrMchResCrs (ActChgCrsTT1stDay + 204) -#define ActSeeUsrMchResGam (ActChgCrsTT1stDay + 205) -#define ActSeeUsrMchResMch (ActChgCrsTT1stDay + 206) -#define ActSeeOneMchResOth (ActChgCrsTT1stDay + 207) +#define ActSeeMyMchResCrs (ActChgCrsTT1stDay + 200) +#define ActSeeMyMchResGam (ActChgCrsTT1stDay + 201) +#define ActSeeMyMchResMch (ActChgCrsTT1stDay + 202) +#define ActSeeOneMchResMe (ActChgCrsTT1stDay + 203) -#define ActChgVisResMchUsr (ActChgCrsTT1stDay + 208) +#define ActReqSeeUsrMchRes (ActChgCrsTT1stDay + 204) +#define ActSeeUsrMchResCrs (ActChgCrsTT1stDay + 205) +#define ActSeeUsrMchResGam (ActChgCrsTT1stDay + 206) +#define ActSeeUsrMchResMch (ActChgCrsTT1stDay + 207) +#define ActSeeOneMchResOth (ActChgCrsTT1stDay + 208) -#define ActLstOneGam (ActChgCrsTT1stDay + 209) +#define ActChgVisResMchUsr (ActChgCrsTT1stDay + 209) -#define ActFrmNewGam (ActChgCrsTT1stDay + 210) -#define ActEdiOneGam (ActChgCrsTT1stDay + 211) -#define ActNewGam (ActChgCrsTT1stDay + 212) -#define ActChgGam (ActChgCrsTT1stDay + 213) -#define ActReqRemGam (ActChgCrsTT1stDay + 214) -#define ActRemGam (ActChgCrsTT1stDay + 215) -#define ActHidGam (ActChgCrsTT1stDay + 216) -#define ActUnhGam (ActChgCrsTT1stDay + 217) -#define ActAddOneGamQst (ActChgCrsTT1stDay + 218) -#define ActGamLstTstQst (ActChgCrsTT1stDay + 219) -#define ActAddTstQstToGam (ActChgCrsTT1stDay + 220) -#define ActReqRemGamQst (ActChgCrsTT1stDay + 221) -#define ActRemGamQst (ActChgCrsTT1stDay + 222) -#define ActUp_GamQst (ActChgCrsTT1stDay + 223) -#define ActDwnGamQst (ActChgCrsTT1stDay + 224) -#define ActReqLnkGam (ActChgCrsTT1stDay + 225) +#define ActLstOneGam (ActChgCrsTT1stDay + 210) -#define ActSeeSvy (ActChgCrsTT1stDay + 226) -#define ActAnsSvy (ActChgCrsTT1stDay + 227) -#define ActFrmNewSvy (ActChgCrsTT1stDay + 228) -#define ActEdiOneSvy (ActChgCrsTT1stDay + 229) -#define ActNewSvy (ActChgCrsTT1stDay + 230) -#define ActChgSvy (ActChgCrsTT1stDay + 231) -#define ActReqRemSvy (ActChgCrsTT1stDay + 232) -#define ActRemSvy (ActChgCrsTT1stDay + 233) -#define ActReqRstSvy (ActChgCrsTT1stDay + 234) -#define ActRstSvy (ActChgCrsTT1stDay + 235) -#define ActHidSvy (ActChgCrsTT1stDay + 236) -#define ActUnhSvy (ActChgCrsTT1stDay + 237) -#define ActEdiOneSvyQst (ActChgCrsTT1stDay + 238) -#define ActRcvSvyQst (ActChgCrsTT1stDay + 239) -#define ActReqRemSvyQst (ActChgCrsTT1stDay + 240) -#define ActRemSvyQst (ActChgCrsTT1stDay + 241) +#define ActFrmNewGam (ActChgCrsTT1stDay + 211) +#define ActEdiOneGam (ActChgCrsTT1stDay + 212) +#define ActNewGam (ActChgCrsTT1stDay + 213) +#define ActChgGam (ActChgCrsTT1stDay + 214) +#define ActReqRemGam (ActChgCrsTT1stDay + 215) +#define ActRemGam (ActChgCrsTT1stDay + 216) +#define ActHidGam (ActChgCrsTT1stDay + 217) +#define ActUnhGam (ActChgCrsTT1stDay + 218) +#define ActAddOneGamQst (ActChgCrsTT1stDay + 219) +#define ActGamLstTstQst (ActChgCrsTT1stDay + 220) +#define ActAddTstQstToGam (ActChgCrsTT1stDay + 221) +#define ActReqRemGamQst (ActChgCrsTT1stDay + 222) +#define ActRemGamQst (ActChgCrsTT1stDay + 223) +#define ActUp_GamQst (ActChgCrsTT1stDay + 224) +#define ActDwnGamQst (ActChgCrsTT1stDay + 225) +#define ActReqLnkGam (ActChgCrsTT1stDay + 226) + +#define ActSeeSvy (ActChgCrsTT1stDay + 227) +#define ActAnsSvy (ActChgCrsTT1stDay + 228) +#define ActFrmNewSvy (ActChgCrsTT1stDay + 229) +#define ActEdiOneSvy (ActChgCrsTT1stDay + 230) +#define ActNewSvy (ActChgCrsTT1stDay + 231) +#define ActChgSvy (ActChgCrsTT1stDay + 232) +#define ActReqRemSvy (ActChgCrsTT1stDay + 233) +#define ActRemSvy (ActChgCrsTT1stDay + 234) +#define ActReqRstSvy (ActChgCrsTT1stDay + 235) +#define ActRstSvy (ActChgCrsTT1stDay + 236) +#define ActHidSvy (ActChgCrsTT1stDay + 237) +#define ActUnhSvy (ActChgCrsTT1stDay + 238) +#define ActEdiOneSvyQst (ActChgCrsTT1stDay + 239) +#define ActRcvSvyQst (ActChgCrsTT1stDay + 240) +#define ActReqRemSvyQst (ActChgCrsTT1stDay + 241) +#define ActRemSvyQst (ActChgCrsTT1stDay + 242) /*****************************************************************************/ /******************************** Files tab **********************************/ diff --git a/swad_browser.c b/swad_browser.c index 162cf266..b96c3b93 100644 --- a/swad_browser.c +++ b/swad_browser.c @@ -5318,6 +5318,38 @@ static void Brw_WriteFileName (unsigned Level,bool IsPublic) } } +/*****************************************************************************/ +/****************************** Get link to file *****************************/ +/*****************************************************************************/ + +void Brw_GetLinkToFile (void) + { + extern const char *Txt_Link_to_resource_X_copied_into_clipboard; + struct FileMetadata FileMetadata; + bool Found; + + /***** Get parameters related to file browser *****/ + Brw_GetParAndInitFileBrowser (); + + /***** Get file name *****/ + FileMetadata.FilCod = Brw_GetParamFilCod (); + Brw_GetFileNameByCod (&FileMetadata); + Found = Brw_GetFileTypeSizeAndDate (&FileMetadata); + + if (Found) + { + /***** Copy link to file into resource clipboard *****/ + Prg_DB_CopyToClipboard (PrgRsc_DOCUMENT,FileMetadata.FilCod); + + /***** Write sucess message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Link_to_resource_X_copied_into_clipboard, + FileMetadata.FilFolLnk.Name); + } + + /***** Show again the file browser *****/ + Brw_ShowAgainFileBrowserOrWorks (); + } + /*****************************************************************************/ /******************** Write file name in course program **********************/ /*****************************************************************************/ @@ -5353,6 +5385,25 @@ void Brw_WriteFileNameInCrsProgram (long FilCod,bool PutFormToDownload) } } +/*****************************************************************************/ +/********************** Get file name from file code *************************/ +/*****************************************************************************/ + +void Brw_GetFileNameFromFilCod (long FilCod,char *FileName,size_t FileNameSize) + { + struct FileMetadata FileMetadata; + + /***** Return nothing on error *****/ + FileName[0] = '\0'; // Return nothing on error + + /***** Get file metadata *****/ + FileMetadata.FilCod = FilCod; + Brw_GetFileMetadataByCod (&FileMetadata); + + /***** Copy file name into summary string *****/ + Str_Copy (FileName,FileMetadata.FilFolLnk.Name,FileNameSize); + } + /*****************************************************************************/ /*********************** Which filename must be shown? ***********************/ /*****************************************************************************/ @@ -8348,35 +8399,47 @@ static void Brw_PutParamsToGetLinkToFile (void *FileMetadata) } /*****************************************************************************/ -/****************************** Get link to file *****************************/ +/************************ Get link to download a file ************************/ /*****************************************************************************/ -void Brw_GetLinkToFile (void) +void Brw_GetLinkToDownloadFile (const char *PathInTree,const char *FileName,char *URL) { - extern const char *Txt_Link_to_resource_X_copied_into_clipboard; - struct FileMetadata FileMetadata; - bool Found; + char FullPathIncludingFile[PATH_MAX + 1 + PATH_MAX + 1 + NAME_MAX + 1]; + FILE *FileURL; + char URLWithSpaces[PATH_MAX + 1]; - /***** Get parameters related to file browser *****/ - Brw_GetParAndInitFileBrowser (); + /***** Construct absolute path to file in the private directory *****/ + snprintf (FullPathIncludingFile,sizeof (FullPathIncludingFile),"%s/%s/%s", + Gbl.FileBrowser.Priv.PathAboveRootFolder,PathInTree,FileName); - /***** Get file metadata *****/ - FileMetadata.FilCod = Brw_GetParamFilCod (); - Brw_GetFileMetadataByCod (&FileMetadata); - Found = Brw_GetFileTypeSizeAndDate (&FileMetadata); - - if (Found) + if (Str_FileIs (FileName,"url")) // It's a link (URL inside a .url file) { - /***** Copy link to file into resource clipboard *****/ - Prg_DB_CopyToClipboard (PrgRsc_DOCUMENT,FileMetadata.FilCod); + /***** Open .url file *****/ + if ((FileURL = fopen (FullPathIncludingFile,"rb"))) + { + if (fgets (URLWithSpaces,PATH_MAX,FileURL) == NULL) + URLWithSpaces[0] = '\0'; + /* File is not longer needed ==> close it */ + fclose (FileURL); + } + } + else + { + /***** Create a temporary public directory used to download files *****/ + Brw_CreateDirDownloadTmp (); - /***** Write sucess message *****/ - Ale_ShowAlert (Ale_SUCCESS,Txt_Link_to_resource_X_copied_into_clipboard, - FileMetadata.FilFolLnk.Name); + /***** Create symbolic link from temporary public directory to private file in order to gain access to it for downloading *****/ + Brw_CreateTmpPublicLinkToPrivateFile (FullPathIncludingFile,FileName); + + /***** Create URL pointing to symbolic link *****/ + snprintf (URLWithSpaces,sizeof (URLWithSpaces),"%s/%s/%s/%s", + Cfg_URL_FILE_BROWSER_TMP_PUBLIC, + Gbl.FileBrowser.TmpPubDir.L, + Gbl.FileBrowser.TmpPubDir.R, + FileName); } - /***** Show again the file browser *****/ - Brw_ShowAgainFileBrowserOrWorks (); + Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces } /*****************************************************************************/ @@ -8713,50 +8776,6 @@ static void Brw_WriteSmallLinkToDownloadFile (const char *URL, } } -/*****************************************************************************/ -/************************ Get link to download a file ************************/ -/*****************************************************************************/ - -void Brw_GetLinkToDownloadFile (const char *PathInTree,const char *FileName,char *URL) - { - char FullPathIncludingFile[PATH_MAX + 1 + PATH_MAX + 1 + NAME_MAX + 1]; - FILE *FileURL; - char URLWithSpaces[PATH_MAX + 1]; - - /***** Construct absolute path to file in the private directory *****/ - snprintf (FullPathIncludingFile,sizeof (FullPathIncludingFile),"%s/%s/%s", - Gbl.FileBrowser.Priv.PathAboveRootFolder,PathInTree,FileName); - - if (Str_FileIs (FileName,"url")) // It's a link (URL inside a .url file) - { - /***** Open .url file *****/ - if ((FileURL = fopen (FullPathIncludingFile,"rb"))) - { - if (fgets (URLWithSpaces,PATH_MAX,FileURL) == NULL) - URLWithSpaces[0] = '\0'; - /* File is not longer needed ==> close it */ - fclose (FileURL); - } - } - else - { - /***** Create a temporary public directory used to download files *****/ - Brw_CreateDirDownloadTmp (); - - /***** Create symbolic link from temporary public directory to private file in order to gain access to it for downloading *****/ - Brw_CreateTmpPublicLinkToPrivateFile (FullPathIncludingFile,FileName); - - /***** Create URL pointing to symbolic link *****/ - snprintf (URLWithSpaces,sizeof (URLWithSpaces),"%s/%s/%s/%s", - Cfg_URL_FILE_BROWSER_TMP_PUBLIC, - Gbl.FileBrowser.TmpPubDir.L, - Gbl.FileBrowser.TmpPubDir.R, - FileName); - } - - Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces - } - /*****************************************************************************/ /**************** Change metadata of a file in a file browser ****************/ /*****************************************************************************/ @@ -9146,22 +9165,33 @@ void Brw_GetFileMetadataByCod (struct FileMetadata *FileMetadata) } /*****************************************************************************/ -/********************** Get file name from file code *************************/ +/*********************** Get file name using its code ************************/ /*****************************************************************************/ +// FileMetadata.FilCod must be filled +// This function only gets file name stored in table files, +// The rest of the fields are not filled -void Brw_GetFileNameFromFilCod (long FilCod,char *FileName,size_t FileNameSize) +void Brw_GetFileNameByCod (struct FileMetadata *FileMetadata) { - struct FileMetadata FileMetadata; + MYSQL_RES *mysql_res; + MYSQL_ROW row; - /***** Return nothing on error *****/ - FileName[0] = '\0'; // Return nothing on error + /***** Get metadata of a file from database *****/ + if (Brw_DB_GetFileNameByCod (&mysql_res,FileMetadata->FilCod)) + { + /* Get row */ + row = mysql_fetch_row (mysql_res); - /***** Get file metadata *****/ - FileMetadata.FilCod = FilCod; - Brw_GetFileMetadataByCod (&FileMetadata); + /* Get path (row[0]) */ + Str_Copy (FileMetadata->FilFolLnk.Full,row[0], + sizeof (FileMetadata->FilFolLnk.Full) - 1); + Str_SplitFullPathIntoPathAndFileName (FileMetadata->FilFolLnk.Full, + FileMetadata->FilFolLnk.Path, + FileMetadata->FilFolLnk.Name); + } - /***** Copy file name into summary string *****/ - Str_Copy (FileName,FileMetadata.FilFolLnk.Name,FileNameSize); + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ diff --git a/swad_browser.h b/swad_browser.h index 9bb177dd..373beee0 100644 --- a/swad_browser.h +++ b/swad_browser.h @@ -226,14 +226,12 @@ void Brw_SetDocumentAsHidden (void); bool Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (Brw_FileType_t FileType,const char *Path); void Brw_ShowFileMetadata (void); -void Brw_GetLinkToFile (void); - -void Brw_DownloadFile (void); void Brw_GetLinkToDownloadFile (const char *PathInTree,const char *FileName,char *URL); +void Brw_DownloadFile (void); void Brw_ChgFileMetadata (void); void Brw_GetFileMetadataByPath (struct FileMetadata *FileMetadata); void Brw_GetFileMetadataByCod (struct FileMetadata *FileMetadata); -void Brw_GetFileNameFromFilCod (long FilCod,char *FileName,size_t FileNameSize); +void Brw_GetFileNameByCod (struct FileMetadata *FileMetadata); bool Brw_GetFileTypeSizeAndDate (struct FileMetadata *FileMetadata); void Brw_GetAndUpdateFileViews (struct FileMetadata *FileMetadata); void Brw_UpdateMyFileViews (long FilCod); @@ -257,8 +255,12 @@ void Brw_CalcSizeOfDir (char *Path); void Brw_SetFullPathInTree (void); +//--------------------------- Program resources ------------------------------- +void Brw_GetLinkToFile (void); void Brw_WriteFileNameInCrsProgram (long FilCod,bool PutFormToDownload); +void Brw_GetFileNameFromFilCod (long FilCod,char *FileName,size_t FileNameSize); +//----------------------------------------------------------------------------- void Brw_CreateTmpPublicLinkToPrivateFile (const char *FullPathIncludingFile, const char *FileName); diff --git a/swad_browser_database.c b/swad_browser_database.c index 1b2f9428..9bbe830d 100644 --- a/swad_browser_database.c +++ b/swad_browser_database.c @@ -324,26 +324,17 @@ unsigned Brw_DB_GetFileMetadataByCod (MYSQL_RES **mysql_res,long FilCod) /*****************************************************************************/ /*********************** Get file name using its code ************************/ /*****************************************************************************/ -/* + unsigned Brw_DB_GetFileNameByCod (MYSQL_RES **mysql_res,long FilCod) { return (unsigned) - DB_QuerySELECT (mysql_res,"can not get file metadata", - "SELECT FilCod," // row[0] - "FileBrowser," // row[1] - "Cod," // row[2] - "ZoneUsrCod," // row[3] - "PublisherUsrCod," // row[4] - "FileType," // row[5] - "Path," // row[6] - "Hidden," // row[7] - "Public," // row[8] - "License" // row[9] + DB_QuerySELECT (mysql_res,"can not get file name", + "SELECT Path" // row[0] " FROM brw_files" " WHERE FilCod=%ld", FilCod); } -*/ + /*****************************************************************************/ /************************ Get the publisher of a subtree *********************/ /*****************************************************************************/ diff --git a/swad_browser_database.h b/swad_browser_database.h index c192190c..ba7b20e8 100644 --- a/swad_browser_database.h +++ b/swad_browser_database.h @@ -46,6 +46,7 @@ void Brw_DB_RenameChildrenFilesOrFolders (const char OldPath[PATH_MAX + 1], long Brw_DB_GetFilCodByPath (const char *Path,bool OnlyIfPublic); unsigned Brw_DB_GetFileMetadataByPath (MYSQL_RES **mysql_res,const char *Path); unsigned Brw_DB_GetFileMetadataByCod (MYSQL_RES **mysql_res,long FilCod); +unsigned Brw_DB_GetFileNameByCod (MYSQL_RES **mysql_res,long FilCod); long Brw_DB_GetPublisherOfSubtree (const char *Path); unsigned Brw_DB_GetNumFilesUsr (long UsrCod); unsigned Brw_DB_GetNumFilesInDocumZonesOfCrs (long CrsCod); diff --git a/swad_changelog.h b/swad_changelog.h index 558a916c..96505a23 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -606,10 +606,11 @@ TODO: Fix bug: error al enviar un mensaje a dos recipientes, error on duplicate TODO: Attach pdf files in multimedia. */ -#define Log_PLATFORM_VERSION "SWAD 22.8 (2022-09-18)" +#define Log_PLATFORM_VERSION "SWAD 22.9 (2022-09-19)" #define CSS_FILE "swad22.7.css" #define JS_FILE "swad21.100.js" /* + Version 22.9: Sep 19, 2022 Links to exams in program. (330491 lines) Version 22.8: Sep 18, 2022 Links to games in program. (330355 lines) Version 22.7: Sep 18, 2022 Links to calls for exams in program. Notification of a call for exam now links to the call. (330230 lines) diff --git a/swad_exam.c b/swad_exam.c index 2db12df5..c2ed133e 100644 --- a/swad_exam.c +++ b/swad_exam.c @@ -51,6 +51,7 @@ #include "swad_match.h" #include "swad_match_result.h" #include "swad_pagination.h" +#include "swad_program_database.h" #include "swad_role.h" #include "swad_test.h" #include "swad_test_visibility.h" @@ -651,10 +652,18 @@ static void Exa_PutIconToShowResultsOfExam (void *Exams) }; if (Exams) + { /***** Put icon to view sessions results *****/ if (NextAction[Gbl.Usrs.Me.Role.Logged]) Ico_PutContextualIconToShowResults (NextAction[Gbl.Usrs.Me.Role.Logged],ExaRes_RESULTS_BOX_ID, Exa_PutParams,Exams); + + + /***** Link to get resource link *****/ + if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) // Only if I am superuser // TODO: Include teachers + Ico_PutContextualIconToGetLink (ActReqLnkExa,NULL, + Exa_PutParams,Exams); + } } /*****************************************************************************/ @@ -1629,3 +1638,85 @@ void Exa_GetAndShowExamsStats (void) /***** End table and box *****/ Box_BoxTableEnd (); } + +/*****************************************************************************/ +/***************************** Get link to exam ******************************/ +/*****************************************************************************/ + +void Exa_GetLinkToExam (void) + { + extern const char *Txt_Link_to_resource_X_copied_into_clipboard; + struct Exa_Exams Exams; + long ExaCod; + char Title[Gam_MAX_BYTES_TITLE + 1]; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Err_WrongExamExit (); + ExaCod = Exams.ExaCod; + + /***** Get exam title *****/ + Exa_DB_GetExamTitle (ExaCod,Title); + + /***** Copy link to exam into resource clipboard *****/ + Prg_DB_CopyToClipboard (PrgRsc_EXAM,ExaCod); + + /***** Write sucess message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Link_to_resource_X_copied_into_clipboard, + Title); + + /***** Show exams again *****/ + Exa_ListAllExams (&Exams); + } + +/*****************************************************************************/ +/*********************** Write exam in course program ************************/ +/*****************************************************************************/ + +void Exa_WriteExamInCrsProgram (long ExaCod,bool PutFormToGo) + { + extern const char *Txt_Actions[Act_NUM_ACTIONS]; + char Title[Gam_MAX_BYTES_TITLE + 1]; + + /***** Get exam title *****/ + Exa_DB_GetExamTitle (ExaCod,Title); + + /***** Begin form to go to exam *****/ + if (PutFormToGo) + { + Frm_BeginForm (ActSeeExa); + Exa_PutParamExamCod (ExaCod); + HTM_BUTTON_Submit_Begin (Txt_Actions[ActSeeExa], + "class=\"LM BT_LINK PRG_RSC_%s\"", + The_GetSuffix ()); + } + + /***** Write Name of the course and date of exam *****/ + HTM_Txt (Title); + + /***** End form to download file *****/ + if (PutFormToGo) + { + /* End form */ + HTM_BUTTON_End (); + + Frm_EndForm (); + } + } + +/*****************************************************************************/ +/*********************** Get exam title from exam code ***********************/ +/*****************************************************************************/ + +void Exa_GetTitleFromExaCod (long ExaCod,char *Title,size_t TitleSize) + { + char TitleFromDB[Exa_MAX_BYTES_TITLE + 1]; + + /***** Get exam title *****/ + Exa_DB_GetExamTitle (ExaCod,TitleFromDB); + Str_Copy (Title,TitleFromDB,TitleSize); + } diff --git a/swad_exam.h b/swad_exam.h index 36a52b79..ddd1a844 100644 --- a/swad_exam.h +++ b/swad_exam.h @@ -87,4 +87,9 @@ bool Exa_CheckIfEditable (const struct Exa_Exam *Exam); //-------------------------------- Figures ------------------------------------ void Exa_GetAndShowExamsStats (void); +//--------------------------- Program resources ------------------------------- +void Exa_GetLinkToExam (void); +void Exa_WriteExamInCrsProgram (long ExaCod,bool PutFormToGo); +void Exa_GetTitleFromExaCod (long ExaCod,char *Title,size_t TitleSize); + #endif diff --git a/swad_exam_database.c b/swad_exam_database.c index 0b2b5dbe..70666f02 100644 --- a/swad_exam_database.c +++ b/swad_exam_database.c @@ -214,6 +214,21 @@ unsigned Exa_DB_GetExamStartEnd (MYSQL_RES **mysql_res,long ExaCod) ExaCod); } +/*****************************************************************************/ +/*********************** Get exam title from database ************************/ +/*****************************************************************************/ + +void Exa_DB_GetExamTitle (long ExaCod,char Title[Exa_MAX_BYTES_TITLE + 1]) + { + DB_QuerySELECTString (Title,Exa_MAX_BYTES_TITLE,"can not get exam title", + "SELECT Title" // row[0] + " FROM exa_exams" + " WHERE ExaCod=%ld" + " AND CrsCod=%ld", // Extra check + ExaCod, + Gbl.Hierarchy.Crs.CrsCod); + } + /*****************************************************************************/ /********************** Get exam text from database **************************/ /*****************************************************************************/ diff --git a/swad_exam_database.h b/swad_exam_database.h index e698f075..6144da87 100644 --- a/swad_exam_database.h +++ b/swad_exam_database.h @@ -44,6 +44,7 @@ void Exa_DB_HideOrUnhideExam (long ExaCod,bool Hide); unsigned Exa_DB_GetListExams (MYSQL_RES **mysql_res,Exa_Order_t SelectedOrder); unsigned Exa_DB_GetDataOfExamByCod (MYSQL_RES **mysql_res,long ExaCod); unsigned Exa_DB_GetExamStartEnd (MYSQL_RES **mysql_res,long ExaCod); +void Exa_DB_GetExamTitle (long ExaCod,char Title[Exa_MAX_BYTES_TITLE + 1]); void Exa_DB_GetExamTxt (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); bool Exa_DB_CheckIfSimilarExamExists (long CrsCod,long ExaCod,const char *Title); unsigned Exa_DB_GetNumCoursesWithExams (HieLvl_Level_t Scope); diff --git a/swad_game.c b/swad_game.c index f3614d65..15cf81e5 100644 --- a/swad_game.c +++ b/swad_game.c @@ -2359,27 +2359,25 @@ void Gam_GetLinkToGame (void) { extern const char *Txt_Link_to_resource_X_copied_into_clipboard; struct Gam_Games Games; - struct Gam_Game Game; + long GamCod; + char Title[Gam_MAX_BYTES_TITLE + 1]; /***** Reset games context *****/ Gam_ResetGames (&Games); - /***** Reset game *****/ - Gam_ResetGame (&Game); - /***** Get parameters *****/ - if ((Game.GamCod = Gam_GetParams (&Games)) <= 0) + if ((GamCod = Gam_GetParams (&Games)) <= 0) Err_WrongGameExit (); - /***** Get data of the game from database *****/ - Gam_GetDataOfGameByCod (&Game); + /***** Get game title *****/ + Gam_DB_GetGameTitle (GamCod,Title); - /***** Copy link to call for exam into resource clipboard *****/ - Prg_DB_CopyToClipboard (PrgRsc_GAME,Game.GamCod); + /***** Copy link to game into resource clipboard *****/ + Prg_DB_CopyToClipboard (PrgRsc_GAME,GamCod); /***** Write sucess message *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Link_to_resource_X_copied_into_clipboard, - Game.Title); + Title); /***** Show games again *****/ Gam_ListAllGames (&Games); @@ -2397,12 +2395,12 @@ void Gam_WriteGameInCrsProgram (long GamCod,bool PutFormToGo) /***** Get game title *****/ Gam_DB_GetGameTitle (GamCod,Title); - /***** Begin form to download file *****/ + /***** Begin form to go to game *****/ if (PutFormToGo) { Frm_BeginForm (ActSeeGam); Gam_PutParamGameCod (GamCod); - HTM_BUTTON_Submit_Begin (Txt_Actions[ActSeeOneCfe], + HTM_BUTTON_Submit_Begin (Txt_Actions[ActSeeGam], "class=\"LM BT_LINK PRG_RSC_%s\"", The_GetSuffix ()); } @@ -2421,7 +2419,7 @@ void Gam_WriteGameInCrsProgram (long GamCod,bool PutFormToGo) } /*****************************************************************************/ -/************** Get game title from call for exam code ***************/ +/*********************** Get game title from game code ***********************/ /*****************************************************************************/ void Gam_GetTitleFromGamCod (long GamCod,char *Title,size_t TitleSize) diff --git a/swad_game_database.c b/swad_game_database.c index fac0feaa..579381d1 100644 --- a/swad_game_database.c +++ b/swad_game_database.c @@ -232,7 +232,7 @@ void Gam_DB_GetGameTitle (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1]) "SELECT Title" // row[0] " FROM gam_games" " WHERE GamCod=%ld" - " AND gam_games.CrsCod=%ld", // Extra check + " AND CrsCod=%ld", // Extra check GamCod, Gbl.Hierarchy.Crs.CrsCod); } diff --git a/swad_program_resource.c b/swad_program_resource.c index 5da6f56f..a5ab9f3a 100644 --- a/swad_program_resource.c +++ b/swad_program_resource.c @@ -30,6 +30,7 @@ #include "swad_browser.h" #include "swad_call_for_exam.h" #include "swad_error.h" +#include "swad_exam.h" #include "swad_form.h" #include "swad_game.h" #include "swad_global.h" @@ -1021,7 +1022,7 @@ static void PrgRsc_WriteLinkName (const struct Prg_Link *Link,bool PutForm) Cfe_WriteCallForExamInCrsProgram (Link->Cod,PutForm); break; case PrgRsc_EXAM: - Ale_ShowAlert (Ale_ERROR,"Not implemented!"); + Exa_WriteExamInCrsProgram (Link->Cod,PutForm); break; case PrgRsc_GAME: Gam_WriteGameInCrsProgram (Link->Cod,PutForm); @@ -1069,7 +1070,9 @@ static void PrgRsc_GetResourceTitleFromLink (struct Prg_Item *Item) sizeof (Item->Resource.Title) - 1); break; case PrgRsc_EXAM: - Ale_ShowAlert (Ale_ERROR,"Not implemented!"); + Exa_GetTitleFromExaCod (Item->Resource.Link.Cod, + Item->Resource.Title, + sizeof (Item->Resource.Title) - 1); break; case PrgRsc_GAME: Gam_GetTitleFromGamCod (Item->Resource.Link.Cod, diff --git a/swad_text_action.c b/swad_text_action.c index 7f2aecc3..beadcfbb 100644 --- a/swad_text_action.c +++ b/swad_text_action.c @@ -11790,6 +11790,29 @@ const char *Txt_Actions[Act_NUM_ACTIONS] = "Unhide exam" // Precisa de tradução #elif L==10 // tr "Unhide exam" // Çeviri lazim! +#endif + , + [ActReqLnkExa] = +#if L==1 // ca + "Copy link to exam" // Necessita traducció +#elif L==2 // de + "Copy link to exam" // Need Übersetzung +#elif L==3 // en + "Copy link to exam" +#elif L==4 // es + "Copiar enlace a examen" +#elif L==5 // fr + "Copy link to exam" // Besoin de traduction +#elif L==6 // gn + "Copiar enlace a examen" // Okoteve traducción +#elif L==7 // it + "Copy link to exam" // Bisogno di traduzione +#elif L==8 // pl + "Copy link to exam" // Potrzebujesz tlumaczenie +#elif L==9 // pt + "Copy link to exam" // Precisa de tradução +#elif L==10 // tr + "Copy link to exam" // Çeviri lazim! #endif , [ActFrmNewExaSet] =