From 252a8178fae6f52ac3352a52064564ba690da41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Ca=C3=B1as=20Vargas?= Date: Thu, 21 Mar 2019 20:04:01 +0100 Subject: [PATCH] Version18.85 --- css/{swad18.83.css => swad18.85.css} | 35 +- js/{swad18.80.js => swad18.85.js} | 88 ++++- sql/swad.sql | 2 +- swad_changelog.h | 15 +- swad_database.c | 20 +- swad_media.c | 551 ++++++++++++++++++--------- swad_media.h | 3 +- swad_test.c | 38 +- swad_text.c | 4 +- 9 files changed, 513 insertions(+), 243 deletions(-) rename css/{swad18.83.css => swad18.85.css} (98%) rename js/{swad18.80.js => swad18.85.js} (96%) diff --git a/css/swad18.83.css b/css/swad18.85.css similarity index 98% rename from css/swad18.83.css rename to css/swad18.85.css index c3661596..ffcdb921 100644 --- a/css/swad18.83.css +++ b/css/swad18.85.css @@ -2774,6 +2774,29 @@ a:hover img.CENTRE_PHOTO_SHOW height:100%; } + /* Slideshare: + 487 / 599 = 0,813021703 + 422 / 514 = 0,821011673 + 357 / 429 = 0,832167832 + 292 / 344 = 0,848837209 */ +.MED_EMBED_CONT /* Adjust container height to get a 16:9 aspect ratio */ + { + position:relative; + box-sizing:border-box; + margin:10px 0; + padding-bottom:56.25%; /* percentage relative to width */ + } +.MED_EMBED_CONT iframe, +.MED_EMBED_CONT object, +.MED_EMBED_CONT embed + { + position:absolute; + top:0; + left:0; + width:100%; + height:100%; + } + /********** Author of assignments, attendance, messages, surveys... **********/ .AUTHOR_1_LINE { @@ -2898,12 +2921,12 @@ a:hover img.CENTRE_PHOTO_SHOW } @media only screen and (min-width: 800px) { /* For tablets and desktop */ - .TL_WIDTH {width:536px;} - .TL_RIGHT_WIDTH {width:480px;} - .TL_RIGHT_AUTHOR_WIDTH {width:320px;} - .TL_POST_MED_WIDTH {width:440px;} - .TL_COMMENT_WIDTH {width:440px;} - .TL_COMMENT_AUTHOR_WIDTH {width:280px;} + .TL_WIDTH {width:566px;} /* 536 -> 566 */ + .TL_RIGHT_WIDTH {width:510px;} /* 480 -> 510 */ + .TL_RIGHT_AUTHOR_WIDTH {width:350px;} /* 320 -> 350 */ + .TL_POST_MED_WIDTH {width:470px;} /* 440 -> 470 */ + .TL_COMMENT_WIDTH {width:470px;} /* 440 -> 470 */ + .TL_COMMENT_AUTHOR_WIDTH {width:310px;} /* 280 -> 310 */ } .TL_NEW_PUB diff --git a/js/swad18.80.js b/js/swad18.85.js similarity index 96% rename from js/swad18.80.js rename to js/swad18.85.js index 2c5d008a..6414e3e4 100644 --- a/js/swad18.80.js +++ b/js/swad18.85.js @@ -772,24 +772,31 @@ function AJAXCreateObject () { /*****************************************************************************/ function mediaClickOnActivateUpload (id) { - var par_upl = document.getElementById (id + '_par_upl'); + var par_upl = document.getElementById (id + '_par_upl'); if (par_upl.disabled) { // Click on highlighted icon - var par_emb = document.getElementById (id + '_par_emb'); + // par_upl already got + var par_you = document.getElementById (id + '_par_you'); + var par_emb = document.getElementById (id + '_par_emb'); + var ico_upl = document.getElementById (id + '_ico_upl'); + var ico_you = document.getElementById (id + '_ico_you'); var ico_emb = document.getElementById (id + '_ico_emb'); + var fil = document.getElementById (id + '_fil'); var url = document.getElementById (id + '_url'); var tit = document.getElementById (id + '_tit'); - // Disable embed and enable upload - par_emb.disabled = true; // Disable embed + // Enable embed, disable others par_upl.disabled = false; // Enable upload + par_you.disabled = true; // Disable youtube + par_emb.disabled = true; // Disable embed ico_upl.className = 'PREF_ON'; // Highlighted upload icon + ico_you.className = 'PREF_OFF'; // Normal youtube icon ico_emb.className = 'PREF_OFF'; // Normal embed icon - fil.style.display = ''; // Show file input + fil.style.display = ''; // Show file input fil.disabled = false; // Enable file input url.style.display = ''; // Show URL input @@ -799,26 +806,33 @@ function mediaClickOnActivateUpload (id) { tit.disabled = false; // Enable title input } else // Click on shadowed icon - mediaDisableUploadAndEmbed (id); + mediaDisableAll (id); } -function mediaClickOnActivateEmbed (id) { - var par_emb = document.getElementById (id + '_par_emb'); +function mediaClickOnActivateYoutube (id) { + var par_you = document.getElementById (id + '_par_you'); - if (par_emb.disabled) { // Click on highlighted icon + if (par_you.disabled) { // Click on highlighted icon var par_upl = document.getElementById (id + '_par_upl'); + // par_you already got + var par_emb = document.getElementById (id + '_par_emb'); + var ico_upl = document.getElementById (id + '_ico_upl'); + var ico_you = document.getElementById (id + '_ico_you'); var ico_emb = document.getElementById (id + '_ico_emb'); + var fil = document.getElementById (id + '_fil'); var url = document.getElementById (id + '_url'); var tit = document.getElementById (id + '_tit'); - // Disable upload and enable embed + // Enable youtube, disable others par_upl.disabled = true; // Disable upload - par_emb.disabled = false; // Enable embed + par_you.disabled = false; // Enable youtube + par_emb.disabled = true; // Disable embed - ico_emb.className = 'PREF_ON'; // Highlighted embed icon ico_upl.className = 'PREF_OFF'; // Normal upload icon + ico_you.className = 'PREF_ON'; // Highlighted youtube icon + ico_emb.className = 'PREF_OFF'; // Normal embed icon fil.style.display = 'none'; // Hide file input fil.disabled = true; // Disable file input @@ -830,22 +844,66 @@ function mediaClickOnActivateEmbed (id) { tit.disabled = true; // Disable title input } else // Click on shadowed icon - mediaDisableUploadAndEmbed (id); + mediaDisableAll (id); } -function mediaDisableUploadAndEmbed (id) { - var par_upl = document.getElementById (id + '_par_upl'); +function mediaClickOnActivateEmbed (id) { var par_emb = document.getElementById (id + '_par_emb'); + + if (par_emb.disabled) { // Click on highlighted icon + var par_upl = document.getElementById (id + '_par_upl'); + var par_you = document.getElementById (id + '_par_you'); + // par_emb already got + + var ico_upl = document.getElementById (id + '_ico_upl'); + var ico_you = document.getElementById (id + '_ico_you'); + var ico_emb = document.getElementById (id + '_ico_emb'); + + var fil = document.getElementById (id + '_fil'); + var url = document.getElementById (id + '_url'); + var tit = document.getElementById (id + '_tit'); + + // Enable embed, disable others + par_upl.disabled = true; // Disable upload + par_you.disabled = true; // Disable youtube + par_emb.disabled = false; // Enable embed + + ico_upl.className = 'PREF_OFF'; // Normal upload icon + ico_you.className = 'PREF_OFF'; // Normal youtube icon + ico_emb.className = 'PREF_ON'; // Highlighted embed icon + + fil.style.display = 'none'; // Hide file input + fil.disabled = true; // Disable file input + + url.style.display = ''; // Show URL input + url.disabled = false; // Enable URL input + + tit.style.display = 'none'; // Hide title input + tit.disabled = true; // Disable title input + } + else // Click on shadowed icon + mediaDisableAll (id); +} + +function mediaDisableAll (id) { + var par_upl = document.getElementById (id + '_par_upl'); + var par_you = document.getElementById (id + '_par_you'); + var par_emb = document.getElementById (id + '_par_emb'); + var ico_upl = document.getElementById (id + '_ico_upl'); + var ico_you = document.getElementById (id + '_ico_you'); var ico_emb = document.getElementById (id + '_ico_emb'); + var fil = document.getElementById (id + '_fil'); var url = document.getElementById (id + '_url'); var tit = document.getElementById (id + '_tit'); par_upl.disabled = true; // Disable upload + par_you.disabled = true; // Disable youtube par_emb.disabled = true; // Disable embed ico_upl.className = 'PREF_OFF'; // Normal upload icon + ico_you.className = 'PREF_OFF'; // Normal youtube icon ico_emb.className = 'PREF_OFF'; // Normal embed icon fil.style.display = 'none'; // Hide file input diff --git a/sql/swad.sql b/sql/swad.sql index 384d95f5..9f1b1c5c 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -797,7 +797,7 @@ CREATE TABLE IF NOT EXISTS marks_properties ( -- CREATE TABLE IF NOT EXISTS media ( MedCod INT NOT NULL AUTO_INCREMENT, - Type ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none', + Type ENUM('none','jpg','gif','mp4','webm','ogg','youtube','embed') NOT NULL DEFAULT 'none', Name VARCHAR(43) NOT NULL DEFAULT '', URL VARCHAR(255) NOT NULL DEFAULT '', Title VARCHAR(2047) NOT NULL DEFAULT '', diff --git a/swad_changelog.h b/swad_changelog.h index 8bee57af..5a298829 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -459,10 +459,19 @@ En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 18.84.1 (2019-03-20)" -#define CSS_FILE "swad18.83.css" -#define JS_FILE "swad18.80.js" +#define Log_PLATFORM_VERSION "SWAD 18.85 (2019-03-21)" +#define CSS_FILE "swad18.85.css" +#define JS_FILE "swad18.85.js" /* + Version 18.85: Mar 21, 2019 New media: other embed media. + Width of timeline increased 30 pixels. + Fixed bug in creation of a test question, reported by Javier Fernández Baldomero. (240825 lines) + 1 change necessary in database: +ALTER TABLE media CHANGE COLUMN Type Type ENUM('none','jpg','gif','mp4','webm','ogg','youtube','embed') NOT NULL DEFAULT 'none'; + + Copy the following icon to icon public directory: +sudo cp icon/code.svg /var/www/html/swad/icon/ + Version 18.84.1: Mar 20, 2019 Added MIME type application/vnd.wolfram.mathematica.package, reported by José Martínez Aroza. Conversion of BMP images to JPG, reported by José Martínez Aroza. (240587 lines) Version 18.84: Mar 20, 2019 Temporary directories for download are created in a two level system to avoid overflow number of directories. (240582 lines) diff --git a/swad_database.c b/swad_database.c index 2cd04ac1..8a2c72e6 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1712,20 +1712,20 @@ mysql> DESCRIBE marks_properties; /***** Table media *****/ /* mysql> DESCRIBE media; -+--------+-------------------------------------------------------+------+-----+---------+----------------+ -| Field | Type | Null | Key | Default | Extra | -+--------+-------------------------------------------------------+------+-----+---------+----------------+ -| MedCod | int(11) | NO | PRI | NULL | auto_increment | -| Type | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | MUL | none | | -| Name | varchar(43) | NO | | | | -| URL | varchar(255) | NO | | | | -| Title | varchar(2047) | NO | | | | -+--------+-------------------------------------------------------+------+-----+---------+----------------+ ++--------+---------------------------------------------------------------+------+-----+---------+----------------+ +| Field | Type | Null | Key | Default | Extra | ++--------+---------------------------------------------------------------+------+-----+---------+----------------+ +| MedCod | int(11) | NO | PRI | NULL | auto_increment | +| Type | enum('none','jpg','gif','mp4','webm','ogg','youtube','embed') | NO | MUL | none | | +| Name | varchar(43) | NO | | | | +| URL | varchar(255) | NO | | | | +| Title | varchar(2047) | NO | | | | ++--------+---------------------------------------------------------------+------+-----+---------+----------------+ 5 rows in set (0.01 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS media (" "MedCod INT NOT NULL AUTO_INCREMENT," - "Type ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," + "Type ENUM('none','jpg','gif','mp4','webm','ogg','youtube','embed') NOT NULL DEFAULT 'none'," "Name VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "URL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "Title VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE diff --git a/swad_media.c b/swad_media.c index 49a08332..894caf36 100644 --- a/swad_media.c +++ b/swad_media.c @@ -62,6 +62,7 @@ const char *Med_StringsTypeDB[Med_NUM_TYPES] = "webm", // Med_WEBM "ogg", // Med_OGG "youtube", // Med_YOUTUBE + "embed", // Med_EMBED }; const char *Med_Extensions[Med_NUM_TYPES] = @@ -73,6 +74,7 @@ const char *Med_Extensions[Med_NUM_TYPES] = "webm", // Med_WEBM "ogg", // Med_OGG "", // Med_YOUTUBE + "", // Med_EMBED }; #define Med_MAX_SIZE_GIF (5UL * 1024UL * 1024UL) // 5 MiB @@ -82,13 +84,14 @@ const char *Med_Extensions[Med_NUM_TYPES] = /****************************** Internal types *******************************/ /*****************************************************************************/ -#define Med_NUM_FORM_TYPES 3 +#define Med_NUM_FORM_TYPES 4 typedef enum { - Med_FORM_UNKNOWN = 0, + Med_FORM_NONE = 0, Med_FORM_FILE = 1, - Med_FORM_EMBED = 2, + Med_FORM_YOUTUBE = 2, + Med_FORM_EMBED = 3, } Med_FormType_t; /*****************************************************************************/ @@ -131,6 +134,8 @@ static int Med_ResizeImage (struct Media *Media, static int Med_GetFirstFrame (const char PathFileOriginal[PATH_MAX + 1], const char PathFileProcessed[PATH_MAX + 1]); +static void Med_GetAndProcessYouTubeFromForm (const char *ParamURL, + struct Media *Media); static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, struct Media *Media); @@ -148,6 +153,7 @@ static void Med_ShowVideo (struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia); static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia); +static void Med_ShowEmbed (struct Media *Media,const char *ClassMedia); static Med_Type_t Med_GetTypeFromStrInDB (const char *Str); static Med_Type_t Med_GetTypeFromExtAndMIME (const char *Extension, @@ -335,11 +341,12 @@ void Med_PutMediaUploader (int NumMediaInForm,const char *ClassInput) /***** Action to perform on media *****/ Par_PutHiddenParamUnsigned (ParamUploadMedia.Action,(unsigned) Med_ACTION_NEW_MEDIA); - /***** Start icons *****/ + /***** Icons *****/ + /* Start icons */ fprintf (Gbl.F.Out,"
" // icons containers "
"); // icons container - /***** Upload icon *****/ + /* Upload icon */ fprintf (Gbl.F.Out,"
_ico_upl " class=\"PREF_OFF\">" "_ico_you + " class=\"PREF_OFF\">" + "\"%s\"" + "
", // _ico_you + Id, + Cfg_URL_ICON_PUBLIC, + "YouTube","YouTube", + Id); + + /* Embed icon */ + fprintf (Gbl.F.Out,"
_ico_emb + " class=\"PREF_OFF\">" + "\"%s\"" + "
", // _ico_emb + Id, + Cfg_URL_ICON_PUBLIC, + "Embed","Embed", + Id); + + /* End icons */ + fprintf (Gbl.F.Out,"
" // icons container + "
"); // icons containers + + /***** Hidden field with form type *****/ + /* Upload file */ fprintf (Gbl.F.Out,"_par_upl " name=\"%s\" value=\"%u\"" @@ -360,28 +398,15 @@ void Med_PutMediaUploader (int NumMediaInForm,const char *ClassInput) Id,ParamUploadMedia.FormType, (unsigned) Med_FORM_FILE); - /***** Embed icon *****/ - fprintf (Gbl.F.Out,"
_ico_emb - " class=\"PREF_OFF\">" - "\"%s\"" - "
", // _ico_emb - Id, - Cfg_URL_ICON_PUBLIC, - "YouTube","YouTube", - Id); + /* YouTube embedded video */ + fprintf (Gbl.F.Out,"_par_you + " name=\"%s\" value=\"%u\"" + " disabled=\"disabled\" />", + Id,ParamUploadMedia.FormType, + (unsigned) Med_FORM_YOUTUBE); - /***** End icons *****/ - fprintf (Gbl.F.Out,"" // icons container - ""); // icons containers - - /***** Start input fields *****/ - fprintf (Gbl.F.Out,"
", // input fields - ClassInput); - - /***** Form type *****/ + /* Other embedded media */ fprintf (Gbl.F.Out,"_par_emb " name=\"%s\" value=\"%u\"" @@ -389,6 +414,10 @@ void Med_PutMediaUploader (int NumMediaInForm,const char *ClassInput) Id,ParamUploadMedia.FormType, (unsigned) Med_FORM_EMBED); + /***** Start input fields *****/ + fprintf (Gbl.F.Out,"
", // input fields + ClassInput); + /***** Media file *****/ fprintf (Gbl.F.Out,"_fil " name=\"%s\" accept=\"image/,video/\"" @@ -471,37 +500,35 @@ void Med_GetMediaFromForm (int NumMediaInForm,struct Media *Media, Usr_GetURLFromForm (ParamUploadMedia.URL,Media); Usr_GetTitleFromForm (ParamUploadMedia.Title,Media); } - else - { - /* Create alert with warning */ - Ale_CreateAlert (Ale_WARNING,SectionForAlerts, - Txt_Error_sending_or_processing_image_video); + break; + case Med_FORM_YOUTUBE: + Media->Action = Med_ACTION_NEW_MEDIA; - /* Reset media (no media will be saved into database) */ - Med_ResetMedia (Media); - } + /* Get and process embed YouTube video from form */ + Med_GetAndProcessYouTubeFromForm (ParamUploadMedia.URL,Media); break; case Med_FORM_EMBED: Media->Action = Med_ACTION_NEW_MEDIA; - /* Get and process embed URL from form */ + /* Get and process other embed media from form */ Med_GetAndProcessEmbedFromForm (ParamUploadMedia.URL,Media); - - /* Check status of media after getting and processing it */ - if (Media->Status != Med_PROCESSED) - { - /* Create alert with warning */ - Ale_CreateAlert (Ale_WARNING,SectionForAlerts, - Txt_Error_sending_or_processing_image_video); - - /* Reset media (no media will be saved into database) */ - Med_ResetMedia (Media); - } break; default: // No media form selected Media->Action = Med_ACTION_NO_MEDIA; break; } + + /***** Check status of media *****/ + if (FormType != Med_FORM_NONE && // A media form is selected + Media->Status != Med_PROCESSED) // No media successfully processed + { + /* Create alert with warning */ + Ale_CreateAlert (Ale_WARNING,SectionForAlerts, + Txt_Error_sending_or_processing_image_video); + + /* Reset media (no media will be saved into database) */ + Med_ResetMedia (Media); + } break; case Med_ACTION_KEEP_MEDIA: // Keep current image/video unchanged Media->Action = Med_ACTION_KEEP_MEDIA; @@ -580,7 +607,7 @@ static Med_FormType_t Usr_GetFormTypeFromForm (struct ParamUploadMedia *ParamUpl return (Med_FormType_t) Par_GetParToUnsignedLong (ParamUploadMedia->FormType, 0, Med_NUM_FORM_TYPES - 1, - (unsigned long) Med_FORM_UNKNOWN); + (unsigned long) Med_FORM_NONE); } /*****************************************************************************/ @@ -961,11 +988,11 @@ static int Med_GetFirstFrame (const char PathFileOriginal[PATH_MAX + 1], } /*****************************************************************************/ -/**************************** Get media from form ****************************/ +/************* Get link from form and transform to YouTube code **************/ /*****************************************************************************/ -static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, - struct Media *Media) +static void Med_GetAndProcessYouTubeFromForm (const char *ParamURL, + struct Media *Media) { extern const char Str_BIN_TO_BASE64URL[64 + 1]; char *PtrHost = NULL; @@ -980,6 +1007,7 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, FULL, // www.youtube.com/watch? EMBED, // www.youtube.com/embed/ } YouTube = WRONG; + bool CodeFound = false; /***** Set media status *****/ Media->Status = Med_STATUS_NONE; @@ -1101,20 +1129,77 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, CodeLength = strspn (PtrCode,Str_BIN_TO_BASE64URL); if (CodeLength > 0 && CodeLength <= Med_BYTES_NAME) - { - /***** Success! *****/ - /* Copy code */ - strncpy (Media->Name,PtrCode,CodeLength); - Media->Name[CodeLength] = '\0'; - - Media->Type = Med_YOUTUBE; - Media->Status = Med_PROCESSED; - } + CodeFound = true; // Success! } } } } } + + /***** Set or reset media *****/ + if (CodeFound) + { + /* Copy code */ + strncpy (Media->Name,PtrCode,CodeLength); + Media->Name[CodeLength] = '\0'; + + /* Set media type and status */ + Media->Type = Med_EMBED; + Media->Status = Med_PROCESSED; + } + else + /* Reset media */ + Med_ResetMedia (Media); + } + +/*****************************************************************************/ +/************************ Get embed link from form ***************************/ +/*****************************************************************************/ + +static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, + struct Media *Media) + { + extern const char Str_BIN_TO_BASE64URL[64 + 1]; + char *PtrHost = NULL; + bool URLFound = false; + + /***** Set media status *****/ + Media->Status = Med_STATUS_NONE; + + /***** Get embed URL from form *****/ + Usr_GetURLFromForm (ParamURL,Media); + + /***** Process URL trying to convert it to a YouTube embed URL *****/ + if (Media->URL) + if (Media->URL[0]) // URL given by user is not empty + { + /* Examples of valid embed URLs: + //www.slideshare.net/slideshow/embed_code/key/yngasD9sIZ7GQV + */ + /***** Step 1: Skip scheme *****/ + if (!strncasecmp (Media->URL,"https://",8)) // URL starts by https:// + PtrHost = &Media->URL[8]; + else if (!strncasecmp (Media->URL,"http://" ,7)) // URL starts by http:// + PtrHost = &Media->URL[7]; + else if (!strncasecmp (Media->URL,"//" ,2)) // URL starts by // + PtrHost = &Media->URL[2]; + + /***** Check if a URL is found *****/ + if (PtrHost) + if (PtrHost[0]) + URLFound = true; // Success! + } + + /***** Set or reset media *****/ + if (URLFound) + { + /* Set media type and status */ + Media->Type = Med_EMBED; + Media->Status = Med_PROCESSED; + } + else + /* Reset media */ + Med_ResetMedia (Media); } /*****************************************************************************/ @@ -1172,49 +1257,58 @@ void Med_MoveMediaToDefinitiveDir (struct Media *Media) /***** Check trivial case *****/ if (Media->Status == Med_PROCESSED) { - if (Media->Type == Med_YOUTUBE) - // Nothing to do with files ==> Processing successfully finished - Media->Status = Med_MOVED; // Success - else + switch (Media->Type) { - /***** Create private subdirectory for media if it does not exist *****/ - snprintf (PathMedPriv,sizeof (PathMedPriv), - "%s/%c%c", - Cfg_PATH_MEDIA_PRIVATE, - Media->Name[0], - Media->Name[1]); - Fil_CreateDirIfNotExists (PathMedPriv); + case Med_JPG: + case Med_GIF: + case Med_MP4: + case Med_WEBM: + case Med_OGG: + /***** Create private subdirectory for media if it does not exist *****/ + snprintf (PathMedPriv,sizeof (PathMedPriv), + "%s/%c%c", + Cfg_PATH_MEDIA_PRIVATE, + Media->Name[0], + Media->Name[1]); + Fil_CreateDirIfNotExists (PathMedPriv); - /***** Move files *****/ - switch (Media->Type) - { - case Med_JPG: - /* Move JPG */ - if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, - Med_Extensions[Med_JPG])) - Media->Status = Med_MOVED; // Success - break; - case Med_GIF: - /* Move PNG */ - if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, - "png")) - /* Move GIF */ + /***** Move files *****/ + switch (Media->Type) + { + case Med_JPG: + /* Move JPG */ if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, - Med_Extensions[Med_GIF])) + Med_Extensions[Med_JPG])) Media->Status = Med_MOVED; // Success - break; - case Med_MP4: - case Med_WEBM: - case Med_OGG: - /* Move MP4 or WEBM or OGG */ - if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, - Med_Extensions[Media->Type])) - Media->Status = Med_MOVED; // Success - break; - default: - Lay_ShowErrorAndExit ("Wrong media type."); - break; // Not reached - } + break; + case Med_GIF: + /* Move PNG */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, + "png")) + /* Move GIF */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, + Med_Extensions[Med_GIF])) + Media->Status = Med_MOVED; // Success + break; + case Med_MP4: + case Med_WEBM: + case Med_OGG: + /* Move MP4 or WEBM or OGG */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPriv, + Med_Extensions[Media->Type])) + Media->Status = Med_MOVED; // Success + break; + default: + break; + } + break; + case Med_YOUTUBE: + case Med_EMBED: + // Nothing to do with files ==> Processing successfully finished + Media->Status = Med_MOVED; // Success + break; + default: + break; } } @@ -1276,7 +1370,7 @@ void Med_StoreMediaInDB (struct Media *Media) " VALUES" " ('%s','%s','%s','%s')", Med_GetStringTypeForDB (Media->Type), - Media->Name, + Media->Name ? Media->Name : "", Media->URL ? Media->URL : "", Media->Title ? Media->Title : ""); Media->Status = Med_STORED_IN_DB; @@ -1301,56 +1395,70 @@ void Med_ShowMedia (struct Media *Media, /***** Start media container *****/ fprintf (Gbl.F.Out,"
",ClassContainer); - if (Media->Type == Med_YOUTUBE) - /***** Show media *****/ - Med_ShowYoutube (Media,ClassMedia); - else // Uploaded file + switch (Media->Type) { - /***** If no media to show ==> nothing to do *****/ - if (!Media->Name) - return; - if (!Media->Name[0]) - return; + case Med_JPG: + case Med_GIF: + case Med_MP4: + case Med_WEBM: + case Med_OGG: + /***** Show uploaded file *****/ + /* If no media to show ==> nothing to do */ + if (!Media->Name) + return; + if (!Media->Name[0]) + return; - /***** Start optional link to external URL *****/ - PutLink = false; - if (Media->URL) - if (Media->URL[0]) - PutLink = true; - if (PutLink) - fprintf (Gbl.F.Out,"",Media->URL); + /* Start optional link to external URL */ + PutLink = false; + if (Media->URL) + if (Media->URL[0]) + PutLink = true; + if (PutLink) + fprintf (Gbl.F.Out,"",Media->URL); - /***** Create a temporary public directory used to show the media *****/ - Brw_CreateDirDownloadTmp (); + /* Create a temporary public directory used to show the media */ + Brw_CreateDirDownloadTmp (); - /***** Build path to private directory with the media *****/ - snprintf (PathMedPriv,sizeof (PathMedPriv), - "%s/%c%c", - Cfg_PATH_MEDIA_PRIVATE, - Media->Name[0], - Media->Name[1]); + /* Build path to private directory with the media */ + snprintf (PathMedPriv,sizeof (PathMedPriv), + "%s/%c%c", + Cfg_PATH_MEDIA_PRIVATE, + Media->Name[0], + Media->Name[1]); - /***** Show media *****/ - switch (Media->Type) - { - case Med_JPG: - Med_ShowJPG (Media,PathMedPriv,ClassMedia); - break; - case Med_GIF: - Med_ShowGIF (Media,PathMedPriv,ClassMedia); - break; - case Med_MP4: - case Med_WEBM: - case Med_OGG: - Med_ShowVideo (Media,PathMedPriv,ClassMedia); - break; - default: - break; - } + /* Show media */ + switch (Media->Type) + { + case Med_JPG: + Med_ShowJPG (Media,PathMedPriv,ClassMedia); + break; + case Med_GIF: + Med_ShowGIF (Media,PathMedPriv,ClassMedia); + break; + case Med_MP4: + case Med_WEBM: + case Med_OGG: + Med_ShowVideo (Media,PathMedPriv,ClassMedia); + break; + default: + break; + } - /***** End optional link to external URL *****/ - if (PutLink) - fprintf (Gbl.F.Out,""); + /* End optional link to external URL */ + if (PutLink) + fprintf (Gbl.F.Out,""); + break; + case Med_YOUTUBE: + /***** Show embed YouTube video *****/ + Med_ShowYoutube (Media,ClassMedia); + break; + case Med_EMBED: + /***** Show other embed media *****/ + Med_ShowEmbed (Media,ClassMedia); + break; + default: + break; } /***** End media container *****/ @@ -1548,7 +1656,7 @@ static void Med_ShowVideo (struct Media *Media, } /*****************************************************************************/ -/*************************** Show an embed media *****************************/ +/*********************** Show an embed YouTube video *************************/ /*****************************************************************************/ static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia) @@ -1562,7 +1670,7 @@ static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia) if (Gbl.Usrs.Me.UsrDat.Prefs.AcceptThirdPartyCookies) { /***** Show linked external media *****/ - // Example of code give by YouTube: + // Example of code given by YouTube: // + fprintf (Gbl.F.Out,"
" + "" + "
"); + } + else + { + /***** Alert to inform about third party cookies *****/ + /* Start alert */ + Ale_ShowAlertAndButton1 (Ale_INFO,Txt_To_watch_YouTube_videos_you_have_to_accept_third_party_cookies_in_your_personal_settings); + + /* Put form to change cookies preferences */ + if (!Gbl.Form.Inside) + Lay_PutContextualLinkIconText (ActReqEdiPrf,Coo_COOKIES_ID,NULL, + "cog.svg", + Txt_Settings); + + /* End alert */ + Ale_ShowAlertAndButton2 (ActUnk,NULL,NULL,NULL,Btn_NO_BUTTON,NULL); + } + } + } + /*****************************************************************************/ /********** Remove several media files and entries in database ***************/ /*****************************************************************************/ @@ -1648,56 +1810,65 @@ void Med_RemoveMedia (long MedCod) Med_GetMediaDataByCod (&Media); /***** Step 1. Remove media files from filesystem *****/ - if (Media.Type != Med_TYPE_NONE && - Media.Type != Med_YOUTUBE && - Media.Name[0]) + switch (Media.Type) { - /***** Build path to private directory with the media *****/ - snprintf (PathMedPriv,sizeof (PathMedPriv), - "%s/%c%c", - Cfg_PATH_MEDIA_PRIVATE, - Media.Name[0], - Media.Name[1]); + case Med_JPG: + case Med_GIF: + case Med_MP4: + case Med_WEBM: + case Med_OGG: + if (Media.Name[0]) + { + /***** Build path to private directory with the media *****/ + snprintf (PathMedPriv,sizeof (PathMedPriv), + "%s/%c%c", + Cfg_PATH_MEDIA_PRIVATE, + Media.Name[0], + Media.Name[1]); - /***** Remove files *****/ - switch (Media.Type) - { - case Med_JPG: - /***** Remove private JPG file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Media.Name,Med_Extensions[Med_JPG]); - unlink (FullPathMediaPriv); + /***** Remove files *****/ + switch (Media.Type) + { + case Med_JPG: + /***** Remove private JPG file *****/ + snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), + "%s/%s.%s", + PathMedPriv,Media.Name,Med_Extensions[Med_JPG]); + unlink (FullPathMediaPriv); - break; - case Med_GIF: - /***** Remove private GIF file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Media.Name,Med_Extensions[Med_GIF]); - unlink (FullPathMediaPriv); + break; + case Med_GIF: + /***** Remove private GIF file *****/ + snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), + "%s/%s.%s", + PathMedPriv,Media.Name,Med_Extensions[Med_GIF]); + unlink (FullPathMediaPriv); - /***** Remove private PNG file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.png", - PathMedPriv,Media.Name); - unlink (FullPathMediaPriv); + /***** Remove private PNG file *****/ + snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), + "%s/%s.png", + PathMedPriv,Media.Name); + unlink (FullPathMediaPriv); - break; - case Med_MP4: - case Med_WEBM: - case Med_OGG: - /***** Remove private video file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Media.Name,Med_Extensions[Media.Type]); - unlink (FullPathMediaPriv); + break; + case Med_MP4: + case Med_WEBM: + case Med_OGG: + /***** Remove private video file *****/ + snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), + "%s/%s.%s", + PathMedPriv,Media.Name,Med_Extensions[Media.Type]); + unlink (FullPathMediaPriv); - break; - default: - break; - } - // Public links are removed automatically after a period + break; + default: + break; + } + // Public links are removed automatically after a period + } + break; + default: + break; } /***** Step 2. Remove entry for this media from database *****/ diff --git a/swad_media.h b/swad_media.h index a4c89080..16e056c0 100644 --- a/swad_media.h +++ b/swad_media.h @@ -86,7 +86,7 @@ typedef enum Med_STORED_IN_DB, } Med_Status_t; -#define Med_NUM_TYPES 7 +#define Med_NUM_TYPES 8 typedef enum { Med_TYPE_NONE, @@ -96,6 +96,7 @@ typedef enum Med_WEBM, Med_OGG, Med_YOUTUBE, + Med_EMBED, } Med_Type_t; /***** Struct used to get images/videos from forms *****/ diff --git a/swad_test.c b/swad_test.c index fbf1ebbf..9c953c0f 100644 --- a/swad_test.c +++ b/swad_test.c @@ -5643,28 +5643,36 @@ static long Tst_GetMedCodFromDB (int NumOpt) { MYSQL_RES *mysql_res; MYSQL_ROW row; - long MedCod; + unsigned long NumRows; + long MedCod = -1L; /***** Query depending on NumOpt *****/ if (NumOpt < 0) // Get media associated to stem - DB_QuerySELECT (&mysql_res,"can not get media", - "SELECT MedCod" // row[0] - " FROM tst_questions" - " WHERE QstCod=%ld AND CrsCod=%ld", - Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod); + NumRows = DB_QuerySELECT (&mysql_res,"can not get media", + "SELECT MedCod" // row[0] + " FROM tst_questions" + " WHERE QstCod=%ld AND CrsCod=%ld", + Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod); else // Get media associated to answer - DB_QuerySELECT (&mysql_res,"can not get media", - "SELECT MedCod" // row[0] - " FROM tst_answers" - " WHERE QstCod=%ld AND AnsInd=%u", - Gbl.Test.QstCod,(unsigned) NumOpt); + NumRows = DB_QuerySELECT (&mysql_res,"can not get media", + "SELECT MedCod" // row[0] + " FROM tst_answers" + " WHERE QstCod=%ld AND AnsInd=%u", + Gbl.Test.QstCod,(unsigned) NumOpt); - row = mysql_fetch_row (mysql_res); - - /***** Get media code (row[0]) *****/ - MedCod = Str_ConvertStrCodToLongCod (row[0]); + if (NumRows) + { + if (NumRows == 1) + { + /***** Get media code (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + MedCod = Str_ConvertStrCodToLongCod (row[0]); + } + else // NumRows > 1 + Lay_ShowErrorAndExit ("Duplicated media in database."); + } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); diff --git a/swad_text.c b/swad_text.c index 3dfd3bcd..6adff618 100644 --- a/swad_text.c +++ b/swad_text.c @@ -49330,11 +49330,11 @@ const char *Txt_TIMELINE_Post_removed = #elif L==3 // en "Post removed."; #elif L==4 // es - "Publicación eliminada"; + "Publicación eliminada."; #elif L==5 // fr "Publication supprimée."; #elif L==6 // gn - "Publicación eliminada"; // Okoteve traducción + "Publicación eliminada."; // Okoteve traducción #elif L==7 // it "Pubblicazione rimossa."; #elif L==8 // pl