// swad_timeline_comment.c: social timeline comments /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. This file is part of SWAD core. Copyright (C) 1999-2021 Antonio Caņas Vargas This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General 3 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /*****************************************************************************/ /*********************************** Headers *********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // For PATH_MAX #include // For asprintf #include "swad_database.h" #include "swad_forum.h" #include "swad_global.h" #include "swad_message.h" #include "swad_photo.h" #include "swad_profile.h" #include "swad_timeline.h" #include "swad_timeline_favourite.h" #include "swad_timeline_note.h" #include "swad_timeline_publication.h" #include "swad_timeline_share.h" /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /************************* Private constants and types ***********************/ /*****************************************************************************/ #define TL_COM_NUM_VISIBLE_COMMENTS 3 // Maximum number of comments visible before expanding them /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /************************* Private global variables **************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void TL_Com_FormToShowHiddenComments (Act_Action_t ActionGbl,Act_Action_t ActionUsr, long NotCod, char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialComments); static unsigned TL_Com_WriteHiddenComments (struct TL_Timeline *Timeline, long NotCod, char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialCommentsToGet); static void TL_Com_WriteOneCommentInList (struct TL_Timeline *Timeline, MYSQL_RES *mysql_res); static void TL_Com_LinkToShowOnlyLatestComments (const char IdComments[Frm_MAX_BYTES_ID + 1]); static void TL_Com_LinkToShowPreviousComments (const char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialComments); static void TL_Com_PutIconToToggleComments (const char *UniqueId, const char *Icon,const char *Text); static void TL_Com_WriteComment (struct TL_Timeline *Timeline, struct TL_Com_Comment *Com, TL_TopMessage_t TopMessage,long UsrCod, TL_ShowAlone_t ShowCommentAlone); // Comment is shown alone, not in a list static void TL_Com_WriteAuthorComment (struct UsrData *UsrDat); static void TL_Com_PutFormToRemoveComment (const struct TL_Timeline *Timeline, long PubCod); static long TL_Com_ReceiveComment (void); static void TL_Com_RequestRemovalComment (struct TL_Timeline *Timeline); static void TL_Com_PutParamsRemoveComment (void *Timeline); static void TL_Com_RemoveComment (void); static void TL_Com_GetDataOfCommentFromRow (MYSQL_ROW row,struct TL_Com_Comment *Com); static void TL_Com_ResetComment (struct TL_Com_Comment *Com); /*****************************************************************************/ /********* Put an icon to toggle on/off the form to comment a note ***********/ /*****************************************************************************/ void TL_Com_PutIconToToggleComment (const char UniqueId[Frm_MAX_BYTES_ID + 1]) { extern const char *Txt_Comment; /***** Link to toggle on/off the form to comment a note *****/ HTM_DIV_Begin ("id=\"%s_ico\" class=\"TL_ICO_COM_OFF\"",UniqueId); HTM_A_Begin ("href=\"\" onclick=\"toggleNewComment ('%s');return false;\"", UniqueId); Ico_PutIcon ("comment-regular.svg",Txt_Comment,"CONTEXT_ICO_16x16"); HTM_A_End (); HTM_DIV_End (); } /*****************************************************************************/ /********** Put an icon to toggle on/off the form to comment a note **********/ /*****************************************************************************/ void TL_Com_PutIconCommentDisabled (void) { extern const char *Txt_Comment; /***** Disabled icon to comment a note *****/ HTM_DIV_Begin ("class=\"TL_ICO_COM_OFF TL_ICO_DISABLED\""); Ico_PutIcon ("edit.svg",Txt_Comment,"ICO16x16"); HTM_DIV_End (); } /*****************************************************************************/ /************************* Form to comment a note ****************************/ /*****************************************************************************/ void TL_Com_PutHiddenFormToWriteNewComment (const struct TL_Timeline *Timeline, long NotCod, const char IdNewComment[Frm_MAX_BYTES_ID + 1]) { extern const char *Txt_New_TIMELINE_comment; bool ShowPhoto = false; char PhotoURL[PATH_MAX + 1]; /***** Start container *****/ HTM_DIV_Begin ("id=\"%s\" class=\"TL_FORM_NEW_COM TL_RIGHT_WIDTH\"" " style=\"display:none;\"", IdNewComment); /***** Left: write author's photo (my photo) *****/ HTM_DIV_Begin ("class=\"TL_COM_PHOTO\""); ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (&Gbl.Usrs.Me.UsrDat,PhotoURL); Pho_ShowUsrPhoto (&Gbl.Usrs.Me.UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO30x40",Pho_ZOOM,true); // Use unique id HTM_DIV_End (); /***** Right: form to write the comment *****/ /* Start right container */ HTM_DIV_Begin ("class=\"TL_COM_CONT TL_COMM_WIDTH\""); /* Begin form to write the post */ TL_FormStart (Timeline,ActRcvTL_ComGbl,ActRcvTL_ComUsr); TL_Not_PutHiddenParamNotCod (NotCod); /* Textarea and button */ TL_PutTextarea (Txt_New_TIMELINE_comment, "TL_COM_TEXTAREA TL_COMM_WIDTH"); /* End form */ Frm_EndForm (); /* End right container */ HTM_DIV_End (); /***** End container *****/ HTM_DIV_End (); } /*****************************************************************************/ /********************* Get number of comments in a note **********************/ /*****************************************************************************/ unsigned long TL_Com_GetNumCommentsInNote (long NotCod) { return DB_QueryCOUNT ("can not get number of comments in a note", "SELECT COUNT(*) FROM tl_pubs" " WHERE NotCod=%ld AND PubType=%u", NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); } /*****************************************************************************/ /*********************** Write comments in a note ****************************/ /*****************************************************************************/ void TL_Com_WriteCommentsInNote (struct TL_Timeline *Timeline, const struct TL_Not_Note *Not, unsigned NumComments) { MYSQL_RES *mysql_res; unsigned NumInitialComments; unsigned NumFinalCommentsToGet; unsigned NumFinalCommentsGot; unsigned NumCom; char IdComments[Frm_MAX_BYTES_ID + 1]; /***** Compute how many initial comments will be hidden and how many final comments will be visible *****/ // Never hide only one comment // So, the number of comments initially hidden must be 0 or >= 2 if (NumComments <= TL_COM_NUM_VISIBLE_COMMENTS + 1) { NumInitialComments = 0; NumFinalCommentsToGet = NumComments; } else { NumInitialComments = NumComments - TL_COM_NUM_VISIBLE_COMMENTS; NumFinalCommentsToGet = TL_COM_NUM_VISIBLE_COMMENTS; } /***** Get last comments of this note from database *****/ NumFinalCommentsGot = (unsigned) DB_QuerySELECT (&mysql_res,"can not get comments", "SELECT * FROM " "(" "SELECT tl_pubs.PubCod," // row[0] "tl_pubs.PublisherCod," // row[1] "tl_pubs.NotCod," // row[2] "UNIX_TIMESTAMP(" "tl_pubs.TimePublish)," // row[3] "tl_comments.Txt," // row[4] "tl_comments.MedCod" // row[5] " FROM tl_pubs,tl_comments" " WHERE tl_pubs.NotCod=%ld" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments.PubCod" " ORDER BY tl_pubs.PubCod DESC LIMIT %u" ") AS comments" " ORDER BY PubCod", Not->NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE, NumFinalCommentsToGet); /* Before clicking "See prev..." --> After clicking "See prev..." _________________________________ _________________________________ | div con_ | | div con_ | | (hidden) | | (visible) | | _____________________________ | | _____________________________ | | | v See only the latest | | | | v See only the latest | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | div | | div updated | | which content | | _____________________________ | | will be updated via AJAX | | | ul com_ | | | (parent of parent of form) | | | _________________________ | | | | | | | li (comment 1) | | | | | | | |_________________________| | | | | | | | ... | | | | | | | |_________________________| | | | | | | | li (comment n) | | | | | --> | | |_________________________| | | | | | |_____________________________| | | _____________________________ | | _____________________________ | | | div exp_ | | | | div exp_ | | | | _________________________ | | | | (hidden) | | | | | form | | | | | | | | | | _____________________ | | | | | _____________________ | | | | | | ^ See prev.comments | | | | | | | ^ See prev.comments | | | | | | |_____________________| | | | | | |_____________________| | | | | |_________________________| | | | | | | | |_____________________________| | | |_____________________________| | |_________________________________| |_________________________________| _________________________________ _________________________________ | ul com_ | | ul com_ | | _________________________ | | _________________________ | | | li (comment 1) | | | | li (comment 1) | | | |_________________________| | | |_________________________| | | | ... | | | | ... | | | |_________________________| | | |_________________________| | | | li (comment n) | | | | li (comment n) | | | |_________________________| | | |_________________________| | |_________________________________| |_________________________________| */ /***** Link to show initial hidden comments *****/ if (NumInitialComments) { /***** Create unique id for list of hidden comments *****/ Frm_SetUniqueId (IdComments); /***** Link (initially hidden) to show only the latest comments *****/ TL_Com_LinkToShowOnlyLatestComments (IdComments); /***** Div which content will be updated via AJAX *****/ HTM_DIV_Begin ("id=\"%s\" class=\"TL_RIGHT_WIDTH\"",IdComments); TL_Com_FormToShowHiddenComments (ActShoHidTL_ComGbl,ActShoHidTL_ComUsr, Not->NotCod, IdComments, NumInitialComments); HTM_DIV_End (); } /***** List final visible comments *****/ if (NumFinalCommentsGot) { HTM_UL_Begin ("class=\"TL_LIST\""); for (NumCom = 0; NumCom < NumFinalCommentsGot; NumCom++) TL_Com_WriteOneCommentInList (Timeline,mysql_res); HTM_UL_End (); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /********** Form to show hidden coments in global or user timeline ***********/ /*****************************************************************************/ static void TL_Com_FormToShowHiddenComments (Act_Action_t ActionGbl,Act_Action_t ActionUsr, long NotCod, char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialComments) { extern const char *The_ClassFormLinkInBox[The_NUM_THEMES]; extern const char *Txt_See_the_previous_X_COMMENTS; char *OnSubmit; HTM_DIV_Begin ("id=\"exp_%s\" class=\"TL_EXPAND_COM TL_RIGHT_WIDTH\"", IdComments); /***** Form and icon-text to show hidden comments *****/ /* Begin form */ if (Gbl.Usrs.Other.UsrDat.UsrCod > 0) { if (asprintf (&OnSubmit,"toggleComments('%s');" "updateDivHiddenComments(this," "'act=%ld&ses=%s&NotCod=%ld&IdComments=%s&NumHidCom=%u&OtherUsrCod=%s');" " return false;", // return false is necessary to not submit form IdComments, Act_GetActCod (ActionUsr), Gbl.Session.Id, NotCod, IdComments, NumInitialComments, Gbl.Usrs.Other.UsrDat.EncryptedUsrCod) < 0) Lay_NotEnoughMemoryExit (); Frm_StartFormUniqueAnchorOnSubmit (ActUnk,"timeline",OnSubmit); } else { if (asprintf (&OnSubmit,"toggleComments('%s');" "updateDivHiddenComments(this," "'act=%ld&ses=%s&NotCod=%ld&IdComments=%s&NumHidCom=%u');" " return false;", // return false is necessary to not submit form IdComments, Act_GetActCod (ActionGbl), Gbl.Session.Id, NotCod, IdComments, NumInitialComments) < 0) Lay_NotEnoughMemoryExit (); Frm_StartFormUniqueAnchorOnSubmit (ActUnk,NULL,OnSubmit); } /* Put icon and text with link to show the first hidden comments */ HTM_BUTTON_SUBMIT_Begin (NULL,The_ClassFormLinkInBox[Gbl.Prefs.Theme],NULL); Ico_PutIconTextLink ("angle-up.svg", Str_BuildStringLong (Txt_See_the_previous_X_COMMENTS, (long) NumInitialComments)); Str_FreeString (); HTM_BUTTON_End (); /* End form */ Frm_EndForm (); /* Free allocated memory */ free (OnSubmit); HTM_DIV_End (); } /*****************************************************************************/ /********************** Write hidden comments via AJAX ***********************/ /*****************************************************************************/ void TL_Com_ShowHiddenCommentsUsr (void) { /***** Get user whom profile is displayed *****/ Usr_GetParamOtherUsrCodEncryptedAndGetUsrData (); /***** Show hidden comments *****/ TL_Com_ShowHiddenCommentsGbl (); } void TL_Com_ShowHiddenCommentsGbl (void) { struct TL_Timeline Timeline; long NotCod; char IdComments[Frm_MAX_BYTES_ID + 1]; unsigned NumInitialCommentsToGet; unsigned NumInitialCommentsGot; /***** Reset timeline context *****/ TL_ResetTimeline (&Timeline); /***** Get parameters *****/ /* Get note code */ NotCod = TL_Not_GetParamNotCod (); /* Get identifier */ Par_GetParToText ("IdComments",IdComments,Frm_MAX_BYTES_ID); /* Get number of comments to get */ NumInitialCommentsToGet = (unsigned) Par_GetParToLong ("NumHidCom"); /***** Write HTML inside DIV with hidden comments *****/ NumInitialCommentsGot = TL_Com_WriteHiddenComments (&Timeline, NotCod,IdComments,NumInitialCommentsToGet); /***** Link to show the first comments *****/ TL_Com_LinkToShowPreviousComments (IdComments,NumInitialCommentsGot); } /*****************************************************************************/ /**************************** Write hidden comments **************************/ /*****************************************************************************/ // Returns the number of comments got static unsigned TL_Com_WriteHiddenComments (struct TL_Timeline *Timeline, long NotCod, char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialCommentsToGet) { MYSQL_RES *mysql_res; unsigned long NumInitialCommentsGot; unsigned long NumCom; /***** Get comments of this note from database *****/ NumInitialCommentsGot = (unsigned) DB_QuerySELECT (&mysql_res,"can not get comments", "SELECT tl_pubs.PubCod," // row[0] "tl_pubs.PublisherCod," // row[1] "tl_pubs.NotCod," // row[2] "UNIX_TIMESTAMP(" "tl_pubs.TimePublish)," // row[3] "tl_comments.Txt," // row[4] "tl_comments.MedCod" // row[5] " FROM tl_pubs,tl_comments" " WHERE tl_pubs.NotCod=%ld" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments.PubCod" " ORDER BY tl_pubs.PubCod" " LIMIT %lu", NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE, NumInitialCommentsToGet); /***** List with comments *****/ HTM_UL_Begin ("id=\"com_%s\" class=\"TL_LIST\"",IdComments); for (NumCom = 0; NumCom < NumInitialCommentsGot; NumCom++) TL_Com_WriteOneCommentInList (Timeline,mysql_res); HTM_UL_End (); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); return NumInitialCommentsGot; } /*****************************************************************************/ /************************* Write a comment in list ***************************/ /*****************************************************************************/ static void TL_Com_WriteOneCommentInList (struct TL_Timeline *Timeline, MYSQL_RES *mysql_res) { MYSQL_ROW row; struct TL_Com_Comment Com; /***** Initialize image *****/ Med_MediaConstructor (&Com.Content.Media); /***** Get data of comment *****/ row = mysql_fetch_row (mysql_res); TL_Com_GetDataOfCommentFromRow (row,&Com); /***** Write comment *****/ TL_Com_WriteComment (Timeline,&Com, TL_TOP_MESSAGE_NONE,-1L, TL_DONT_SHOW_ALONE); /***** Free image *****/ Med_MediaDestructor (&Com.Content.Media); } /*****************************************************************************/ /****************** Link to show only the latest comments ********************/ /*****************************************************************************/ static void TL_Com_LinkToShowOnlyLatestComments (const char IdComments[Frm_MAX_BYTES_ID + 1]) { extern const char *Txt_See_only_the_latest_COMMENTS; /***** Icon and text to show only the latest comments ****/ HTM_DIV_Begin ("id=\"con_%s\" class=\"TL_EXPAND_COM TL_RIGHT_WIDTH\"" " style=\"display:none;\"", // Hidden IdComments); TL_Com_PutIconToToggleComments (IdComments,"angle-down.svg", Txt_See_only_the_latest_COMMENTS); HTM_DIV_End (); } /*****************************************************************************/ /********************* Link to show the first comments ***********************/ /*****************************************************************************/ static void TL_Com_LinkToShowPreviousComments (const char IdComments[Frm_MAX_BYTES_ID + 1], unsigned NumInitialComments) { extern const char *Txt_See_the_previous_X_COMMENTS; /***** Icon and text to show only the latest comments ****/ HTM_DIV_Begin ("id=\"exp_%s\" class=\"TL_EXPAND_COM TL_RIGHT_WIDTH\"" " style=\"display:none;\"", // Hidden IdComments); TL_Com_PutIconToToggleComments (IdComments,"angle-up.svg", Str_BuildStringLong (Txt_See_the_previous_X_COMMENTS, (long) NumInitialComments)); Str_FreeString (); HTM_DIV_End (); } /*****************************************************************************/ /********** Put an icon to toggle on/off comments in a publication ***********/ /*****************************************************************************/ static void TL_Com_PutIconToToggleComments (const char *UniqueId, const char *Icon,const char *Text) { extern const char *The_ClassFormLinkInBox[The_NUM_THEMES]; char *OnClick; if (asprintf (&OnClick,"toggleComments('%s')",UniqueId) < 0) Lay_NotEnoughMemoryExit (); /***** Link to toggle on/off some divs *****/ HTM_BUTTON_BUTTON_Begin (Text,The_ClassFormLinkInBox[Gbl.Prefs.Theme],OnClick); Ico_PutIconTextLink (Icon,Text); HTM_BUTTON_End (); free (OnClick); } /*****************************************************************************/ /******************************** Write comment ******************************/ /*****************************************************************************/ static void TL_Com_WriteComment (struct TL_Timeline *Timeline, struct TL_Com_Comment *Com, TL_TopMessage_t TopMessage,long UsrCod, TL_ShowAlone_t ShowCommentAlone) // Comment is shown alone, not in a list { struct UsrData UsrDat; bool IAmTheAuthor; bool ShowPhoto = false; char PhotoURL[PATH_MAX + 1]; static unsigned NumDiv = 0; // Used to create unique div id for fav NumDiv++; if (ShowCommentAlone == TL_SHOW_ALONE) { Box_BoxBegin (NULL,NULL, NULL,NULL, NULL,Box_NOT_CLOSABLE); /***** Write sharer/commenter if distinct to author *****/ TL_WriteTopMessage (TopMessage,UsrCod); HTM_DIV_Begin ("class=\"TL_LEFT_PHOTO\""); HTM_DIV_End (); HTM_DIV_Begin ("class=\"TL_RIGHT_CONT TL_RIGHT_WIDTH\""); HTM_UL_Begin ("class=\"LIST_LEFT\""); } /***** Start list item *****/ HTM_LI_Begin (ShowCommentAlone == TL_SHOW_ALONE ? NULL : "class=\"TL_COM\""); if (Com->PubCod <= 0 || Com->NotCod <= 0 || Com->UsrCod <= 0) Ale_ShowAlert (Ale_ERROR,"Error in comment."); else { /***** Get author's data *****/ Usr_UsrDataConstructor (&UsrDat); UsrDat.UsrCod = Com->UsrCod; Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS); IAmTheAuthor = Usr_ItsMe (UsrDat.UsrCod); /***** Left: write author's photo *****/ HTM_DIV_Begin ("class=\"TL_COM_PHOTO\""); ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (&UsrDat,PhotoURL); Pho_ShowUsrPhoto (&UsrDat,ShowPhoto ? PhotoURL : NULL, "PHOTO30x40",Pho_ZOOM,true); // Use unique id HTM_DIV_End (); /***** Right: author's name, time, content, image and buttons *****/ HTM_DIV_Begin ("class=\"TL_COM_CONT TL_COMM_WIDTH\""); /* Write author's full name and nickname */ TL_Com_WriteAuthorComment (&UsrDat); /* Write date and time */ TL_WriteDateTime (Com->DateTimeUTC); /* Write content of the comment */ if (Com->Content.Txt[0]) { HTM_DIV_Begin ("class=\"TL_TXT\""); Msg_WriteMsgContent (Com->Content.Txt,Cns_MAX_BYTES_LONG_TEXT,true,false); HTM_DIV_End (); } /* Show image */ Med_ShowMedia (&Com->Content.Media,"TL_COM_MED_CONT TL_COMM_WIDTH", "TL_COM_MED TL_COMM_WIDTH"); /* Start foot container */ HTM_DIV_Begin ("class=\"TL_FOOT TL_COMM_WIDTH\""); /* Fav zone */ HTM_DIV_Begin ("id=\"fav_com_%s_%u\" class=\"TL_FAV_COM TL_FAV_WIDTH\"", Gbl.UniqueNameEncrypted,NumDiv); TL_Fav_PutFormToFavUnfComment (Com,TL_SHOW_FEW_USRS); HTM_DIV_End (); /* Put icon to remove this comment */ HTM_DIV_Begin ("class=\"TL_REM\""); if (IAmTheAuthor && ShowCommentAlone == TL_DONT_SHOW_ALONE) TL_Com_PutFormToRemoveComment (Timeline,Com->PubCod); HTM_DIV_End (); /* End foot container */ HTM_DIV_End (); /***** Free memory used for user's data *****/ Usr_UsrDataDestructor (&UsrDat); } /***** End list item *****/ HTM_LI_End (); if (ShowCommentAlone == TL_SHOW_ALONE) { HTM_UL_End (); HTM_DIV_End (); Box_BoxEnd (); } } /*****************************************************************************/ /********* Write name and nickname of author of a comment to a note **********/ /*****************************************************************************/ static void TL_Com_WriteAuthorComment (struct UsrData *UsrDat) { extern const char *Txt_My_public_profile; extern const char *Txt_Another_user_s_profile; bool ItsMe = Usr_ItsMe (UsrDat->UsrCod); /***** Show user's name inside form to go to user's public profile *****/ Frm_StartFormUnique (ActSeeOthPubPrf); Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); HTM_BUTTON_SUBMIT_Begin (ItsMe ? Txt_My_public_profile : Txt_Another_user_s_profile, "BT_LINK TL_COM_AUTHOR TL_COMM_AUTHOR_WIDTH DAT_BOLD",NULL); HTM_Txt (UsrDat->FullName); HTM_BUTTON_End (); Frm_EndForm (); } /*****************************************************************************/ /************************* Form to remove comment ****************************/ /*****************************************************************************/ static void TL_Com_PutFormToRemoveComment (const struct TL_Timeline *Timeline, long PubCod) { extern const char *Txt_Remove; /***** Form to remove publication *****/ TL_FormStart (Timeline,ActReqRemTL_ComGbl,ActReqRemTL_ComUsr); TL_Pub_PutHiddenParamPubCod (PubCod); Ico_PutIconLink ("trash.svg",Txt_Remove); Frm_EndForm (); } /*****************************************************************************/ /******************************* Comment a note ******************************/ /*****************************************************************************/ void TL_Com_ReceiveCommentUsr (void) { struct TL_Timeline Timeline; long NotCod; /***** Reset timeline context *****/ TL_ResetTimeline (&Timeline); /***** Get user whom profile is displayed *****/ Usr_GetParamOtherUsrCodEncryptedAndGetUsrData (); /***** Show user's profile *****/ Prf_ShowUserProfile (&Gbl.Usrs.Other.UsrDat); /***** Start section *****/ HTM_SECTION_Begin (TL_TIMELINE_SECTION_ID); /***** Receive comment in a note and write updated timeline after commenting (user) *****/ NotCod = TL_Com_ReceiveComment (); TL_ShowTimelineUsrHighlightingNot (&Timeline,NotCod); /***** End section *****/ HTM_SECTION_End (); } void TL_Com_ReceiveCommentGbl (void) { struct TL_Timeline Timeline; long NotCod; /***** Initialize timeline *****/ TL_InitTimelineGbl (&Timeline); /***** Receive comment in a note *****/ NotCod = TL_Com_ReceiveComment (); /***** Write updated timeline after commenting (global) *****/ TL_ShowTimelineGblHighlightingNot (&Timeline,NotCod); } static long TL_Com_ReceiveComment (void) { extern const char *Txt_The_original_post_no_longer_exists; struct TL_PostContent Content; struct TL_Not_Note Not; struct TL_Pub_Publication Pub; /***** Get data of note *****/ Not.NotCod = TL_Not_GetParamNotCod (); TL_Not_GetDataOfNoteByCod (&Not); if (Not.NotCod > 0) { /***** Get the content of the comment *****/ Par_GetParAndChangeFormat ("Txt",Content.Txt,Cns_MAX_BYTES_LONG_TEXT, Str_TO_RIGOROUS_HTML,true); /***** Initialize image *****/ Med_MediaConstructor (&Content.Media); /***** Get attached image (action, file and title) *****/ Content.Media.Width = TL_IMAGE_SAVED_MAX_WIDTH; Content.Media.Height = TL_IMAGE_SAVED_MAX_HEIGHT; Content.Media.Quality = TL_IMAGE_SAVED_QUALITY; Med_GetMediaFromForm (-1L,-1L,-1,&Content.Media,NULL,NULL); Ale_ShowAlerts (NULL); if (Content.Txt[0] || // Text not empty Content.Media.Status == Med_PROCESSED) // A media is attached { /***** Store media in filesystem and database *****/ Med_RemoveKeepOrStoreMedia (-1L,&Content.Media); /***** Publish *****/ /* Insert into publications */ Pub.NotCod = Not.NotCod; Pub.PublisherCod = Gbl.Usrs.Me.UsrDat.UsrCod; Pub.PubType = TL_Pub_COMMENT_TO_NOTE; TL_Pub_PublishPubInTimeline (&Pub); // Set Pub.PubCod /* Insert comment content in the database */ DB_QueryINSERT ("can not store comment content", "INSERT INTO tl_comments" " (PubCod,Txt,MedCod)" " VALUES" " (%ld,'%s',%ld)", Pub.PubCod, Content.Txt, Content.Media.MedCod); /***** Store notifications about the new comment *****/ Ntf_StoreNotifyEventsToAllUsrs (Ntf_EVENT_TIMELINE_COMMENT,Pub.PubCod); /***** Analyze content and store notifications about mentions *****/ Str_AnalyzeTxtAndStoreNotifyEventToMentionedUsrs (Pub.PubCod,Content.Txt); } /***** Free image *****/ Med_MediaDestructor (&Content.Media); } else Ale_ShowAlert (Ale_WARNING,Txt_The_original_post_no_longer_exists); return Not.NotCod; } /*****************************************************************************/ /**************** Request the removal of a comment in a note *****************/ /*****************************************************************************/ void TL_Com_RequestRemComUsr (void) { struct TL_Timeline Timeline; /***** Reset timeline context *****/ TL_ResetTimeline (&Timeline); /***** Get user whom profile is displayed *****/ Usr_GetParamOtherUsrCodEncryptedAndGetUsrData (); /***** Show user's profile *****/ Prf_ShowUserProfile (&Gbl.Usrs.Other.UsrDat); /***** Start section *****/ HTM_SECTION_Begin (TL_TIMELINE_SECTION_ID); /***** Request the removal of comment in note *****/ TL_Com_RequestRemovalComment (&Timeline); /***** Write timeline again (user) *****/ TL_ShowTimelineUsr (&Timeline); /***** End section *****/ HTM_SECTION_End (); } void TL_Com_RequestRemComGbl (void) { struct TL_Timeline Timeline; /***** Initialize timeline *****/ TL_InitTimelineGbl (&Timeline); /***** Request the removal of comment in note *****/ TL_Com_RequestRemovalComment (&Timeline); /***** Write timeline again (global) *****/ TL_ShowNoteAndTimelineGbl (&Timeline); } static void TL_Com_RequestRemovalComment (struct TL_Timeline *Timeline) { extern const char *Txt_The_comment_no_longer_exists; extern const char *Txt_Do_you_really_want_to_remove_the_following_comment; extern const char *Txt_Remove; struct TL_Com_Comment Com; bool ItsMe; /***** Initialize image *****/ Med_MediaConstructor (&Com.Content.Media); /***** Get data of comment *****/ Com.PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (&Com); if (Com.PubCod > 0) { ItsMe = Usr_ItsMe (Com.UsrCod); if (ItsMe) // I am the author of this comment { /***** Show question and button to remove comment *****/ /* Start alert */ Ale_ShowAlertAndButton1 (Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_following_comment); /* Show comment */ TL_Com_WriteComment (Timeline,&Com, TL_TOP_MESSAGE_NONE,-1L, TL_SHOW_ALONE); /* End alert */ Timeline->PubCod = Com.PubCod; // Publication to be removed if (Gbl.Usrs.Other.UsrDat.UsrCod > 0) Ale_ShowAlertAndButton2 (ActRemTL_ComUsr,"timeline",NULL, TL_Com_PutParamsRemoveComment,Timeline, Btn_REMOVE_BUTTON,Txt_Remove); else Ale_ShowAlertAndButton2 (ActRemTL_ComGbl,NULL,NULL, TL_Com_PutParamsRemoveComment,Timeline, Btn_REMOVE_BUTTON,Txt_Remove); } } else Ale_ShowAlert (Ale_WARNING,Txt_The_comment_no_longer_exists); /***** Free image *****/ Med_MediaDestructor (&Com.Content.Media); } /*****************************************************************************/ /******************** Put parameters to remove a comment *********************/ /*****************************************************************************/ static void TL_Com_PutParamsRemoveComment (void *Timeline) { if (Timeline) { if (Gbl.Usrs.Other.UsrDat.UsrCod > 0) Usr_PutParamOtherUsrCodEncrypted (Gbl.Usrs.Other.UsrDat.EncryptedUsrCod); else Usr_PutHiddenParamWho (((struct TL_Timeline *) Timeline)->Who); TL_Pub_PutHiddenParamPubCod (((struct TL_Timeline *) Timeline)->PubCod); } } /*****************************************************************************/ /***************************** Remove a comment ******************************/ /*****************************************************************************/ void TL_Com_RemoveComUsr (void) { struct TL_Timeline Timeline; /***** Reset timeline context *****/ TL_ResetTimeline (&Timeline); /***** Get user whom profile is displayed *****/ Usr_GetParamOtherUsrCodEncryptedAndGetUsrData (); /***** Show user's profile *****/ Prf_ShowUserProfile (&Gbl.Usrs.Other.UsrDat); /***** Start section *****/ HTM_SECTION_Begin (TL_TIMELINE_SECTION_ID); /***** Remove a comment *****/ TL_Com_RemoveComment (); /***** Write updated timeline after removing (user) *****/ TL_ShowTimelineUsr (&Timeline); /***** End section *****/ HTM_SECTION_End (); } void TL_Com_RemoveComGbl (void) { struct TL_Timeline Timeline; /***** Initialize timeline *****/ TL_InitTimelineGbl (&Timeline); /***** Remove a comment *****/ TL_Com_RemoveComment (); /***** Write updated timeline after removing (global) *****/ TL_ShowNoteAndTimelineGbl (&Timeline); } static void TL_Com_RemoveComment (void) { extern const char *Txt_The_comment_no_longer_exists; extern const char *Txt_Comment_removed; struct TL_Com_Comment Com; bool ItsMe; /***** Initialize image *****/ Med_MediaConstructor (&Com.Content.Media); /***** Get data of comment *****/ Com.PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (&Com); if (Com.PubCod > 0) { ItsMe = Usr_ItsMe (Com.UsrCod); if (ItsMe) // I am the author of this comment { /***** Remove media associated to comment and delete comment from database *****/ TL_Com_RemoveCommentMediaAndDBEntries (Com.PubCod); /***** Reset fields of comment *****/ TL_Com_ResetComment (&Com); /***** Message of success *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Comment_removed); } } else Ale_ShowAlert (Ale_WARNING,Txt_The_comment_no_longer_exists); /***** Free image *****/ Med_MediaDestructor (&Com.Content.Media); } /*****************************************************************************/ /*************** Remove comment media and database entries *******************/ /*****************************************************************************/ void TL_Com_RemoveCommentMediaAndDBEntries (long PubCod) { MYSQL_RES *mysql_res; MYSQL_ROW row; long MedCod; /***** Remove media associated to comment *****/ if (DB_QuerySELECT (&mysql_res,"can not get media", "SELECT MedCod" // row[0] " FROM tl_comments" " WHERE PubCod=%ld", PubCod) == 1) // Result should have a unique row { /* Get media code */ row = mysql_fetch_row (mysql_res); MedCod = Str_ConvertStrCodToLongCod (row[0]); /* Remove media */ Med_RemoveMedia (MedCod); } /* Free structure that stores the query result */ DB_FreeMySQLResult (&mysql_res); /***** Mark possible notifications on this comment as removed *****/ Ntf_MarkNotifAsRemoved (Ntf_EVENT_TIMELINE_COMMENT,PubCod); Ntf_MarkNotifAsRemoved (Ntf_EVENT_TIMELINE_FAV ,PubCod); Ntf_MarkNotifAsRemoved (Ntf_EVENT_TIMELINE_MENTION,PubCod); /***** Remove favs for this comment *****/ DB_QueryDELETE ("can not remove favs for comment", "DELETE FROM tl_comments_fav" " WHERE PubCod=%ld", PubCod); /***** Remove content of this comment *****/ DB_QueryDELETE ("can not remove a comment", "DELETE FROM tl_comments" " WHERE PubCod=%ld", PubCod); /***** Remove this comment *****/ DB_QueryDELETE ("can not remove a comment", "DELETE FROM tl_pubs" " WHERE PubCod=%ld" " AND PublisherCod=%ld" // Extra check: I am the author " AND PubType=%u", // Extra check: it's a comment PubCod, Gbl.Usrs.Me.UsrDat.UsrCod, (unsigned) TL_Pub_COMMENT_TO_NOTE); } /*****************************************************************************/ /******************* Get data of comment using its code **********************/ /*****************************************************************************/ void TL_Com_GetDataOfCommByCod (struct TL_Com_Comment *Com) { MYSQL_RES *mysql_res; MYSQL_ROW row; if (Com->PubCod > 0) { /***** Get data of comment from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get data of comment", "SELECT tl_pubs.PubCod," // row[0] "tl_pubs.PublisherCod," // row[1] "tl_pubs.NotCod," // row[2] "UNIX_TIMESTAMP(tl_pubs.TimePublish)," // row[3] "tl_comments.Txt," // row[4] "tl_comments.MedCod" // row[5] " FROM tl_pubs,tl_comments" " WHERE tl_pubs.PubCod=%ld" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments.PubCod", Com->PubCod,(unsigned) TL_Pub_COMMENT_TO_NOTE)) { /***** Get data of comment *****/ row = mysql_fetch_row (mysql_res); TL_Com_GetDataOfCommentFromRow (row,Com); } else /***** Reset fields of comment *****/ TL_Com_ResetComment (Com); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } else /***** Reset fields of comment *****/ TL_Com_ResetComment (Com); } /*****************************************************************************/ /********************** Get data of comment from row *************************/ /*****************************************************************************/ static void TL_Com_GetDataOfCommentFromRow (MYSQL_ROW row,struct TL_Com_Comment *Com) { /* row[0]: PubCod row[1]: PublisherCod row[2]: NotCod row[3]: TimePublish row[4]: Txt row[5]: MedCod */ /***** Get code of comment (row[0]) *****/ Com->PubCod = Str_ConvertStrCodToLongCod (row[0]); /***** Get (from) user code (row[1]) *****/ Com->UsrCod = Str_ConvertStrCodToLongCod (row[1]); /***** Get code of note (row[2]) *****/ Com->NotCod = Str_ConvertStrCodToLongCod (row[2]); /***** Get time of the note (row[3]) *****/ Com->DateTimeUTC = Dat_GetUNIXTimeFromStr (row[3]); /***** Get text content (row[4]) *****/ Str_Copy (Com->Content.Txt,row[4], Cns_MAX_BYTES_LONG_TEXT); /***** Get number of times this comment has been favourited *****/ TL_Fav_GetNumTimesACommHasBeenFav (Com); /***** Get media content (row[5]) *****/ Com->Content.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Med_GetMediaDataByCod (&Com->Content.Media); } /*****************************************************************************/ /************************** Reset fields of comment **************************/ /*****************************************************************************/ static void TL_Com_ResetComment (struct TL_Com_Comment *Com) { Com->PubCod = -1L; Com->UsrCod = -1L; Com->NotCod = -1L; Com->DateTimeUTC = (time_t) 0; Com->Content.Txt[0] = '\0'; }