diff --git a/css/swad18.80.css b/css/swad18.80.css index 9803e505..b173092d 100644 --- a/css/swad18.80.css +++ b/css/swad18.80.css @@ -2991,7 +2991,7 @@ a:hover img.CENTRE_PHOTO_SHOW .TL_POST_MED { box-sizing:border-box; - border-radius:8px; + border-radius:4px; } .TL_COMMENT_CONTAINER { @@ -3017,7 +3017,7 @@ a:hover img.CENTRE_PHOTO_SHOW .TL_COMMENT_MED { box-sizing:border-box; - border-radius:8px; + border-radius:4px; } .TL_FORM_NEW_COMMENT { diff --git a/sql/swad.sql b/sql/swad.sql index 87812d78..a0505f4c 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -1334,6 +1334,7 @@ CREATE TABLE IF NOT EXISTS usr_data ( Comments TEXT NOT NULL DEFAULT '', Menu TINYINT NOT NULL DEFAULT 0, SideCols TINYINT NOT NULL DEFAULT 3, + ThirdPartyCookies ENUM('N','Y') NOT NULL DEFAULT 'N', NotifNtfEvents INT NOT NULL DEFAULT 0, EmailNtfEvents INT NOT NULL DEFAULT 0, PRIMARY KEY(UsrCod), @@ -1351,7 +1352,8 @@ CREATE TABLE IF NOT EXISTS usr_data ( INDEX(DptCod), INDEX(CtrCod), INDEX(Menu), - INDEX(SideCols)); + INDEX(SideCols), + INDEX(ThirdPartyCookies)); -- -- Table usr_duplicated: stores informs of users possibly duplicated -- diff --git a/swad_changelog.h b/swad_changelog.h index 61403a41..a890504b 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -436,6 +436,8 @@ Lo de mutear anuncios, en principio prefiero hacer una opci // TODO: Los usuarios que no tienes permiso para ver su perfil público, se debería mostrar algo, una mínima ficha sin tinmeline o algo así +// TODO: Para acelerar la carga, todas las preferencias de usuarios no deberían obtenerse siempre, sino en una llamada especial pues en general sólo interesan para el usuario identificado + // TODO: Allow timeline posting only for users belonging to courses or admins to avoid user who create accounts only to post /*****************************************************************************/ @@ -457,10 +459,51 @@ En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 18.80 (2019-03-17)" +#define Log_PLATFORM_VERSION "SWAD 18.81 (2019-03-18)" #define CSS_FILE "swad18.80.css" #define JS_FILE "swad18.80.js" /* +TODO: Remove unused fields MediaName,MediaType,MediaTitle,MediaURL,Media from tables: +// ALTER TABLE forum_post DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE msg_content DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE msg_content_deleted DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE social_comments DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE social_posts DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE tst_answers DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE tst_questions DROP COLUMN MediaName,DROP COLUMN MediaType,DROP COLUMN MediaTitle,DROP COLUMN MediaURL; +// ALTER TABLE media DROP COLUMN T,DROP COLUMN Cod; + + Version 18.81: Mar 18, 2019 New database table media to store images and videos. + Fixed bugs in removal of publications in timeline. (240704 lines) + 1 change necessary in database: +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',Name VARCHAR(43) NOT NULL DEFAULT '',URL VARCHAR(255) NOT NULL DEFAULT '',Title VARCHAR(2047) NOT NULL DEFAULT '',T VARCHAR (2047) NOT NULL DEFAULT '',Cod INT NOT NULL DEFAULT -1,UNIQUE INDEX(MedCod),INDEX(Type)); +Only if you use MyISAM: +ALTER TABLE media ENGINE=MyISAM; + 21 changes necessary in database: +ALTER TABLE forum_post ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Content,ADD INDEX (MedCod); +ALTER TABLE msg_content ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Content,ADD INDEX (MedCod); +ALTER TABLE msg_content_deleted ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Content,ADD INDEX (MedCod); +ALTER TABLE social_comments ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Content,ADD INDEX (MedCod); +ALTER TABLE social_posts ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Content,ADD INDEX (MedCod); +ALTER TABLE tst_answers ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Feedback,ADD INDEX (MedCod); +ALTER TABLE tst_questions ADD COLUMN MedCod INT NOT NULL DEFAULT -1 AFTER Feedback,ADD INDEX (MedCod); + +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'forum_post',PstCod FROM forum_post WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'msg_content',MsgCod FROM msg_content WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'msg_content_deleted',MsgCod FROM msg_content_deleted WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'social_comments',PubCod FROM social_comments WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'social_posts',PstCod FROM social_posts WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'tst_answers',QstCod*10+AnsInd FROM tst_answers WHERE MediaType<>'none'; +INSERT INTO media (Type,Name,URL,Title,T,Cod) SELECT MediaType,MediaName,MediaURL,MediaTitle,'tst_questions',QstCod FROM tst_questions WHERE MediaType<>'none'; + +UPDATE forum_post,media SET forum_post.MedCod=media.MedCod WHERE media.T='forum_post' AND forum_post.PstCod=media.Cod; +UPDATE msg_content,media SET msg_content.MedCod=media.MedCod WHERE media.T='msg_content' AND msg_content.MsgCod=media.Cod; +UPDATE msg_content_deleted,media SET msg_content_deleted.MedCod=media.MedCod WHERE media.T='msg_content_deleted' AND msg_content_deleted.MsgCod=media.Cod; +UPDATE social_comments,media SET social_comments.MedCod=media.MedCod WHERE media.T='social_comments' AND social_comments.PubCod=media.Cod; +UPDATE social_posts,media SET social_posts.MedCod=media.MedCod WHERE media.T='social_posts' AND social_posts.PstCod=media.Cod; +UPDATE tst_answers,media SET tst_answers.MedCod=media.MedCod WHERE media.T='tst_answers' AND tst_answers.QstCod*10+AnsInd=media.Cod; +UPDATE tst_questions,media SET tst_questions.MedCod=media.MedCod WHERE media.T='tst_questions' AND tst_questions.QstCod=media.Cod; + Version 18.80: Mar 17, 2019 Figure about cookies. (240647 lines) Version 18.79.1: Mar 17, 2019 YouTube videos are not shown if user doesn't accept third party cookies. (240541 lines) Version 18.79: Mar 17, 2019 New module swad_cookies for user's preference about cookies. (240494 lines) diff --git a/swad_database.c b/swad_database.c index 124dde08..ebf3cbc5 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1218,12 +1218,13 @@ mysql> DESCRIBE forum_post; | NumNotif | int(11) | NO | | 0 | | | Subject | text | NO | | NULL | | | Content | longtext | NO | | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | +------------+-------------------------------------------------------+------+-----+---------+----------------+ -12 rows in set (0.00 sec) +13 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS forum_post (" "PstCod INT NOT NULL AUTO_INCREMENT," @@ -1234,6 +1235,7 @@ mysql> DESCRIBE forum_post; "NumNotif INT NOT NULL DEFAULT 0," "Subject TEXT NOT NULL," // Cns_MAX_BYTES_SUBJECT "Content LONGTEXT NOT NULL," // Cns_MAX_BYTES_LONG_TEXT + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE @@ -1242,7 +1244,8 @@ mysql> DESCRIBE forum_post; "INDEX(ThrCod)," "INDEX(UsrCod)," "INDEX(CreatTime)," - "INDEX(ModifTime))"); + "INDEX(ModifTime)," + "INDEX(MedCod))"); /***** Table forum_thr_clip *****/ /* @@ -1714,6 +1717,29 @@ mysql> DESCRIBE marks_properties; "Footer INT NOT NULL," "UNIQUE INDEX(FilCod))"); + /***** 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 | | | | ++--------+-------------------------------------------------------+------+-----+---------+----------------+ +5 rows in set (0.00 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'," + "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 + "UNIQUE INDEX(MedCod)," + "INDEX(Type))"); + /***** Table msg_banned *****/ /* mysql> DESCRIBE msg_banned; @@ -1739,23 +1765,26 @@ mysql> DESCRIBE msg_content; | MsgCod | int(11) | NO | PRI | NULL | auto_increment | | Subject | text | NO | MUL | NULL | | | Content | longtext | NO | | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | +------------+-------------------------------------------------------+------+-----+---------+----------------+ -7 rows in set (0.00 sec) +8 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS msg_content (" "MsgCod INT NOT NULL AUTO_INCREMENT," "Subject TEXT NOT NULL," "Content LONGTEXT NOT NULL," + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE "MediaURL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "UNIQUE INDEX(MsgCod)," - "FULLTEXT(Subject,Content)) ENGINE = MYISAM;"); + "FULLTEXT(Subject,Content)," + "INDEX(MedCod)) ENGINE = MYISAM;"); /***** Table msg_content_deleted *****/ /* @@ -1766,23 +1795,26 @@ mysql> DESCRIBE msg_content_deleted; | MsgCod | int(11) | NO | PRI | NULL | | | Subject | text | NO | MUL | NULL | | | Content | longtext | NO | | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | +------------+-------------------------------------------------------+------+-----+---------+-------+ -7 rows in set (0.00 sec) +8 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS msg_content_deleted (" "MsgCod INT NOT NULL," "Subject TEXT NOT NULL," "Content LONGTEXT NOT NULL," + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE "MediaURL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "UNIQUE INDEX(MsgCod)," - "FULLTEXT(Subject,Content)) ENGINE = MYISAM;"); + "FULLTEXT(Subject,Content)," + "INDEX(MedCod)) ENGINE = MYISAM;"); /***** Table msg_rcv *****/ /* @@ -2181,22 +2213,25 @@ mysql> DESCRIBE social_comments; +------------+-------------------------------------------------------+------+-----+---------+-------+ | PubCod | bigint(20) | NO | PRI | NULL | | | Content | longtext | NO | MUL | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | +------------+-------------------------------------------------------+------+-----+---------+-------+ -6 rows in set (0.00 sec) +7 rows in set (0.01 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS social_comments (" "PubCod BIGINT NOT NULL," "Content LONGTEXT NOT NULL," + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE "MediaURL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "UNIQUE INDEX(PubCod)," - "FULLTEXT(Content)) ENGINE = MYISAM;"); + "FULLTEXT(Content)," + "INDEX(MedCod)) ENGINE = MYISAM;"); /***** Table social_comments_fav *****/ /* @@ -2279,22 +2314,25 @@ mysql> DESCRIBE social_posts; +------------+-------------------------------------------------------+------+-----+---------+----------------+ | PstCod | int(11) | NO | PRI | NULL | auto_increment | | Content | longtext | NO | MUL | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | +------------+-------------------------------------------------------+------+-----+---------+----------------+ -6 rows in set (0.00 sec) +7 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS social_posts (" "PubCod INT NOT NULL AUTO_INCREMENT," "Content LONGTEXT NOT NULL," + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE "MediaURL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "UNIQUE INDEX(PubCod)," - "FULLTEXT(Content)) ENGINE = MYISAM;"); + "FULLTEXT(Content)," + "INDEX(MedCod)) ENGINE = MYISAM;"); /***** Table social_pubs *****/ /* @@ -2554,25 +2592,28 @@ mysql> DESCRIBE tst_answers; | AnsInd | tinyint(4) | NO | | NULL | | | Answer | text | NO | | NULL | | | Feedback | text | NO | | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | | MediaURL | varchar(255) | NO | | | | | Correct | enum('N','Y') | NO | | NULL | | +------------+-------------------------------------------------------+------+-----+---------+-------+ -9 rows in set (0.00 sec) +10 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_answers (" "QstCod INT NOT NULL," "AnsInd TINYINT NOT NULL," "Answer TEXT NOT NULL," // Tst_MAX_BYTES_ANSWER_OR_FEEDBACK "Feedback TEXT NOT NULL," // Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE "MediaURL VARCHAR(255) NOT NULL DEFAULT ''," // Cns_MAX_BYTES_WWW "Correct ENUM('N','Y') NOT NULL," - "INDEX(QstCod))"); + "INDEX(QstCod)," + "INDEX(MedCod))"); /***** Table tst_config *****/ /* @@ -2684,6 +2725,7 @@ mysql> DESCRIBE tst_questions; | Shuffle | enum('N','Y') | NO | | NULL | | | Stem | text | NO | | NULL | | | Feedback | text | NO | | NULL | | +| MedCod | int(11) | NO | MUL | -1 | | | MediaName | varchar(43) | NO | | | | | MediaType | enum('none','jpg','gif','mp4','webm','ogg','youtube') | NO | | none | | | MediaTitle | varchar(2047) | NO | | | | @@ -2692,7 +2734,7 @@ mysql> DESCRIBE tst_questions; | NumHitsNotBlank | int(11) | NO | | 0 | | | Score | double | NO | | 0 | | +-----------------+---------------------------------------------------------------------------+------+-----+---------+----------------+ -14 rows in set (0.00 sec) +15 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_questions (" "QstCod INT NOT NULL AUTO_INCREMENT," @@ -2702,6 +2744,7 @@ mysql> DESCRIBE tst_questions; "Shuffle ENUM('N','Y') NOT NULL," "Stem TEXT NOT NULL," // Cns_MAX_BYTES_TEXT "Feedback TEXT NOT NULL," // Cns_MAX_BYTES_TEXT + "MedCod INT NOT NULL DEFAULT -1," "MediaName VARCHAR(43) NOT NULL DEFAULT ''," // Med_BYTES_NAME "MediaType ENUM('none','jpg','gif','mp4','webm','ogg','youtube') NOT NULL DEFAULT 'none'," "MediaTitle VARCHAR(2047) NOT NULL DEFAULT ''," // Med_MAX_BYTES_TITLE @@ -2710,7 +2753,8 @@ mysql> DESCRIBE tst_questions; "NumHitsNotBlank INT NOT NULL DEFAULT 0," "Score DOUBLE PRECISION NOT NULL DEFAULT 0," "UNIQUE INDEX(QstCod)," - "INDEX(CrsCod,EditTime))"); + "INDEX(CrsCod,EditTime)," + "INDEX(MedCod))"); /***** Table tst_status *****/ /* @@ -2865,7 +2909,7 @@ mysql> DESCRIBE usr_data; "INDEX(CtrCod)," "INDEX(Menu)," "INDEX(SideCols)," - "INDEX(ThirdPartyCookies)"); + "INDEX(ThirdPartyCookies))"); /***** Table usr_duplicated *****/ /* diff --git a/swad_forum.c b/swad_forum.c index 095e2013..4986554d 100644 --- a/swad_forum.c +++ b/swad_forum.c @@ -283,7 +283,7 @@ static void For_InsertPstIntoBannedPstTable (long PstCod); static long For_InsertForumPst (long ThrCod,long UsrCod, const char *Subject,const char *Content, struct Media *Media); -static bool For_RemoveForumPst (long PstCod,struct Media *Media); +static bool For_RemoveForumPst (long PstCod,long MedCod); static unsigned For_NumPstsInThrWithPstCod (long PstCod,long *ThrCod); static long For_InsertForumThread (long FirstPstCod); @@ -501,28 +501,29 @@ static long For_InsertForumPst (long ThrCod,long UsrCod, long PstCod; /***** Check if image is received and processed *****/ + Media->MedCod = -1L; if (Media->Action == Med_ACTION_NEW_MEDIA && // New media Media->Status == Med_PROCESSED) // The new media received has been processed + { /* Move processed media to definitive directory */ Med_MoveMediaToDefinitiveDir (Media); + /* Store media in database */ + if (Media->Status == Med_MOVED) + Med_StoreMediaInDB (Media); // Set Media->MedCod + } + /***** Insert forum post in the database *****/ PstCod = DB_QueryINSERTandReturnCode ("can not create a new post in a forum", "INSERT INTO forum_post" " (ThrCod,UsrCod,CreatTime,ModifTime,NumNotif," - "Subject,Content," - "MediaName,MediaType,MediaTitle,MediaURL)" + "Subject,Content,MedCod)" " VALUES" " (%ld,%ld,NOW(),NOW(),0," - "'%s','%s'," - "'%s','%s','%s','%s')", + "'%s','%s',%ld)", ThrCod,UsrCod, - Subject,Content, - Media->Name, - Med_GetStringTypeForDB (Media->Type), - Media->Title ? Media->Title : "", - Media->URL ? Media->URL : ""); + Subject,Content,Media->MedCod); return PstCod; } @@ -532,13 +533,13 @@ static long For_InsertForumPst (long ThrCod,long UsrCod, /*****************************************************************************/ // Return true if the post thread is deleted -static bool For_RemoveForumPst (long PstCod,struct Media *Media) +static bool For_RemoveForumPst (long PstCod,long MedCod) { long ThrCod; bool ThreadDeleted = false; /***** Remove media file attached to forum post *****/ - Med_RemoveMediaFiles (Media->Name,Media->Type); + Med_RemoveMedia (MedCod); /***** If the post is the only one in its thread, delete that thread *****/ if (For_NumPstsInThrWithPstCod (PstCod,&ThrCod) < 2) @@ -1345,10 +1346,7 @@ static void For_GetPstData (long PstCod,long *UsrCod,time_t *CreatTimeUTC, "UNIX_TIMESTAMP(CreatTime)," // row[1] "Subject," // row[2] "Content," // row[3] - "MediaName," // row[4] - "MediaType," // row[5] - "MediaTitle," // row[6] - "MediaURL" // row[7] + "MedCod" // row[4] " FROM forum_post WHERE PstCod=%ld", PstCod); @@ -1359,22 +1357,23 @@ static void For_GetPstData (long PstCod,long *UsrCod,time_t *CreatTimeUTC, /***** Get number of rows *****/ row = mysql_fetch_row (mysql_res); - /****** Get author code (row[1]) *****/ + /***** Get author code (row[1]) *****/ *UsrCod = Str_ConvertStrCodToLongCod (row[0]); - /****** Get creation time (row[1]) *****/ + /***** Get creation time (row[1]) *****/ *CreatTimeUTC = Dat_GetUNIXTimeFromStr (row[1]); - /****** Get subject (row[2]) *****/ + /***** Get subject (row[2]) *****/ Str_Copy (Subject,row[2], Cns_MAX_BYTES_SUBJECT); - /****** Get location (row[3]) *****/ + /***** Get location (row[3]) *****/ Str_Copy (Content,row[3], Cns_MAX_BYTES_LONG_TEXT); - /****** Get media data (row[4], row[5], row[6], row[7]) *****/ - Med_GetMediaDataFromRow (row[4],row[5],row[6],row[7],Media); + /***** Get media (row[4]) *****/ + Media->MedCod = Str_ConvertStrCodToLongCod (row[4]); + Med_GetMediaDataByCod (Media); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -4089,7 +4088,7 @@ void For_ReceiveForumPost (void) For_UpdateThrFirstAndLastPst (Gbl.Forum.ForumSelected.ThrCod,PstCod,PstCod); } - /***** Free image *****/ + /***** Free media *****/ Med_MediaDestructor (&Media); /***** Increment number of forum posts in my user's figures *****/ @@ -4188,7 +4187,7 @@ void For_RemovePost (void) Lay_ShowErrorAndExit ("You can not remove post because it is not the last of the thread."); /***** Remove the post *****/ - ThreadDeleted = For_RemoveForumPst (Gbl.Forum.ForumSelected.PstCod,&Media); + ThreadDeleted = For_RemoveForumPst (Gbl.Forum.ForumSelected.PstCod,Media.MedCod); /***** Free image *****/ Med_MediaDestructor (&Media); diff --git a/swad_game.c b/swad_game.c index 0146f8f0..7aac49a5 100644 --- a/swad_game.c +++ b/swad_game.c @@ -2734,10 +2734,7 @@ static void Gam_ListGameQuestions (struct Game *Game) "tst_questions.AnsType," // row[1] "tst_questions.Stem," // row[2] "tst_questions.Feedback," // row[3] - "tst_questions.MediaName," // row[4] - "tst_questions.MediaType," // row[5] - "tst_questions.MediaTitle," // row[6] - "tst_questions.MediaURL" // row[7] + "tst_questions.MedCod" // row[4] " FROM gam_questions,tst_questions" " WHERE gam_questions.GamCod=%ld" " AND gam_questions.QstCod=tst_questions.QstCod" @@ -2842,10 +2839,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, row[1] AnsType row[2] Stem row[3] Feedback - row[4] MediaName - row[5] MediaType - row[6] MediaTitle - row[7] MediaURL + row[4] MedCod */ /***** Create test question *****/ Tst_QstConstructor (); @@ -2923,16 +2917,24 @@ static void Gam_ListOneOrMoreQuestionsForEdition (struct Game *Game, Tst_GetAndWriteTagsQst (Gbl.Test.QstCod); fprintf (Gbl.F.Out,""); - /* Write stem (row[2]), media data (row[4], row[5], row[6], row[7]), - feedback (row[3]) and answers */ + /* Write stem (row[2]) */ fprintf (Gbl.F.Out,"", Gbl.RowEvenOdd); Tst_WriteQstStem (row[2],"TEST_EDI"); - Med_GetMediaDataFromRow (row[4],row[5],row[6],row[7],&Gbl.Test.Media); + + /* Get media (row[4]) */ + Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[4]); + Med_GetMediaDataByCod (&Gbl.Test.Media); + + /* Show media */ Med_ShowMedia (&Gbl.Test.Media, "TEST_IMG_EDIT_LIST_STEM_CONTAINER", "TEST_IMG_EDIT_LIST_STEM"); + + /* Show feedback (row[3]) */ Tst_WriteQstFeedback (row[3],"TEST_EDI_LIGHT"); + + /* Show answers */ Tst_WriteAnswersGameResult (Game,NumQst,QstCod, "TEST_EDI",true); // Show result @@ -3531,10 +3533,7 @@ static void Gam_PlayGameShowQuestionAndAnswers (bool ShowAnswers) "SELECT tst_questions.QstCod," // row[0] "tst_questions.AnsType," // row[1] "tst_questions.Stem," // row[2] - "tst_questions.MediaName," // row[3] - "tst_questions.MediaType," // row[4] - "tst_questions.MediaTitle," // row[5] - "tst_questions.MediaURL" // row[6] + "tst_questions.MedCod" // row[3] " FROM gam_questions,tst_questions" " WHERE gam_questions.GamCod=%ld" " AND gam_questions.QstInd=%u" @@ -3553,9 +3552,14 @@ static void Gam_PlayGameShowQuestionAndAnswers (bool ShowAnswers) fprintf (Gbl.F.Out,"
"); - /* Write stem (row[2]) and media data (row[3], row[4], row[5], row[6]) */ + /* Write stem (row[2]) */ Tst_WriteQstStem (row[2],"GAM_PLAY_QST"); - Med_GetMediaDataFromRow (row[3],row[4],row[5],row[6],&Gbl.Test.Media); + + /* Get media (row[3]) */ + Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Gbl.Test.Media); + + /* Show media */ Med_ShowMedia (&Gbl.Test.Media, "TEST_IMG_EDIT_LIST_STEM_CONTAINER", "TEST_IMG_EDIT_LIST_STEM"); diff --git a/swad_media.c b/swad_media.c index cd80fa4b..e9b240cb 100644 --- a/swad_media.c +++ b/swad_media.c @@ -38,6 +38,7 @@ #include "swad_config.h" #include "swad_cookie.h" +#include "swad_database.h" #include "swad_global.h" #include "swad_file.h" #include "swad_file_browser.h" @@ -153,8 +154,10 @@ static void Med_ShowVideo (struct Media *Media, const char *ClassMedia); static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia); +static Med_Type_t Med_GetTypeFromStrInDB (const char *Str); static Med_Type_t Med_GetTypeFromExtAndMIME (const char *Extension, const char *MIMEType); +static const char *Med_GetStringTypeForDB (Med_Type_t Type); /*****************************************************************************/ /********************** Media (image/video) constructor **********************/ @@ -197,6 +200,7 @@ void Med_ResetMedia (struct Media *Media) static void Med_ResetMediaExceptURLAndTitle (struct Media *Media) { + Media->MedCod = -1L; Media->Action = Med_ACTION_NO_MEDIA; Media->Status = Med_STATUS_NONE; Media->Name[0] = '\0'; @@ -235,58 +239,81 @@ static void Med_FreeMediaTitle (struct Media *Media) /**** Get media name, title and URL from a query result and copy to struct ***/ /*****************************************************************************/ -void Med_GetMediaDataFromRow (const char *Name, - const char *TypeStr, - const char *Title, - const char *URL, - struct Media *Media) +void Med_GetMediaDataByCod (struct Media *Media) { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumRows; size_t Length; - /***** Copy image name to struct *****/ - Str_Copy (Media->Name,Name, - Med_BYTES_NAME); + /***** Get data of a media from database *****/ + NumRows = DB_QuerySELECT (&mysql_res,"can not get data of a post", + "SELECT Type," // row[0] + "Name," // row[1] + "URL," // row[2] + "Title" // row[3] + " FROM media WHERE MedCod=%ld", + Media->MedCod); - /***** Convert type string to type *****/ - Media->Type = Med_GetTypeFromStrInDB (TypeStr); - - /***** Set status of media file *****/ - Media->Status = (Media->Type != Med_TYPE_NONE) ? Med_STORED_IN_DB : - Med_STATUS_NONE; - - /***** Copy image URL to struct *****/ - // Media->URL can be empty or filled with previous value - // If filled ==> free it - Med_FreeMediaURL (Media); - if (URL[0]) + /***** Result should have a unique row *****/ + if (NumRows == 0) // Media not found + /***** Reset media data *****/ + Med_ResetMedia (Media); + else if (NumRows == 1) { - /* Get and limit length of the URL */ - Length = strlen (URL); - if (Length > Cns_MAX_BYTES_WWW) - Length = Cns_MAX_BYTES_WWW; + /***** Get row *****/ + row = mysql_fetch_row (mysql_res); - if ((Media->URL = (char *) malloc (Length + 1)) == NULL) - Lay_ShowErrorAndExit ("Error allocating memory for image URL."); - Str_Copy (Media->URL,URL, - Length); + /***** Convert type string (row[0]) to type *****/ + Media->Type = Med_GetTypeFromStrInDB (row[0]); + + /***** Set status of media file *****/ + Media->Status = (Media->Type != Med_TYPE_NONE) ? Med_STORED_IN_DB : + Med_STATUS_NONE; + + /***** Copy media name (row[1]) to struct *****/ + Str_Copy (Media->Name,row[1], + Med_BYTES_NAME); + + /***** Copy media URL (row[2]) to struct *****/ + // Media->URL can be empty or filled with previous value + // If filled ==> free it + Med_FreeMediaURL (Media); + if (row[2][0]) + { + /* Get and limit length of the URL */ + Length = strlen (row[2]); + if (Length > Cns_MAX_BYTES_WWW) + Length = Cns_MAX_BYTES_WWW; + + if ((Media->URL = (char *) malloc (Length + 1)) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory for image URL."); + Str_Copy (Media->URL,row[2], + Length); + } + + /***** Copy media title (row[3]) to struct *****/ + // Media->Title can be empty or filled with previous value + // If filled ==> free it + Med_FreeMediaTitle (Media); + if (row[3][0]) + { + /* Get and limit length of the title */ + Length = strlen (row[3]); + if (Length > Med_MAX_BYTES_TITLE) + Length = Med_MAX_BYTES_TITLE; + + if ((Media->Title = (char *) malloc (Length + 1)) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory for image title."); + Str_Copy (Media->Title,row[3], + Length); + } } + else + Lay_ShowErrorAndExit ("Internal error in database when getting media data."); - /***** Copy image title to struct *****/ - // Media->Title can be empty or filled with previous value - // If filled ==> free it - Med_FreeMediaTitle (Media); - if (Title[0]) - { - /* Get and limit length of the title */ - Length = strlen (Title); - if (Length > Med_MAX_BYTES_TITLE) - Length = Med_MAX_BYTES_TITLE; - - if ((Media->Title = (char *) malloc (Length + 1)) == NULL) - Lay_ShowErrorAndExit ("Error allocating memory for image title."); - Str_Copy (Media->Title,Title, - Length); - } + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ @@ -980,7 +1007,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, /***** Get embed URL from form *****/ Usr_GetURLFromForm (ParamURL,Media); - // Ale_ShowAlert (Ale_INFO,"DEBUG: Media->URL = '%s'",Media->URL); /***** Process URL trying to convert it to a YouTube embed URL *****/ if (Media->URL) @@ -1007,7 +1033,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, if (PtrHost[0]) { /***** Step 2: Skip host *****/ - // Ale_ShowAlert (Ale_INFO,"DEBUG: PtrHost = '%s'",PtrHost); if (!strncasecmp (PtrHost,"youtu.be/" , 9)) // Host starts by youtu.be/ { YouTube = SHORT; @@ -1035,7 +1060,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, if (YouTube != WRONG) { - // Ale_ShowAlert (Ale_INFO,"DEBUG: PtrPath = '%s'",PtrPath); /***** Step 3: Skip path *****/ if (YouTube == FULL) { @@ -1063,7 +1087,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, if (YouTube != WRONG) { - // Ale_ShowAlert (Ale_INFO,"DEBUG: PtrParams = '%s'",PtrParams); /***** Step 4: Search for video code *****/ switch (YouTube) { @@ -1095,7 +1118,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, if (YouTube != WRONG) { - // Ale_ShowAlert (Ale_INFO,"DEBUG: PtrCode = '%s'",PtrCode); /***** Step 5: Get video code *****/ CodeLength = strspn (PtrCode,Str_BIN_TO_BASE64URL); if (CodeLength > 0 && @@ -1105,7 +1127,6 @@ static void Med_GetAndProcessEmbedFromForm (const char *ParamURL, /* Copy code */ strncpy (Media->Name,PtrCode,CodeLength); Media->Name[CodeLength] = '\0'; - // Ale_ShowAlert (Ale_INFO,"DEBUG: Media->Name = '%s'",Media->Name); Media->Type = Med_YOUTUBE; Media->Status = Med_PROCESSED; @@ -1126,56 +1147,63 @@ void Med_MoveMediaToDefinitiveDir (struct Media *Media) char PathMedPrivTmp[PATH_MAX + 1]; char PathMedPriv[PATH_MAX + 1]; - /***** Check trivial cases *****/ - if (Media->Status != Med_PROCESSED) - return; - if (Media->Type == Med_YOUTUBE) - return; // Nothing to do with files - - /***** Build temporary path *****/ - snprintf (PathMedPrivTmp,sizeof (PathMedPrivTmp), - "%s/%s/%s", - Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA,Cfg_FOLDER_IMG_TMP); - - /***** Create private subdirectory for media if it does not exist *****/ - snprintf (PathMedPriv,sizeof (PathMedPriv), - "%s/%s/%c%c", - Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA, - Media->Name[0], - Media->Name[1]); - Fil_CreateDirIfNotExists (PathMedPriv); - - /***** Move files *****/ - switch (Media->Type) + /***** Check trivial case *****/ + if (Media->Status == Med_PROCESSED) { - case Med_JPG: - /* Move JPG */ - if (!Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, - Med_Extensions[Med_JPG])) - return; // Fail - break; - case Med_GIF: - /* Move PNG */ - if (!Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, - "png")) - return; // Fail - /* Move GIF */ - if (!Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, - Med_Extensions[Med_GIF])) - return; // Fail - break; - case Med_MP4: - case Med_WEBM: - case Med_OGG: - /* Move MP4 or WEBM or OGG */ - if (!Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, - Med_Extensions[Media->Type])) - return; // Fail - break; - default: - Lay_ShowErrorAndExit ("Wrong media type."); - break; + if (Media->Type == Med_YOUTUBE) + // Nothing to do with files ==> Processing successfully finished + Media->Status = Med_MOVED; // Success + else + { + /***** Build temporary path *****/ + snprintf (PathMedPrivTmp,sizeof (PathMedPrivTmp), + "%s/%s/%s", + Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA,Cfg_FOLDER_IMG_TMP); + + /***** Create private subdirectory for media if it does not exist *****/ + snprintf (PathMedPriv,sizeof (PathMedPriv), + "%s/%s/%c%c", + Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA, + Media->Name[0], + Media->Name[1]); + Fil_CreateDirIfNotExists (PathMedPriv); + + /***** Move files *****/ + switch (Media->Type) + { + case Med_JPG: + /* Move JPG */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, + Med_Extensions[Med_JPG])) + Media->Status = Med_MOVED; // Success + break; + case Med_GIF: + /* Move PNG */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,PathMedPriv, + "png")) + /* Move GIF */ + if (Med_MoveTmpFileToDefDir (Media,PathMedPrivTmp,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,PathMedPrivTmp,PathMedPriv, + Med_Extensions[Media->Type])) + Media->Status = Med_MOVED; // Success + break; + default: + Lay_ShowErrorAndExit ("Wrong media type."); + break; // Not reached + } + } } + + /***** If fail ==> reset media *****/ + if (Media->Status != Med_MOVED) // Fail + Med_ResetMedia (Media); } /*****************************************************************************/ @@ -1212,6 +1240,32 @@ static bool Med_MoveTmpFileToDefDir (struct Media *Media, return true; // Success } +/*****************************************************************************/ +/************************ Store media into database **************************/ +/*****************************************************************************/ + +void Med_StoreMediaInDB (struct Media *Media) + { + /***** Trivial case *****/ + if (Media->Status != Med_MOVED) + { + Med_ResetMedia (Media); // No media inserted in database + return; + } + + /***** Insert media into database *****/ + Media->MedCod = DB_QueryINSERTandReturnCode ("can not create media", + "INSERT INTO media" + " (Type,Name,URL,Title)" + " VALUES" + " ('%s','%s','%s','%s')", + Med_GetStringTypeForDB (Media->Type), + Media->Name, + Media->URL ? Media->URL : "", + Media->Title ? Media->Title : ""); + Media->Status = Med_STORED_IN_DB; + } + /*****************************************************************************/ /****** Show a user uploaded media (in a test question, timeline, etc.) ******/ /*****************************************************************************/ @@ -1542,10 +1596,10 @@ static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia) } /*****************************************************************************/ -/*** Remove private files with an image/video, given the image/video name ****/ +/**************** Remove media files and entries in database *****************/ /*****************************************************************************/ -void Med_RemoveMediaFilesFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res) +void Med_RemoveMediaFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res) { unsigned NumMed; @@ -1553,87 +1607,106 @@ void Med_RemoveMediaFilesFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res) for (NumMed = 0; NumMed < NumMedia; NumMed++) - Med_RemoveMediaFilesFromRow (mysql_res); + Med_RemoveMediaFromRow (mysql_res); } -void Med_RemoveMediaFilesFromRow (MYSQL_RES *mysql_res) +void Med_RemoveMediaFromRow (MYSQL_RES *mysql_res) { MYSQL_ROW row; + long MedCod; - /***** Get media name (row[0]) and type (row[1]) *****/ + /***** Get media code (row[0]) *****/ row = mysql_fetch_row (mysql_res); + MedCod = Str_ConvertStrCodToLongCod (row[0]); - /***** Remove image file *****/ - Med_RemoveMediaFiles (row[0],Med_GetTypeFromStrInDB (row[1])); + /***** Remove media files *****/ + Med_RemoveMedia (MedCod); } -void Med_RemoveMediaFiles (const char *Name,Med_Type_t Type) +void Med_RemoveMedia (long MedCod) { char PathMedPriv[PATH_MAX + 1]; char FullPathMediaPriv[PATH_MAX + 1]; + struct Media Media; - /***** Trivial cases *****/ - if (Name == NULL) - return; - if (!Name[0]) - return; - if (Type == Med_YOUTUBE) + /***** Trivial case *****/ + if (MedCod <= 0) return; - /***** Build path to private directory with the media *****/ - snprintf (PathMedPriv,sizeof (PathMedPriv), - "%s/%s/%c%c", - Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA, - Name[0], - Name[1]); + /***** Initialize media *****/ + Med_MediaConstructor (&Media); - /***** Remove files *****/ - switch (Type) + /***** Get media *****/ + Media.MedCod = MedCod; + Med_GetMediaDataByCod (&Media); + + /***** Step 1. Remove files *****/ + if (Media.Type != Med_TYPE_NONE && + Media.Type != Med_YOUTUBE && + Media.Name[0]) { - case Med_JPG: - /***** Remove private JPG file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Name,Med_Extensions[Med_JPG]); - unlink (FullPathMediaPriv); + /***** Build path to private directory with the media *****/ + snprintf (PathMedPriv,sizeof (PathMedPriv), + "%s/%s/%c%c", + Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_MEDIA, + Media.Name[0], + Media.Name[1]); - break; - case Med_GIF: - /***** Remove private GIF file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Name,Med_Extensions[Med_GIF]); - 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); - /***** Remove private PNG file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.png", - PathMedPriv,Name); - 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_MP4: - case Med_WEBM: - case Med_OGG: - /***** Remove private video file *****/ - snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), - "%s/%s.%s", - PathMedPriv,Name,Med_Extensions[Type]); - unlink (FullPathMediaPriv); + /***** Remove private PNG file *****/ + snprintf (FullPathMediaPriv,sizeof (FullPathMediaPriv), + "%s/%s.png", + PathMedPriv,Media.Name); + unlink (FullPathMediaPriv); - break; - default: - break; + 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 } - // Public links are removed automatically after a period + /***** Step 2. Remove entry for this media from database *****/ + DB_QueryDELETE ("can not remove media", + "DELETE FROM media WHERE MedCod=%ld", + MedCod); + + /***** Free media *****/ + Med_MediaDestructor (&Media); } /*****************************************************************************/ /************************ Get media type from string *************************/ /*****************************************************************************/ -Med_Type_t Med_GetTypeFromStrInDB (const char *Str) +static Med_Type_t Med_GetTypeFromStrInDB (const char *Str) { Med_Type_t Type; @@ -1708,7 +1781,7 @@ static Med_Type_t Med_GetTypeFromExtAndMIME (const char *Extension, /*************** Get string media type in database from type *****************/ /*****************************************************************************/ -const char *Med_GetStringTypeForDB (Med_Type_t Type) +static const char *Med_GetStringTypeForDB (Med_Type_t Type) { /***** Check if type is out of valid range *****/ if (Type > (Med_Type_t) (Med_NUM_TYPES - 1)) diff --git a/swad_media.h b/swad_media.h index f0a7ed5d..b2f3b3ad 100644 --- a/swad_media.h +++ b/swad_media.h @@ -58,7 +58,7 @@ typedef enum No file Original file Temporary Definitive Name of the image/video uploaded uploaded by user processed file processed file stored in database --------- --------------------------- ------------------ ------------------ --------------------- -Med_STATUS_NONE Med_PROCESSED Med_NAME_STORED_IN_DB +Med_STATUS_NONE Med_PROCESSED Med_MOVED Med_NAME_STORED_IN_DB --------- --------------------------- ------------------ ------------------ --------------------- upload-file process file move file insert in database --------- --------------------------- ------------------ ------------------ --------------------- @@ -82,6 +82,7 @@ typedef enum { Med_STATUS_NONE, Med_PROCESSED, + Med_MOVED, Med_STORED_IN_DB, } Med_Status_t; @@ -100,6 +101,7 @@ typedef enum /***** Struct used to get images/videos from forms *****/ struct Media { + long MedCod; Med_Action_t Action; Med_Status_t Status; char Name[Med_BYTES_NAME + 1]; @@ -135,11 +137,7 @@ void Med_MediaConstructor (struct Media *Media); void Med_MediaDestructor (struct Media *Media); void Med_ResetMedia (struct Media *Media); -void Med_GetMediaDataFromRow (const char *Name, - const char *TypeStr, - const char *Title, - const char *URL, - struct Media *Media); +void Med_GetMediaDataByCod (struct Media *Media); void Med_PutMediaUploader (int NumMediaInForm,const char *ClassInput); void Med_GetMediaFromForm (int NumMediaInForm,struct Media *Media, @@ -148,14 +146,13 @@ void Med_GetMediaFromForm (int NumMediaInForm,struct Media *Media, void Med_SetParamNames (struct ParamUploadMedia *ParamUploadMedia,int NumMediaInForm); void Med_MoveMediaToDefinitiveDir (struct Media *Media); +void Med_StoreMediaInDB (struct Media *Media); + void Med_ShowMedia (struct Media *Media, const char *ClassContainer,const char *ClassMedia); -void Med_RemoveMediaFilesFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res); -void Med_RemoveMediaFilesFromRow (MYSQL_RES *mysql_res); -void Med_RemoveMediaFiles (const char *Name,Med_Type_t Type); - -Med_Type_t Med_GetTypeFromStrInDB (const char *Str); -const char *Med_GetStringTypeForDB (Med_Type_t Type); +void Med_RemoveMediaFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res); +void Med_RemoveMediaFromRow (MYSQL_RES *mysql_res); +void Med_RemoveMedia (long MedCod); #endif diff --git a/swad_message.c b/swad_message.c index 0b348aeb..13f08d7b 100644 --- a/swad_message.c +++ b/swad_message.c @@ -1282,25 +1282,26 @@ static long Msg_InsertNewMsg (const char *Subject,const char *Content, long MsgCod; /***** Check if image is received and processed *****/ + Media->MedCod = -1L; if (Media->Action == Med_ACTION_NEW_MEDIA && // New media Media->Status == Med_PROCESSED) // The new media received has been processed + { /* Move processed image to definitive directory */ Med_MoveMediaToDefinitiveDir (Media); + /* Store media in database */ + if (Media->Status == Med_MOVED) + Med_StoreMediaInDB (Media); // Set Media->MedCod + } + /***** Insert message subject and content in the database *****/ MsgCod = DB_QueryINSERTandReturnCode ("can not create message", "INSERT INTO msg_content" - " (Subject,Content," - "MediaName,MediaType,MediaTitle,MediaURL)" + " (Subject,Content,MedCod)" " VALUES" - " ('%s','%s'," - "'%s','%s','%s','%s')", - Subject,Content, - Media->Name, - Med_GetStringTypeForDB (Media->Type), - Media->Title ? Media->Title : "", - Media->URL ? Media->URL : ""); + " ('%s','%s',%ld)", + Subject,Content,Media->MedCod); /***** Insert message in sent messages *****/ DB_QueryINSERT ("can not create message", @@ -1493,10 +1494,8 @@ static void Msg_MoveMsgContentToDeleted (long MsgCod) /* Insert message content into msg_content_deleted */ DB_QueryINSERT ("can not remove the content of a message", "INSERT IGNORE INTO msg_content_deleted" - " (MsgCod,Subject,Content," - "MediaName,MediaType,MediaTitle,MediaURL)" - " SELECT MsgCod,Subject,Content," - "MediaName,MediaType,MediaTitle,MediaURL" + " (MsgCod,Subject,Content,MedCod)" + " SELECT MsgCod,Subject,Content,MedCod" " FROM msg_content WHERE MsgCod=%ld", MsgCod); @@ -2788,10 +2787,7 @@ static void Msg_GetMsgContent (long MsgCod,char Content[Cns_MAX_BYTES_LONG_TEXT /***** Get content of message from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get the content of a message", "SELECT Content," // row[0] - "MediaName," // row[1] - "MediaType," // row[2] - "MediaTitle," // row[3] - "MediaURL" // row[4] + "MedCod" // row[1] " FROM msg_content WHERE MsgCod=%ld", MsgCod); @@ -2806,8 +2802,9 @@ static void Msg_GetMsgContent (long MsgCod,char Content[Cns_MAX_BYTES_LONG_TEXT Str_Copy (Content,row[0], Cns_MAX_BYTES_LONG_TEXT); - /****** Get media data (row[1], row[2], row[3], row[4]) *****/ - Med_GetMediaDataFromRow (row[1],row[2],row[3],row[4],Media); + /***** Get media (row[1]) *****/ + Media->MedCod = Str_ConvertStrCodToLongCod (row[1]); + Med_GetMediaDataByCod (Media); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); diff --git a/swad_test.c b/swad_test.c index 56abb729..fc9801ac 100644 --- a/swad_test.c +++ b/swad_test.c @@ -155,6 +155,11 @@ static Tst_Status_t Tst_GetTstStatus (unsigned NumTst); static unsigned Tst_GetNumAccessesTst (void); static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res); static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore); +static void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, + struct UsrData *UsrDat, + struct Game *Game, + unsigned NumQst,long QstCod,MYSQL_ROW row, + double *ScoreThisQst,bool *AnswerIsNotBlank); static void Tst_PutFormToEditQstMedia (struct Media *Media,int NumMediaInForm, const char *ClassContainer, const char *ClassMedia, @@ -683,8 +688,8 @@ static bool Tst_CheckIfNextTstAllowed (void) /***** Get date of next allowed access to test from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get last access to test", "SELECT UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)-" - "UNIX_TIMESTAMP()," - "UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)" + "UNIX_TIMESTAMP()," // row[0] + "UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)" // row[1] " FROM crs_usr" " WHERE CrsCod=%ld AND UsrCod=%ld", Gbl.Test.Config.MinTimeNxtTstPerQst, @@ -758,7 +763,8 @@ static Tst_Status_t Tst_GetTstStatus (unsigned NumTst) /***** Get status of test from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get status of test", - "SELECT Status FROM tst_status" + "SELECT Status" // row[0] + " FROM tst_status" " WHERE SessionId='%s'" " AND CrsCod=%ld" " AND NumTst=%u", @@ -795,7 +801,8 @@ static unsigned Tst_GetNumAccessesTst (void) { /***** Get number of hits to test from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get number of hits to test", - "SELECT NumAccTst FROM crs_usr" + "SELECT NumAccTst" // row[0] + " FROM crs_usr" " WHERE CrsCod=%ld AND UsrCod=%ld", Gbl.CurrentCrs.Crs.CrsCod, Gbl.Usrs.Me.UsrDat.UsrCod); @@ -834,6 +841,18 @@ static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res) MYSQL_ROW row; double ScoreThisQst; // Not used here bool AnswerIsNotBlank; // Not used here + /* + row[0] QstCod + row[1] UNIX_TIMESTAMP(EditTime) + row[2] AnsType + row[3] Shuffle + row[4] Stem + row[5] Feedback + row[6] MedCod + row[7] NumHits + row[8] NumHitsNotBlank + row[9] Score + */ /***** Write rows *****/ for (NumQst = 0; @@ -872,7 +891,8 @@ static void Tst_ShowTstTagsPresentInATestResult (long TstCod) /***** Get all tags of questions in this test *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get tags" " present in a test result", - "SELECT tst_tags.TagTxt FROM" + "SELECT tst_tags.TagTxt" // row[0] + " FROM" " (SELECT DISTINCT(tst_question_tags.TagCod)" " FROM tst_question_tags,tst_exam_questions" " WHERE tst_exam_questions.TstCod=%ld" @@ -933,19 +953,16 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank /***** Get row of the result of the query *****/ row = mysql_fetch_row (mysql_res); /* - row[ 0] QstCod - row[ 1] UNIX_TIMESTAMP(EditTime) - row[ 2] AnsType - row[ 3] Shuffle - row[ 4] Stem - row[ 5] Feedback - row[ 6] MediaName - row[ 7] MediaType - row[ 8] MediaTitle - row[ 9] MediaURL - row[10] NumHits - row[11] NumHitsNotBlank - row[12] Score + row[0] QstCod + row[1] UNIX_TIMESTAMP(EditTime) + row[2] AnsType + row[3] Shuffle + row[4] Stem + row[5] Feedback + row[6] MedCod + row[7] NumHits + row[8] NumHitsNotBlank + row[9] Score */ /***** Get the code of question (row[0]) *****/ @@ -994,27 +1011,24 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank /********** Write a row of a test, with one question and its answer **********/ /*****************************************************************************/ -void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, - struct UsrData *UsrDat, - struct Game *Game, - unsigned NumQst,long QstCod,MYSQL_ROW row, - double *ScoreThisQst,bool *AnswerIsNotBlank) +static void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, + struct UsrData *UsrDat, + struct Game *Game, + unsigned NumQst,long QstCod,MYSQL_ROW row, + double *ScoreThisQst,bool *AnswerIsNotBlank) { extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; /* - row[ 0] QstCod - row[ 1] UNIX_TIMESTAMP(EditTime) - row[ 2] AnsType - row[ 3] Shuffle - row[ 4] Stem - row[ 5] Feedback - row[ 6] MediaName - row[ 7] MediaType - row[ 8] MediaTitle - row[ 9] MediaURL - row[10] NumHits - row[11] NumHitsNotBlank - row[12] Score + row[0] QstCod + row[1] UNIX_TIMESTAMP(EditTime) + row[2] AnsType + row[3] Shuffle + row[4] Stem + row[5] Feedback + row[6] MedCod + row[7] NumHits + row[8] NumHitsNotBlank + row[9] Score */ /***** Create test question *****/ @@ -1034,16 +1048,19 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio "", Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); - /***** Write stem (row[4]), media data (row[6], row[7], row[8], row[9]), - answers depending on shuffle (row[3]) and feedback (row[5]) *****/ + /***** Write stem (row[4]) *****/ fprintf (Gbl.F.Out,"", Gbl.RowEvenOdd); Tst_WriteQstStem (row[4],"TEST_EXA"); - Med_GetMediaDataFromRow (row[6],row[7],row[8],row[9],&Gbl.Test.Media); + + /***** Get and show media (row[6]) *****/ + Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[6]); + Med_GetMediaDataByCod (&Gbl.Test.Media); Med_ShowMedia (&Gbl.Test.Media, "TEST_IMG_SHOW_STEM_CONTAINER", "TEST_IMG_SHOW_STEM"); + /***** Write answers depending on shuffle (row[3]) and feedback (row[5]) *****/ switch (ActionToDoWithQuestions) { case Tst_SHOW_TEST_TO_ANSWER: @@ -1639,7 +1656,10 @@ static unsigned long Tst_GetAllTagsFromCurrentCrs (MYSQL_RES **mysql_res) { /***** Get available tags from database *****/ return DB_QuerySELECT (mysql_res,"can not get available tags", - "SELECT TagCod,TagTxt,TagHidden FROM tst_tags" + "SELECT TagCod," // row[0] + "TagTxt," // row[1] + "TagHidden" // row[2] + " FROM tst_tags" " WHERE CrsCod=%ld" " ORDER BY TagTxt", Gbl.CurrentCrs.Crs.CrsCod); @@ -1677,6 +1697,11 @@ static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res, bool TagHidden = false; const char *Ptr; char TagText[Tst_MAX_BYTES_TAG + 1]; + /* + row[0] TagCod + row[1] TagTxt + row[2] TagHidden + */ /***** Label *****/ fprintf (Gbl.F.Out,"" @@ -1785,6 +1810,11 @@ static void Tst_ShowFormEditTags (void) NumRow++) { row = mysql_fetch_row (mysql_res); + /* + row[0] TagCod + row[1] TagTxt + row[2] TagHidden + */ if ((TagCod = Str_ConvertStrCodToLongCod (row[0])) < 0) Lay_ShowErrorAndExit ("Wrong code of tag."); @@ -2126,7 +2156,9 @@ bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void) /***** Get pluggability of tests for current course from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get configuration of test", - "SELECT Pluggable FROM tst_config WHERE CrsCod=%ld", + "SELECT Pluggable" // row[0] + " FROM tst_config" + " WHERE CrsCod=%ld", Gbl.CurrentCrs.Crs.CrsCod); if (NumRows == 0) @@ -2446,19 +2478,16 @@ static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res) /***** Select questions *****/ /* Start query */ snprintf (Query,Tst_MAX_BYTES_QUERY_TEST + 1, - "SELECT tst_questions.QstCod," // row[ 0] - "UNIX_TIMESTAMP(tst_questions.EditTime) AS F," // row[ 1] - "tst_questions.AnsType," // row[ 2] - "tst_questions.Shuffle," // row[ 3] - "tst_questions.Stem," // row[ 4] - "tst_questions.Feedback," // row[ 5] - "tst_questions.MediaName," // row[ 6] - "tst_questions.MediaType," // row[ 7] - "tst_questions.MediaTitle," // row[ 8] - "tst_questions.MediaURL," // row[ 9] - "tst_questions.NumHits," // row[10] - "tst_questions.NumHitsNotBlank," // row[11] - "tst_questions.Score" // row[12] + "SELECT tst_questions.QstCod," // row[0] + "UNIX_TIMESTAMP(tst_questions.EditTime)," // row[1] + "tst_questions.AnsType," // row[2] + "tst_questions.Shuffle," // row[3] + "tst_questions.Stem," // row[4] + "tst_questions.Feedback," // row[5] + "tst_questions.MedCod," // row[6] + "tst_questions.NumHits," // row[7] + "tst_questions.NumHitsNotBlank," // row[8] + "tst_questions.Score" // row[9] " FROM tst_questions"); if (!Gbl.Test.Tags.All) Str_Concat (Query,",tst_question_tags,tst_tags", @@ -2619,19 +2648,16 @@ static unsigned long Tst_GetQuestionsForTest (MYSQL_RES **mysql_res) // Select only questions with tags // DISTINCTROW is necessary to not repeat questions snprintf (Query,Tst_MAX_BYTES_QUERY_TEST + 1, - "SELECT DISTINCTROW tst_questions.QstCod," // row[ 0] - "UNIX_TIMESTAMP(tst_questions.EditTime)," // row[ 1] - "tst_questions.AnsType," // row[ 2] - "tst_questions.Shuffle," // row[ 3] - "tst_questions.Stem," // row[ 4] - "tst_questions.Feedback," // row[ 5] - "tst_questions.MediaName," // row[ 6] - "tst_questions.MediaType," // row[ 7] - "tst_questions.MediaTitle," // row[ 8] - "tst_questions.MediaURL," // row[ 9] - "tst_questions.NumHits," // row[10] - "tst_questions.NumHitsNotBlank," // row[11] - "tst_questions.Score" // row[12] + "SELECT DISTINCTROW tst_questions.QstCod," // row[0] + "UNIX_TIMESTAMP(tst_questions.EditTime)," // row[1] + "tst_questions.AnsType," // row[2] + "tst_questions.Shuffle," // row[3] + "tst_questions.Stem," // row[4] + "tst_questions.Feedback," // row[5] + "tst_questions.MedCod," // row[6] + "tst_questions.NumHits," // row[7] + "tst_questions.NumHitsNotBlank," // row[8] + "tst_questions.Score" // row[9] " FROM tst_questions,tst_question_tags,tst_tags" " WHERE tst_questions.CrsCod=%ld" " AND tst_questions.QstCod NOT IN" @@ -2745,19 +2771,16 @@ bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res) { /***** Get data of a question from database *****/ return (DB_QuerySELECT (mysql_res,"can not get data of a question", - "SELECT QstCod," // row[ 0] - "UNIX_TIMESTAMP(EditTime)," // row[ 1] - "AnsType," // row[ 2] - "Shuffle," // row[ 3] - "Stem," // row[ 4] - "Feedback," // row[ 5] - "MediaName," // row[ 6] - "MediaType," // row[ 7] - "MediaTitle," // row[ 8] - "MediaURL," // row[ 9] - "NumHits," // row[10] - "NumHitsNotBlank," // row[11] - "Score" // row[12] + "SELECT QstCod," // row[0] + "UNIX_TIMESTAMP(EditTime)," // row[1] + "AnsType," // row[2] + "Shuffle," // row[3] + "Stem," // row[4] + "Feedback," // row[5] + "MedCod," // row[6] + "NumHits," // row[7] + "NumHitsNotBlank," // row[8] + "Score" // row[9] " FROM tst_questions" " WHERE QstCod=%ld", QstCod) == 1); @@ -2859,19 +2882,16 @@ static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows, row = mysql_fetch_row (mysql_res); /* - row[ 0] QstCod - row[ 1] UNIX_TIMESTAMP(EditTime) - row[ 2] AnsType - row[ 3] Shuffle - row[ 4] Stem - row[ 5] Feedback - row[ 6] MediaName - row[ 7] MediaType - row[ 8] MediaTitle - row[ 9] MediaURL - row[10] NumHits - row[11] NumHitsNotBlank - row[12] Score + row[0] QstCod + row[1] UNIX_TIMESTAMP(EditTime) + row[2] AnsType + row[3] Shuffle + row[4] Stem + row[5] Feedback + row[6] MedCod + row[7] NumHits + row[8] NumHitsNotBlank + row[9] Score */ /***** Create test question *****/ Tst_QstConstructor (); @@ -2958,34 +2978,38 @@ static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows, } fprintf (Gbl.F.Out,""); - /* Write stem (row[4]), media data (row[6], row[7], row[8], row[9]), - feedback (row[5]) and answers */ + /* Write stem (row[4]) */ fprintf (Gbl.F.Out,"", Gbl.RowEvenOdd); Tst_WriteQstStem (row[4],"TEST_EDI"); - Med_GetMediaDataFromRow (row[6],row[7],row[8],row[9],&Gbl.Test.Media); + + /***** Get and show media (row[6]) *****/ + Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[6]); + Med_GetMediaDataByCod (&Gbl.Test.Media); Med_ShowMedia (&Gbl.Test.Media, "TEST_IMG_EDIT_LIST_STEM_CONTAINER", "TEST_IMG_EDIT_LIST_STEM"); + + /* Write feedback (row[5]) and answers */ Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT"); Tst_WriteAnswersEdit (Gbl.Test.QstCod); fprintf (Gbl.F.Out,""); /* Get number of hits (number of times that the question has been answered, - including blank answers) (row[10]) */ - if (sscanf (row[10],"%lu",&NumHitsThisQst) != 1) + including blank answers) (row[7]) */ + if (sscanf (row[7],"%lu",&NumHitsThisQst) != 1) Lay_ShowErrorAndExit ("Wrong number of hits to a question."); /* Get number of hits not blank (number of times that the question has been answered - with a not blank answer) (row[11]) */ - if (sscanf (row[11],"%lu",&NumHitsNotBlankThisQst) != 1) + with a not blank answer) (row[8]) */ + if (sscanf (row[8],"%lu",&NumHitsNotBlankThisQst) != 1) Lay_ShowErrorAndExit ("Wrong number of hits not blank to a question."); - /* Get the acumulated score of the question (row[12]) */ + /* Get the acumulated score of the question (row[9]) */ Str_SetDecimalPointToUS (); // To get the decimal point as a dot - if (sscanf (row[12],"%lf",&TotalScoreThisQst) != 1) + if (sscanf (row[9],"%lf",&TotalScoreThisQst) != 1) Lay_ShowErrorAndExit ("Wrong score of a question."); Str_SetDecimalPointToLocal (); // Return to local system @@ -3113,19 +3137,16 @@ static void Tst_ListOneOrMoreQuestionsForSelection (long GamCod, row = mysql_fetch_row (mysql_res); /* - row[ 0] QstCod - row[ 1] UNIX_TIMESTAMP(EditTime) - row[ 2] AnsType - row[ 3] Shuffle - row[ 4] Stem - row[ 5] Feedback - row[ 6] MediaName - row[ 7] MediaType - row[ 8] MediaTitle - row[ 9] MediaURL - row[10] NumHits - row[11] NumHitsNotBlank - row[12] Score + row[0] QstCod + row[1] UNIX_TIMESTAMP(EditTime) + row[2] AnsType + row[3] Shuffle + row[4] Stem + row[5] Feedback + row[6] MedCod + row[7] NumHits + row[8] NumHitsNotBlank + row[9] Score */ /***** Create test question *****/ Tst_QstConstructor (); @@ -3193,16 +3214,22 @@ static void Tst_ListOneOrMoreQuestionsForSelection (long GamCod, fprintf (Gbl.F.Out,""); - /* Write stem (row[4]), media data (row[6], row[7], row[8], row[9]), - feedback (row[5]) and answers */ + /* Write stem (row[4]) */ fprintf (Gbl.F.Out,"", Gbl.RowEvenOdd); Tst_WriteQstStem (row[4],"TEST_EDI"); - Med_GetMediaDataFromRow (row[6],row[7],row[8],row[9],&Gbl.Test.Media); + + /***** Get and show media (row[6]) *****/ + Gbl.Test.Media.MedCod = Str_ConvertStrCodToLongCod (row[6]); + Med_GetMediaDataByCod (&Gbl.Test.Media); Med_ShowMedia (&Gbl.Test.Media, "TEST_IMG_EDIT_LIST_STEM_CONTAINER", "TEST_IMG_EDIT_LIST_STEM"); + + /* Write feedback (row[5]) */ Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT"); + + /* Write answers */ Tst_WriteAnswersEdit (Gbl.Test.QstCod); fprintf (Gbl.F.Out,"" ""); @@ -3255,11 +3282,8 @@ unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle) "SELECT AnsInd," // row[0] "Answer," // row[1] "Feedback," // row[2] - "MediaName," // row[3] - "MediaType," // row[4] - "MediaTitle," // row[5] - "MediaURL," // row[6] - "Correct" // row[7] + "MedCod," // row[3] + "Correct" // row[4] " FROM tst_answers WHERE QstCod=%ld ORDER BY %s", QstCod, Shuffle ? "RAND(NOW())" : @@ -3292,11 +3316,8 @@ static void Tst_WriteAnswersEdit (long QstCod) row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Write the answers *****/ switch (Gbl.Test.AnswerType) @@ -3362,15 +3383,16 @@ static void Tst_WriteAnswersEdit (long QstCod) Feedback,LengthFeedback,false); } - /* Get media data (row[3], row[4], row[5], row[6]) */ - Med_GetMediaDataFromRow (row[3],row[4],row[5],row[6], - &Gbl.Test.Answer.Options[NumOpt].Media); + /* Get media (row[3]) */ + Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media); - /* Put an icon that indicates whether the answer is correct or wrong */ + /* Put an icon that indicates whether the answer + is correct or wrong (row[4]) */ fprintf (Gbl.F.Out,"" "", Gbl.RowEvenOdd); - if (row[7][0] == 'Y') + if (row[4][0] == 'Y') fprintf (Gbl.F.Out,"\"%s\"", @@ -3467,11 +3489,8 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Write answer depending on type *****/ switch (Gbl.Test.AnswerType) @@ -3585,11 +3604,8 @@ static void Tst_WriteTFAnsAssessTest (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Check if number of rows is correct *****/ Tst_CheckIfNumberOfAnswersIsOne (); @@ -3677,11 +3693,8 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Start table *****/ @@ -3719,9 +3732,9 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle Gbl.Test.Answer.Options[NumOpt].Text, Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); - /***** Get media data (row[3], row[4], row[5], row[6]) *****/ - Med_GetMediaDataFromRow (row[3],row[4],row[5],row[6], - &Gbl.Test.Answer.Options[NumOpt].Media); + /***** Get media (row[3]) *****/ + Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media); /***** Write selectors and letter of this option *****/ fprintf (Gbl.F.Out,"" @@ -3803,11 +3816,8 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ for (NumOpt = 0; NumOpt < Gbl.Test.Answer.NumOptions; @@ -3842,12 +3852,12 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); } - /***** Get media data (row[3], row[4], row[5], row[6]) *****/ - Med_GetMediaDataFromRow (row[3],row[4],row[5],row[6], - &Gbl.Test.Answer.Options[NumOpt].Media); + /***** Get media (row[3]) *****/ + Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media); - /***** Assign correctness (row[7]) of this answer (this option) *****/ - Gbl.Test.Answer.Options[NumOpt].Correct = (row[7][0] == 'Y'); + /***** Assign correctness (row[4]) of this answer (this option) *****/ + Gbl.Test.Answer.Options[NumOpt].Correct = (row[4][0] == 'Y'); } /***** Get indexes for this question from string *****/ @@ -4050,11 +4060,8 @@ static void Tst_WriteChoiceAnsViewGame (struct Game *Game, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Start table *****/ @@ -4092,9 +4099,9 @@ static void Tst_WriteChoiceAnsViewGame (struct Game *Game, Gbl.Test.Answer.Options[NumOpt].Text, Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); - /***** Get media data (row[3], row[4], row[5], row[6]) *****/ - Med_GetMediaDataFromRow (row[3],row[4],row[5],row[6], - &Gbl.Test.Answer.Options[NumOpt].Media); + /***** Get media (row[3]) *****/ + Gbl.Test.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Gbl.Test.Answer.Options[NumOpt].Media); /***** Write letter of this option *****/ fprintf (Gbl.F.Out,"" @@ -4168,11 +4175,8 @@ static void Tst_WriteTextAnsAssessTest (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Get text and correctness of answers for this question from database (one row per answer) *****/ for (NumOpt = 0; @@ -4206,8 +4210,8 @@ static void Tst_WriteTextAnsAssessTest (struct UsrData *UsrDat, Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); } - /***** Assign correctness (row[7]) of this answer (this option) *****/ - Gbl.Test.Answer.Options[NumOpt].Correct = (row[7][0] == 'Y'); + /***** Assign correctness (row[4]) of this answer (this option) *****/ + Gbl.Test.Answer.Options[NumOpt].Correct = (row[4][0] == 'Y'); } /***** Header with the title of each column *****/ @@ -4362,11 +4366,8 @@ static void Tst_WriteIntAnsAssessTest (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Check if number of rows is correct *****/ Tst_CheckIfNumberOfAnswersIsOne (); @@ -4478,11 +4479,8 @@ static void Tst_WriteFloatAnsAssessTest (struct UsrData *UsrDat, row[0] AnsInd row[1] Answer row[2] Feedback - row[3] MediaName - row[4] MediaType - row[5] MediaTitle - row[6] MediaURL - row[7] Correct + row[3] MedCod + row[4] Correct */ /***** Check if number of rows is correct *****/ if (Gbl.Test.Answer.NumOptions != 2) @@ -5010,7 +5008,11 @@ static void Tst_PutFormEditOneQst (char Stem[Cns_MAX_BYTES_TEXT + 1], NumRow++) { row = mysql_fetch_row (mysql_res); - + /* + row[0] TagCod + row[1] TagTxt + row[2] TagHidden + */ fprintf (Gbl.F.Out,"