From 636665abda198e2fca3869e4da2b2e1af19a65c1 Mon Sep 17 00:00:00 2001 From: acanas Date: Thu, 11 Feb 2021 13:10:08 +0100 Subject: [PATCH] Version20.25 --- Makefile | 3 +- swad_changelog.h | 3 +- swad_notification.c | 5 +- swad_profile.c | 3 +- swad_session.c | 4 +- swad_timeline.c | 1014 +---------------------------------- swad_timeline.h | 44 +- swad_timeline_comment.c | 25 +- swad_timeline_favourite.c | 11 +- swad_timeline_note.c | 33 +- swad_timeline_note.h | 5 +- swad_timeline_publication.c | 988 ++++++++++++++++++++++++++++++++++ swad_timeline_publication.h | 98 ++++ swad_timeline_share.c | 8 +- 14 files changed, 1177 insertions(+), 1067 deletions(-) create mode 100644 swad_timeline_publication.c create mode 100644 swad_timeline_publication.h diff --git a/Makefile b/Makefile index 8f1e7756..3bc7a30c 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,8 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \ swad_tab.o swad_tag.o swad_test.o swad_test_config.o \ swad_test_import.o swad_test_print.o swad_test_visibility.o \ swad_theme.o swad_timeline.o swad_timeline_comment.o \ - swad_timeline_favourite.o swad_timeline_note.o swad_timeline_share.o \ + swad_timeline_favourite.o swad_timeline_note.o \ + swad_timeline_publication.o swad_timeline_share.o \ swad_timetable.o \ swad_user.o \ swad_xml.o \ diff --git a/swad_changelog.h b/swad_changelog.h index 97803ab9..aff1e795 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -553,7 +553,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 20.24 (2021-02-11)" +#define Log_PLATFORM_VERSION "SWAD 20.25 (2021-02-11)" #define CSS_FILE "swad20.8.css" #define JS_FILE "swad20.6.2.js" /* @@ -601,6 +601,7 @@ TODO: DNI de un estudiante sale err TODO: BUG: Cuando un tipo de grupo sólo tiene un grupo, inscribirse es voluntario, el estudiante sólo puede pertenecer a un grupo, y se inscribe en él, debería poder desapuntarse. Ahora no puede. TODO: Salvador Romero Cortés: @acanas opción para editar posts + Version 20.25: Feb 11, 2021 New module swad_timeline_publication. (305440 lines) Version 20.24: Feb 11, 2021 Code refactoring in timeline. New linked list to hold publications. (305354 lines) Version 20.23: Feb 11, 2021 New modules swad_timeline_comment and swad_timeline_note. (305319 lines) Version 20.22: Feb 10, 2021 Code refactoring in timeline. (305137 lines) diff --git a/swad_notification.c b/swad_notification.c index fb616564..626bbb39 100644 --- a/swad_notification.c +++ b/swad_notification.c @@ -51,6 +51,7 @@ #include "swad_parameter.h" #include "swad_survey.h" #include "swad_timeline.h" +#include "swad_timeline_publication.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ @@ -725,7 +726,7 @@ static bool Ntf_StartFormGoToAction (Ntf_NotifyEvent_t NotifyEvent, case Ntf_EVENT_TIMELINE_MENTION: // Cod is the code of the social publishing Frm_StartForm (ActSeeTmlGbl); - TL_PutHiddenParamPubCod (Cod); + TL_Pub_PutHiddenParamPubCod (Cod); Usr_PutParamUsrCodEncrypted (UsrDat->EncryptedUsrCod); Ntf_PutHiddenParamNotifyEvent (NotifyEvent); break; @@ -877,7 +878,7 @@ void Ntf_GetNotifSummaryAndContent (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], case Ntf_EVENT_TIMELINE_SHARE: case Ntf_EVENT_TIMELINE_MENTION: // Cod is the code of the social publishing - TL_GetNotifPublication (SummaryStr,ContentStr,Cod,GetContent); + TL_Pub_GetNotifPublication (SummaryStr,ContentStr,Cod,GetContent); break; case Ntf_EVENT_FOLLOWER: Fol_GetNotifFollower (SummaryStr,ContentStr); diff --git a/swad_profile.c b/swad_profile.c index 877813f5..c727ff59 100644 --- a/swad_profile.c +++ b/swad_profile.c @@ -53,6 +53,7 @@ #include "swad_setting.h" #include "swad_theme.h" #include "swad_timeline.h" +#include "swad_timeline_publication.h" #include "swad_user.h" /*****************************************************************************/ @@ -1129,7 +1130,7 @@ static void Prf_GetNumSocialPubsAndStoreAsUsrFigure (long UsrCod) Prf_ResetUsrFigures (&UsrFigures); /***** Get number of forum posts from database *****/ - UsrFigures.NumSocPub = TL_GetNumPubsUsr (UsrCod); + UsrFigures.NumSocPub = TL_Pub_GetNumPubsUsr (UsrCod); /***** Update number of forum posts in user's figures *****/ if (Prf_CheckIfUsrFiguresExists (UsrCod)) diff --git a/swad_session.c b/swad_session.c index 59870691..20013210 100644 --- a/swad_session.c +++ b/swad_session.c @@ -35,7 +35,7 @@ #include "swad_database.h" #include "swad_global.h" #include "swad_parameter.h" -#include "swad_timeline.h" +#include "swad_timeline_note.h" /*****************************************************************************/ /***************************** Private constants *****************************/ @@ -229,7 +229,7 @@ static void Ses_RemoveSessionFromDB (void) /***** Clear old unused social timelines in database *****/ // This is necessary to prevent the table growing and growing - TL_ClearOldTimelinesDB (); + TL_Not_ClearOldTimelinesNotesFromDB (); } /*****************************************************************************/ diff --git a/swad_timeline.c b/swad_timeline.c index fd4e8498..28083990 100644 --- a/swad_timeline.c +++ b/swad_timeline.c @@ -47,6 +47,7 @@ #include "swad_timeline.h" #include "swad_timeline_favourite.h" #include "swad_timeline_note.h" +#include "swad_timeline_publication.h" #include "swad_timeline_share.h" /*****************************************************************************/ @@ -57,15 +58,8 @@ /************************* Private constants and types ***********************/ /*****************************************************************************/ -// Number of recent publishings got and shown the first time, before refreshing -#define TL_MAX_REC_PUBS_TO_GET_AND_SHOW 10 // Recent publishings to show (first time) -#define TL_MAX_NEW_PUBS_TO_GET_AND_SHOW 10000 // New publishings retrieved (big number) -#define TL_MAX_OLD_PUBS_TO_GET_AND_SHOW 20 // Old publishings are retrieved in packs of this size - #define TL_MAX_CHARS_IN_POST 1000 // Maximum number of characters in a post -#define TL_MAX_BYTES_SUBQUERY (128 - 1) - /* mysql> SHOW TABLES LIKE 'tl_%'; +-----------------------+ @@ -164,21 +158,6 @@ mysql> SHOW TABLES LIKE 'tl_%'; */ -struct TL_SubQueries - { - char *TablePublishers; - char Publishers[TL_MAX_BYTES_SUBQUERY + 1]; - char RangeBottom[TL_MAX_BYTES_SUBQUERY + 1]; - char RangeTop[TL_MAX_BYTES_SUBQUERY + 1]; - char AlreadyExists[TL_MAX_BYTES_SUBQUERY + 1]; - }; - -struct TL_RangePubsToGet - { - long Top; - long Bottom; - }; - /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ @@ -199,24 +178,6 @@ Usr_Who_t TL_GlobalWho; static void TL_GetAndShowOldTimeline (struct TL_Timeline *Timeline); -static void TL_GetListPubsToShowInTimeline (struct TL_Timeline *Timeline); -static unsigned TL_GetMaxPubsToGet (const struct TL_Timeline *Timeline); -static long TL_GetPubCodFromSession (const char *FieldName); -static void TL_UpdateFirstLastPubCodesIntoSession (const struct TL_Timeline *Timeline); -static void TL_CreateTmpTableCurrentTimeline (const struct TL_Timeline *Timeline); -static void TL_CreateTmpTablePublishers (void); -static void TL_DropTmpTablesUsedToQueryTimeline (void); -static void TL_CreateSubQueryPublishers (const struct TL_Timeline *Timeline, - struct TL_SubQueries *SubQueries); -static void TL_CreateSubQueryAlreadyExists (const struct TL_Timeline *Timeline, - struct TL_SubQueries *SubQueries); -static void TL_CreateSubQueryRangeBottom (const struct TL_RangePubsToGet *RangePubsToGet, - struct TL_SubQueries *SubQueries); -static void TL_CreateSubQueryRangeTop (const struct TL_RangePubsToGet *RangePubsToGet, - struct TL_SubQueries *SubQueries); -static void TL_FreeListPubs (struct TL_Timeline *Timeline); -static struct TL_Publication *TL_SelectTheMostRecentPub (const struct TL_SubQueries *SubQueries); - static void TL_ShowTimeline (struct TL_Timeline *Timeline, const char *Title,long NotCodToHighlight); static void TL_PutIconsTimeline (__attribute__((unused)) void *Args); @@ -229,26 +190,10 @@ static void TL_SaveWhoInDB (struct TL_Timeline *Timeline); static void TL_ShowWarningYouDontFollowAnyUser (void); -static void TL_InsertNewPubsInTimeline (struct TL_Timeline *Timeline); -static void TL_ShowOldPubsInTimeline (struct TL_Timeline *Timeline); - -static void TL_PutLinkToViewNewPublications (void); -static void TL_PutLinkToViewOldPublications (void); - static void TL_PutFormToWriteNewPost (struct TL_Timeline *Timeline); static long TL_ReceivePost (void); -static long TL_Pub_GetNotCodFromPubCod (long PubCod); - -static void TL_GetDataOfPublicationFromNextRow (MYSQL_RES *mysql_res, - struct TL_Publication *Pub); -static TL_PubType_t TL_GetPubTypeFromStr (const char *Str); - -// static void TL_Pub_ResetPublication (struct TL_Publication *Pub); - -static void TL_ClearTimelineThisSession (void); - /*****************************************************************************/ /************************ Initialize global timeline *************************/ /*****************************************************************************/ @@ -313,7 +258,7 @@ void TL_ShowNoteAndTimelineGbl (struct TL_Timeline *Timeline) /***** Get parameter with the code of a publication *****/ // This parameter is optional. It can be provided by a notification. // If > 0 ==> the note is shown highlighted above the timeline - PubCod = TL_GetParamPubCod (); + PubCod = TL_Pub_GetParamPubCod (); /***** If a note should be highlighted ==> get code of note from database *****/ if (PubCod > 0) @@ -340,13 +285,13 @@ void TL_ShowTimelineGblHighlightingNot (struct TL_Timeline *Timeline, /***** Get list of pubications to show in timeline *****/ Timeline->UsrOrGbl = TL_TIMELINE_GBL; Timeline->WhatToGet = TL_GET_RECENT_TIMELINE; - TL_GetListPubsToShowInTimeline (Timeline); + TL_Pub_GetListPubsToShowInTimeline (Timeline); /***** Show timeline *****/ TL_ShowTimeline (Timeline,Txt_Timeline,NotCod); /***** Free chained list of publications *****/ - TL_FreeListPubs (Timeline); + TL_Pub_FreeListPubs (Timeline); } /*****************************************************************************/ @@ -370,7 +315,7 @@ void TL_ShowTimelineUsrHighlightingNot (struct TL_Timeline *Timeline, /***** Get list of pubications to show in timeline *****/ Timeline->UsrOrGbl = TL_TIMELINE_USR; Timeline->WhatToGet = TL_GET_RECENT_TIMELINE; - TL_GetListPubsToShowInTimeline (Timeline); + TL_Pub_GetListPubsToShowInTimeline (Timeline); /***** Show timeline *****/ TL_ShowTimeline (Timeline, @@ -380,7 +325,7 @@ void TL_ShowTimelineUsrHighlightingNot (struct TL_Timeline *Timeline, Str_FreeString (); /***** Free chained list of publications *****/ - TL_FreeListPubs (Timeline); + TL_Pub_FreeListPubs (Timeline); } /*****************************************************************************/ @@ -402,13 +347,13 @@ void TL_RefreshNewTimelineGbl (void) /***** Get list of pubications to show in timeline *****/ Timeline.UsrOrGbl = TL_TIMELINE_GBL; Timeline.WhatToGet = TL_GET_ONLY_NEW_PUBS; - TL_GetListPubsToShowInTimeline (&Timeline); + TL_Pub_GetListPubsToShowInTimeline (&Timeline); /***** Show new timeline *****/ - TL_InsertNewPubsInTimeline (&Timeline); + TL_Pub_InsertNewPubsInTimeline (&Timeline); /***** Free chained list of publications *****/ - TL_FreeListPubs (&Timeline); + TL_Pub_FreeListPubs (&Timeline); } } @@ -456,13 +401,13 @@ void TL_RefreshOldTimelineUsr (void) static void TL_GetAndShowOldTimeline (struct TL_Timeline *Timeline) { /***** Get list of pubications to show in timeline *****/ - TL_GetListPubsToShowInTimeline (Timeline); + TL_Pub_GetListPubsToShowInTimeline (Timeline); /***** Show old timeline *****/ - TL_ShowOldPubsInTimeline (Timeline); + TL_Pub_ShowOldPubsInTimeline (Timeline); /***** Free chained list of publications *****/ - TL_FreeListPubs (Timeline); + TL_Pub_FreeListPubs (Timeline); } /*****************************************************************************/ @@ -478,467 +423,6 @@ void TL_MarkMyNotifAsSeen (void) Ntf_MarkNotifAsSeen (Ntf_EVENT_TIMELINE_MENTION,-1L,-1L,Gbl.Usrs.Me.UsrDat.UsrCod); } -/*****************************************************************************/ -/*************** Get list of pubications to show in timeline *****************/ -/*****************************************************************************/ - -static void TL_GetListPubsToShowInTimeline (struct TL_Timeline *Timeline) - { - struct TL_SubQueries SubQueries; - struct TL_RangePubsToGet RangePubsToGet; - unsigned MaxPubsToGet = TL_GetMaxPubsToGet (Timeline); - unsigned NumPub; - struct TL_Publication *Pub; - - /***** Clear timeline for this session in database *****/ - if (Timeline->WhatToGet == TL_GET_RECENT_TIMELINE) - TL_ClearTimelineThisSession (); - - /***** Create temporary table with notes in current timeline *****/ - TL_CreateTmpTableCurrentTimeline (Timeline); - - /***** Create temporary table and subquery with potential publishers *****/ - TL_CreateSubQueryPublishers (Timeline,&SubQueries); - - /***** Create subquery to get only notes not present in timeline *****/ - TL_CreateSubQueryAlreadyExists (Timeline,&SubQueries); - - /***** Get the publications in timeline *****/ - /* Initialize range of pubs: - - tl_pubs - _____ - |_____|11 - |_____|10 - _|_____| 9 <-- RangePubsToGet.Top - Get / |_____| 8 - pubs | |_____| 7 - from < |_____| 6 - this | |_____| 5 - range \_|_____| 4 - |_____| 3 <-- RangePubsToGet.Bottom - |_____| 2 - |_____| 1 - 0 - */ - switch (Timeline->WhatToGet) - { - case TL_GET_ONLY_NEW_PUBS: // Get the publications (without limit) newer than LastPubCod - /* This query is made via AJAX automatically from time to time */ - RangePubsToGet.Top = 0; // +Infinite - RangePubsToGet.Bottom = TL_GetPubCodFromSession ("LastPubCod"); - break; - case TL_GET_ONLY_OLD_PUBS: // Get some limited publications older than FirstPubCod - /* This query is made via AJAX - when I click in link to get old publications */ - RangePubsToGet.Top = TL_GetPubCodFromSession ("FirstPubCod"); - RangePubsToGet.Bottom = 0; // -Infinite - break; - case TL_GET_RECENT_TIMELINE: // Get some limited recent publications - default: - /* This is the first query to get initial timeline shown - ==> no notes yet in current timeline table */ - RangePubsToGet.Top = 0; // +Infinite - RangePubsToGet.Bottom = 0; // -Infinite - break; - } - /* Create subquery with bottom range of publications to get from tl_pubs. - Bottom publication code remains unchanged in all iterations of the next loop. */ - TL_CreateSubQueryRangeBottom (&RangePubsToGet,&SubQueries); - - /* - With the current approach, we select one by one - the publications and notes in a loop. In each iteration, - we get the more recent publication (original, shared or commment) - of every set of publications corresponding to the same note, - checking that the note is not already retrieved. - After getting a publication, its note code is stored - in order to not get it again. - - As an alternative, we tried to get the maximum PubCod, - i.e more recent publication (original, shared or commment), - of every set of publications corresponding to the same note: - "SELECT MAX(PubCod) AS NewestPubCod FROM tl_pubs ... - " GROUP BY NotCod ORDER BY NewestPubCod DESC LIMIT ..." - but this query is slow (several seconds) with a big table. - */ - - /* - Chained list of publications: - - Timeline->Pubs.Top Pub #0 - ______ ______ Pub #1 - |______|------>|______| ______ Pub #2 - |______| -> |______| ______ Pub #3 - |______| / |______| ->|______| ______ - |______| / |______| / |______| ->|______| - |_Next_|-- |______| / |______| // |______| - |_Next_|-- |______| // |______| - ______ |_Next_|--/ |______| - |______|---------------------------------------------- |_NULL_| - - Timeline->Pubs.Bottom - - */ - Timeline->Pubs.Top = - Timeline->Pubs.Bottom = NULL; - - for (NumPub = 0; - NumPub < MaxPubsToGet; - NumPub++) - { - /* Create subquery with top range of publications to get from tl_pubs - In each iteration of this loop, top publication code is changed to a lower value */ - TL_CreateSubQueryRangeTop (&RangePubsToGet,&SubQueries); - - /* Select the most recent publication from tl_pubs */ - Pub = TL_SelectTheMostRecentPub (&SubQueries); - - /* Chain the previous publication with the current one */ - if (NumPub == 0) - Timeline->Pubs.Top = Pub; // Pointer to top publication - else - Timeline->Pubs.Bottom->Next = Pub; // Chain the previous publication with the current one - Timeline->Pubs.Bottom = Pub; // Update pointer to bottom publication - - if (Pub == NULL) // Nothing got ==> abort loop - break; // Last publication - - /* Insert note in temporary tables with just retrieved notes. - These tables will be used to not get notes already shown */ - TL_Not_InsertNoteInJustRetrievedNotes (Pub->NotCod); - if (Timeline->WhatToGet == TL_GET_ONLY_OLD_PUBS) - TL_Not_InsertNoteInVisibleTimeline (Pub->NotCod); - - /* Narrow the range for the next iteration */ - RangePubsToGet.Top = Pub->PubCod; - } - - /***** Update first (oldest) and last (more recent) publication codes - into session for next refresh *****/ - TL_UpdateFirstLastPubCodesIntoSession (Timeline); - - /***** Add notes just retrieved to current timeline for this session *****/ - TL_Not_AddNotesJustRetrievedToTimelineThisSession (); - - /***** Drop temporary tables *****/ - TL_DropTmpTablesUsedToQueryTimeline (); - } - -/*****************************************************************************/ -/********* Get maximum number of publications to get from database ***********/ -/*****************************************************************************/ - -static unsigned TL_GetMaxPubsToGet (const struct TL_Timeline *Timeline) - { - static const unsigned MaxPubsToGet[TL_NUM_WHAT_TO_GET] = - { - [TL_GET_RECENT_TIMELINE] = TL_MAX_REC_PUBS_TO_GET_AND_SHOW, - [TL_GET_ONLY_NEW_PUBS ] = TL_MAX_NEW_PUBS_TO_GET_AND_SHOW, - [TL_GET_ONLY_OLD_PUBS ] = TL_MAX_OLD_PUBS_TO_GET_AND_SHOW, - }; - - return MaxPubsToGet[Timeline->WhatToGet]; - } - -/*****************************************************************************/ -/************* Get last/first publication code stored in session *************/ -/*****************************************************************************/ -// FieldName can be: -// "LastPubCod" -// "FirstPubCod" - -static long TL_GetPubCodFromSession (const char *FieldName) - { - extern const char *Txt_The_session_has_expired; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - long PubCod; - - /***** Get last publication code from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get publication code from session", - "SELECT %s FROM sessions" - " WHERE SessionId='%s'", - FieldName,Gbl.Session.Id) != 1) - Lay_ShowErrorAndExit (Txt_The_session_has_expired); - - /***** Get last publication code *****/ - row = mysql_fetch_row (mysql_res); - if (sscanf (row[0],"%ld",&PubCod) != 1) - PubCod = 0; - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return PubCod; - } - -/*****************************************************************************/ -/************* Update first (oldest) and last (more recent) ***************/ -/************* publication codes into session for next refresh ***************/ -/*****************************************************************************/ - -static void TL_UpdateFirstLastPubCodesIntoSession (const struct TL_Timeline *Timeline) - { - long FirstPubCod; - - switch (Timeline->WhatToGet) - { - case TL_GET_ONLY_NEW_PUBS: - DB_QueryUPDATE ("can not update first/last publication codes into session", - "UPDATE sessions" - " SET LastPubCod=" - "(SELECT IFNULL(MAX(PubCod),0)" - " FROM tl_pubs)" // The most recent publication - " WHERE SessionId='%s'", - Gbl.Session.Id); - break; - case TL_GET_ONLY_OLD_PUBS: - // The oldest publication code retrieved and shown - FirstPubCod = Timeline->Pubs.Bottom ? Timeline->Pubs.Bottom->PubCod : - 0; - - DB_QueryUPDATE ("can not update first/last publication codes into session", - "UPDATE sessions" - " SET FirstPubCod=%ld" - " WHERE SessionId='%s'", - FirstPubCod, - Gbl.Session.Id); - break; - case TL_GET_RECENT_TIMELINE: - // The oldest publication code retrieved and shown - FirstPubCod = Timeline->Pubs.Bottom ? Timeline->Pubs.Bottom->PubCod : - 0; - - DB_QueryUPDATE ("can not update first/last publication codes into session", - "UPDATE sessions" - " SET FirstPubCod=%ld," - "LastPubCod=" - "(SELECT IFNULL(MAX(PubCod),0)" - " FROM tl_pubs)" // The most recent publication - " WHERE SessionId='%s'", - FirstPubCod, - Gbl.Session.Id); - break; - } - } - -/*****************************************************************************/ -/************* Create temporary tables used to query timeline ****************/ -/*****************************************************************************/ - -static void TL_CreateTmpTableCurrentTimeline (const struct TL_Timeline *Timeline) - { - /***** Create temporary table with notes just retrieved *****/ - DB_Query ("can not create temporary table", - "CREATE TEMPORARY TABLE tl_tmp_just_retrieved_notes " - "(NotCod BIGINT NOT NULL,UNIQUE INDEX(NotCod))" - " ENGINE=MEMORY"); - - if (Timeline->WhatToGet == TL_GET_ONLY_OLD_PUBS) - /***** Create temporary table with all notes visible in timeline *****/ - DB_Query ("can not create temporary table", - "CREATE TEMPORARY TABLE tl_tmp_visible_timeline " - "(NotCod BIGINT NOT NULL,UNIQUE INDEX(NotCod))" - " ENGINE=MEMORY" - " SELECT NotCod FROM tl_timelines WHERE SessionId='%s'", - Gbl.Session.Id); - } - -static void TL_CreateTmpTablePublishers (void) - { - /***** Create temporary table with me and the users I follow *****/ - DB_Query ("can not create temporary table", - "CREATE TEMPORARY TABLE tl_tmp_publishers " - "(UsrCod INT NOT NULL," - "UNIQUE INDEX(UsrCod))" - " ENGINE=MEMORY" - " SELECT %ld AS UsrCod" // Me - " UNION" - " SELECT FollowedCod AS UsrCod" // Users I follow - " FROM usr_follow" - " WHERE FollowerCod=%ld", - Gbl.Usrs.Me.UsrDat.UsrCod, - Gbl.Usrs.Me.UsrDat.UsrCod); - } - -/*****************************************************************************/ -/*************** Drop temporary tables used to query timeline ****************/ -/*****************************************************************************/ - -static void TL_DropTmpTablesUsedToQueryTimeline (void) - { - DB_Query ("can not remove temporary tables", - "DROP TEMPORARY TABLE IF EXISTS " - "tl_tmp_just_retrieved_notes," - "tl_tmp_visible_timeline," - "tl_tmp_publishers"); - } - -/*****************************************************************************/ -/******* Create temporary table and subquery with potential publishers *******/ -/*****************************************************************************/ - -static void TL_CreateSubQueryPublishers (const struct TL_Timeline *Timeline, - struct TL_SubQueries *SubQueries) - { - /***** Create temporary table and subquery with potential publishers *****/ - switch (Timeline->UsrOrGbl) - { - case TL_TIMELINE_USR: // Show the timeline of a user - SubQueries->TablePublishers = ""; - sprintf (SubQueries->Publishers,"tl_pubs.PublisherCod=%ld AND ", - Gbl.Usrs.Other.UsrDat.UsrCod); - break; - case TL_TIMELINE_GBL: // Show the global timeline - switch (Timeline->Who) - { - case Usr_WHO_ME: // Show my timeline - SubQueries->TablePublishers = ""; - snprintf (SubQueries->Publishers,sizeof (SubQueries->Publishers), - "tl_pubs.PublisherCod=%ld AND ", - Gbl.Usrs.Me.UsrDat.UsrCod); - break; - case Usr_WHO_FOLLOWED: // Show the timeline of the users I follow - TL_CreateTmpTablePublishers (); - SubQueries->TablePublishers = ",tl_tmp_publishers"; - Str_Copy (SubQueries->Publishers, - "tl_pubs.PublisherCod=tl_tmp_publishers.UsrCod AND ", - TL_MAX_BYTES_SUBQUERY); - break; - case Usr_WHO_ALL: // Show the timeline of all users - SubQueries->TablePublishers = ""; - SubQueries->Publishers[0] = '\0'; - break; - default: - Lay_WrongWhoExit (); - break; - } - break; - } - } - -/*****************************************************************************/ -/********* Create subquery to get only notes not present in timeline *********/ -/*****************************************************************************/ - -static void TL_CreateSubQueryAlreadyExists (const struct TL_Timeline *Timeline, - struct TL_SubQueries *SubQueries) - { - switch (Timeline->WhatToGet) - { - case TL_GET_RECENT_TIMELINE: - case TL_GET_ONLY_NEW_PUBS: - Str_Copy (SubQueries->AlreadyExists, - " tl_pubs.NotCod NOT IN" - " (SELECT NotCod FROM tl_tmp_just_retrieved_notes)", // Avoid notes just retrieved - TL_MAX_BYTES_SUBQUERY); - break; - case TL_GET_ONLY_OLD_PUBS: - Str_Copy (SubQueries->AlreadyExists, - " tl_pubs.NotCod NOT IN" - " (SELECT NotCod FROM tl_tmp_visible_timeline)", // Avoid notes already shown - TL_MAX_BYTES_SUBQUERY); - break; - } - } - -/*****************************************************************************/ -/***** Create subqueries with range of publications to get from tl_pubs ******/ -/*****************************************************************************/ - -static void TL_CreateSubQueryRangeBottom (const struct TL_RangePubsToGet *RangePubsToGet, - struct TL_SubQueries *SubQueries) - { - if (RangePubsToGet->Bottom > 0) - sprintf (SubQueries->RangeBottom,"tl_pubs.PubCod>%ld AND ", - RangePubsToGet->Bottom); - else - SubQueries->RangeBottom[0] = '\0'; - } - -static void TL_CreateSubQueryRangeTop (const struct TL_RangePubsToGet *RangePubsToGet, - struct TL_SubQueries *SubQueries) - { - if (RangePubsToGet->Top > 0) - sprintf (SubQueries->RangeTop,"tl_pubs.PubCod<%ld AND ", - RangePubsToGet->Top); - else - SubQueries->RangeTop[0] = '\0'; - } - -/*****************************************************************************/ -/************** Free chained list of publications in timeline ****************/ -/*****************************************************************************/ - -static void TL_FreeListPubs (struct TL_Timeline *Timeline) - { - struct TL_Publication *Pub; - struct TL_Publication *Next; - - /***** Go over the list freeing memory *****/ - for (Pub = Timeline->Pubs.Top; - Pub; - Pub = Next) - { - /* Save a copy of pointer to next element before freeing it */ - Next = Pub->Next; - - /* Free memory used for this publication */ - free (Pub); - } - - /***** Reset pointers to top and bottom elements *****/ - Timeline->Pubs.Top = - Timeline->Pubs.Bottom = NULL; - } - -/*****************************************************************************/ -/************** Select the most recent publication from tl_pubs **************/ -/*****************************************************************************/ - -static struct TL_Publication *TL_SelectTheMostRecentPub (const struct TL_SubQueries *SubQueries) - { - MYSQL_RES *mysql_res; - unsigned NumPubs = 0; // Initialized to avoid warning - struct TL_Publication *Pub; - - NumPubs = - (unsigned) DB_QuerySELECT (&mysql_res,"can not get publication", - "SELECT tl_pubs.PubCod," // row[0] - "tl_pubs.NotCod," // row[1] - "tl_pubs.PublisherCod," // row[2] - "tl_pubs.PubType" // row[3] - " FROM tl_pubs%s" - " WHERE %s%s%s%s" - " ORDER BY tl_pubs.PubCod DESC LIMIT 1", - SubQueries->TablePublishers, - SubQueries->RangeBottom, - SubQueries->RangeTop, - SubQueries->Publishers, - SubQueries->AlreadyExists); - - if (NumPubs == 1) - { - /* Allocate space for publication */ - if ((Pub = (struct TL_Publication *) malloc (sizeof (struct TL_Publication))) == NULL) - Lay_ShowErrorAndExit ("Error allocating memory publication."); - - /* Get data of publication */ - TL_GetDataOfPublicationFromNextRow (mysql_res,Pub); - Pub->Next = NULL; - } - else - Pub = NULL; - /* Reset data of publication */ - // TL_Pub_ResetPublication (Pub); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return Pub; - } - /*****************************************************************************/ /******************************* Show timeline *******************************/ /*****************************************************************************/ @@ -975,7 +459,7 @@ static void TL_ShowTimeline (struct TL_Timeline *Timeline, const char *Title,long NotCodToHighlight) { extern const char *Hlp_START_Timeline; - struct TL_Publication *Pub; + struct TL_Pub_Publication *Pub; struct TL_Not_Note Not; unsigned NumPubs; bool GlobalTimeline = (Gbl.Usrs.Other.UsrDat.UsrCod <= 0); @@ -998,7 +482,7 @@ static void TL_ShowTimeline (struct TL_Timeline *Timeline, if (GlobalTimeline) { /* Link to view new publications via AJAX */ - TL_PutLinkToViewNewPublications (); + TL_Pub_PutLinkToViewNewPublications (); /* Hidden list where insert just received (not visible) publications via AJAX */ HTM_UL_Begin ("id=\"just_now_timeline_list\" class=\"TL_LIST\""); @@ -1031,10 +515,10 @@ static void TL_ShowTimeline (struct TL_Timeline *Timeline, /***** If the number of publications shown is the maximum, probably there will be more, so show link to get more *****/ - if (NumPubs == TL_MAX_REC_PUBS_TO_GET_AND_SHOW) + if (NumPubs == TL_Pub_MAX_REC_PUBS_TO_GET_AND_SHOW) { /* Link to view old publications via AJAX */ - TL_PutLinkToViewOldPublications (); + TL_Pub_PutLinkToViewOldPublications (); /* Hidden list where insert old publications via AJAX */ HTM_UL_Begin ("id=\"old_timeline_list\" class=\"TL_LIST\""); @@ -1224,117 +708,6 @@ static void TL_ShowWarningYouDontFollowAnyUser (void) } } -/*****************************************************************************/ -/******************* Show new publications in timeline ***********************/ -/*****************************************************************************/ -// The publications are inserted as list elements of a hidden list - -static void TL_InsertNewPubsInTimeline (struct TL_Timeline *Timeline) - { - struct TL_Publication *Pub; - struct TL_Not_Note Not; - - /***** List new publications timeline *****/ - for (Pub = Timeline->Pubs.Top; - Pub; - Pub = Pub->Next) - { - /* Get data of note */ - Not.NotCod = Pub->NotCod; - TL_Not_GetDataOfNoteByCod (&Not); - - /* Write note */ - TL_Not_WriteNote (Timeline,&Not, - Pub->TopMessage, - Pub->PublisherCod, - TL_DONT_HIGHLIGHT, - TL_DONT_SHOW_ALONE); - } - } - -/*****************************************************************************/ -/********************* Show old publications in timeline *********************/ -/*****************************************************************************/ -// The publications are inserted as list elements of a hidden list - -static void TL_ShowOldPubsInTimeline (struct TL_Timeline *Timeline) - { - struct TL_Publication *Pub; - struct TL_Not_Note Not; - - /***** List old publications in timeline *****/ - for (Pub = Timeline->Pubs.Top; - Pub; - Pub = Pub->Next) - { - /* Get data of note */ - Not.NotCod = Pub->NotCod; - TL_Not_GetDataOfNoteByCod (&Not); - - /* Write note */ - TL_Not_WriteNote (Timeline,&Not, - Pub->TopMessage, - Pub->PublisherCod, - TL_DONT_HIGHLIGHT, - TL_DONT_SHOW_ALONE); - } - } - -/*****************************************************************************/ -/***************** Put link to view new publications in timeline *************/ -/*****************************************************************************/ - -static void TL_PutLinkToViewNewPublications (void) - { - extern const char *The_ClassFormInBoxBold[The_NUM_THEMES]; - extern const char *Txt_See_new_activity; - - /***** Link to view (show hidden) new publications *****/ - // div is hidden. When new posts arrive to the client via AJAX, div is shown - HTM_DIV_Begin ("id=\"view_new_posts_container\"" - " class=\"TL_WIDTH TL_SEP VERY_LIGHT_BLUE\"" - " style=\"display:none;\""); - HTM_A_Begin ("href=\"\" class=\"%s\"" - " onclick=\"moveNewTimelineToTimeline();return false;\"", - The_ClassFormInBoxBold[Gbl.Prefs.Theme]); - HTM_TxtF ("%s (",Txt_See_new_activity); - HTM_SPAN_Begin ("id=\"view_new_posts_count\""); - HTM_Unsigned (0); - HTM_SPAN_End (); - HTM_Txt (")"); - HTM_A_End (); - HTM_DIV_End (); - } - -/*****************************************************************************/ -/***************** Put link to view old publications in timeline *************/ -/*****************************************************************************/ - -static void TL_PutLinkToViewOldPublications (void) - { - extern const char *The_ClassFormInBoxBold[The_NUM_THEMES]; - extern const char *Txt_See_more; - - /***** Animated link to view old publications *****/ - HTM_DIV_Begin ("id=\"view_old_posts_container\"" - " class=\"TL_WIDTH TL_SEP VERY_LIGHT_BLUE\""); - HTM_A_Begin ("href=\"\" class=\"%s\" onclick=\"" - "document.getElementById('get_old_timeline').style.display='none';" // Icon to be hidden on click - "document.getElementById('getting_old_timeline').style.display='';" // Icon to be shown on click - "refreshOldTimeline();" - "return false;\"", - The_ClassFormInBoxBold[Gbl.Prefs.Theme]); - HTM_IMG (Cfg_URL_ICON_PUBLIC,"recycle16x16.gif","Txt_See_more", - "class=\"ICO20x20\" id=\"get_old_timeline\""); - HTM_IMG (Cfg_URL_ICON_PUBLIC,"working16x16.gif",Txt_See_more, - "class=\"ICO20x20\" style=\"display:none;\" id=\"getting_old_timeline\""); // Animated icon hidden - HTM_IMG (Cfg_URL_ICON_PUBLIC,"recycle16x16.gif","Txt_See_more", - "class=\"ICO20x20\" style=\"display:none;\" id=\"get_old_timeline\""); - HTM_TxtF (" %s",Txt_See_more); - HTM_A_End (); - HTM_DIV_End (); - } - /*****************************************************************************/ /*************** Write sharer/commenter if distinct to author ****************/ /*****************************************************************************/ @@ -1461,28 +834,6 @@ void TL_GetAndWritePost (long PstCod) Med_MediaDestructor (&Content.Media); } -/*****************************************************************************/ -/********************* Publish note/comment in timeline **********************/ -/*****************************************************************************/ -// Pub->PubCod is set by the function - -void TL_PublishPubInTimeline (struct TL_Publication *Pub) - { - /***** Publish note in timeline *****/ - Pub->PubCod = - DB_QueryINSERTandReturnCode ("can not publish note/comment", - "INSERT INTO tl_pubs" - " (NotCod,PublisherCod,PubType,TimePublish)" - " VALUES" - " (%ld,%ld,%u,NOW())", - Pub->NotCod, - Pub->PublisherCod, - (unsigned) Pub->PubType); - - /***** Increment number of publications in user's figures *****/ - Prf_IncrementNumPubsUsr (Pub->PublisherCod); - } - /*****************************************************************************/ /********************** Form to write a new publication **********************/ /*****************************************************************************/ @@ -1614,7 +965,7 @@ static long TL_ReceivePost (void) { struct TL_PostContent Content; long PstCod; - struct TL_Publication Pub; + struct TL_Pub_Publication Pub; /***** Get the content of the new post *****/ Par_GetParAndChangeFormat ("Txt",Content.Txt,Cns_MAX_BYTES_LONG_TEXT, @@ -1662,91 +1013,6 @@ static long TL_ReceivePost (void) return Pub.NotCod; } -/*****************************************************************************/ -/*************** Put parameter with the code of a publication ****************/ -/*****************************************************************************/ - -void TL_PutHiddenParamPubCod (long PubCod) - { - Par_PutHiddenParamLong (NULL,"PubCod",PubCod); - } - -/*****************************************************************************/ -/**************** Get parameter with the code of a publication ***************/ -/*****************************************************************************/ - -long TL_GetParamPubCod (void) - { - /***** Get comment code *****/ - return Par_GetParToLong ("PubCod"); - } - -/*****************************************************************************/ -/*********** Create a notification for the author of a post/comment **********/ -/*****************************************************************************/ - -void TL_CreateNotifToAuthor (long AuthorCod,long PubCod, - Ntf_NotifyEvent_t NotifyEvent) - { - struct UsrData UsrDat; - bool CreateNotif; - bool NotifyByEmail; - - /***** Initialize structure with user's data *****/ - Usr_UsrDataConstructor (&UsrDat); - - UsrDat.UsrCod = AuthorCod; - if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS)) - { - /***** This fav must be notified by email? *****/ - CreateNotif = (UsrDat.NtfEvents.CreateNotif & (1 << NotifyEvent)); - NotifyByEmail = CreateNotif && - (UsrDat.NtfEvents.SendEmail & (1 << NotifyEvent)); - - /***** Create notification for the author of the post. - If this author wants to receive notifications by email, - activate the sending of a notification *****/ - if (CreateNotif) - Ntf_StoreNotifyEventToOneUser (NotifyEvent,&UsrDat,PubCod, - (Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL : - 0), - Gbl.Hierarchy.Ins.InsCod, - Gbl.Hierarchy.Ctr.CtrCod, - Gbl.Hierarchy.Deg.DegCod, - Gbl.Hierarchy.Crs.CrsCod); - } - - /***** Free memory used for user's data *****/ - Usr_UsrDataDestructor (&UsrDat); - } - -/*****************************************************************************/ -/*********************** Get code of note of a publication *******************/ -/*****************************************************************************/ - -static long TL_Pub_GetNotCodFromPubCod (long PubCod) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - long NotCod = -1L; - - /***** Get code of note from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get code of note", - "SELECT NotCod FROM tl_pubs" - " WHERE PubCod=%ld", - PubCod) == 1) // Result should have a unique row - { - /* Get code of note */ - row = mysql_fetch_row (mysql_res); - NotCod = Str_ConvertStrCodToLongCod (row[0]); - } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return NotCod; - } - /*****************************************************************************/ /*************** Get code of publication of the original note ****************/ /*****************************************************************************/ @@ -1794,7 +1060,7 @@ void TL_RemoveUsrContent (long UsrCod) " WHERE tl_pubs.PublisherCod=%ld" // Author of the comment " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments_fav.PubCod", - UsrCod,(unsigned) TL_PUB_COMMENT_TO_NOTE); + UsrCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); /* Remove all favs for all comments in all the notes of the user */ DB_QueryDELETE ("can not remove comments", @@ -1804,7 +1070,7 @@ void TL_RemoveUsrContent (long UsrCod) " AND tl_notes.NotCod=tl_pubs.NotCod" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments_fav.PubCod", - UsrCod,(unsigned) TL_PUB_COMMENT_TO_NOTE); + UsrCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); /***** Remove favs for notes *****/ /* Remove all favs made by this user in any note */ @@ -1830,7 +1096,7 @@ void TL_RemoveUsrContent (long UsrCod) " AND tl_notes.NotCod=tl_pubs.NotCod" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments.PubCod", - UsrCod,(unsigned) TL_PUB_COMMENT_TO_NOTE); + UsrCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); /* Remove all the comments from any user in any note of the user */ DB_QueryDELETE ("can not remove comments", @@ -1839,7 +1105,7 @@ void TL_RemoveUsrContent (long UsrCod) " WHERE tl_notes.UsrCod=%ld" " AND tl_notes.NotCod=tl_pubs.NotCod" " AND tl_pubs.PubType=%u", - UsrCod,(unsigned) TL_PUB_COMMENT_TO_NOTE); + UsrCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); /* Remove content of all the comments of the user in any note */ DB_QueryDELETE ("can not remove comments", @@ -1848,7 +1114,7 @@ void TL_RemoveUsrContent (long UsrCod) " WHERE tl_pubs.PublisherCod=%ld" " AND tl_pubs.PubType=%u" " AND tl_pubs.PubCod=tl_comments.PubCod", - UsrCod,(unsigned) TL_PUB_COMMENT_TO_NOTE); + UsrCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); /***** Remove all the posts of the user *****/ DB_QueryDELETE ("can not remove posts", @@ -2023,239 +1289,3 @@ void TL_FormFavSha (Act_Action_t ActionGbl,Act_Action_t ActionUsr, /* Free allocated memory */ free (OnSubmit); } - -/*****************************************************************************/ -/***************** Get data of publication using its code ********************/ -/*****************************************************************************/ - -static void TL_GetDataOfPublicationFromNextRow (MYSQL_RES *mysql_res, - struct TL_Publication *Pub) - { - static const TL_TopMessage_t TopMessages[TL_NUM_PUB_TYPES] = - { - [TL_PUB_UNKNOWN ] = TL_TOP_MESSAGE_NONE, - [TL_PUB_ORIGINAL_NOTE ] = TL_TOP_MESSAGE_NONE, - [TL_PUB_SHARED_NOTE ] = TL_TOP_MESSAGE_SHARED, - [TL_PUB_COMMENT_TO_NOTE] = TL_TOP_MESSAGE_COMMENTED, - }; - MYSQL_ROW row; - - /***** Get next row from result *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0]: PubCod - row[1]: NotCod - row[2]: PublisherCod - row[3]: PubType - */ - - /***** Get code of publication (row[0]) *****/ - Pub->PubCod = Str_ConvertStrCodToLongCod (row[0]); - - /***** Get note code (row[1]) *****/ - Pub->NotCod = Str_ConvertStrCodToLongCod (row[1]); - - /***** Get publisher's code (row[2]) *****/ - Pub->PublisherCod = Str_ConvertStrCodToLongCod (row[2]); - - /***** Get type of publication (row[3]) *****/ - Pub->PubType = TL_GetPubTypeFromStr ((const char *) row[3]); - Pub->TopMessage = TopMessages[Pub->PubType]; - } - -/*****************************************************************************/ -/******* Get publication type from string number coming from database ********/ -/*****************************************************************************/ - -static TL_PubType_t TL_GetPubTypeFromStr (const char *Str) - { - unsigned UnsignedNum; - - if (sscanf (Str,"%u",&UnsignedNum) == 1) - if (UnsignedNum < TL_NUM_PUB_TYPES) - return (TL_PubType_t) UnsignedNum; - - return TL_PUB_UNKNOWN; - } - -/*****************************************************************************/ -/************************ Reset fields of publication ************************/ -/*****************************************************************************/ -/* -static void TL_Pub_ResetPublication (struct TL_Publication *Pub) - { - Pub->PubCod = -1L; - Pub->NotCod = -1L; - Pub->PublisherCod = -1L; - Pub->PubType = TL_PUB_UNKNOWN; - Pub->TopMessage = TL_TOP_MESSAGE_NONE; - } -*/ -/*****************************************************************************/ -/******************* Clear unused old timelines in database ******************/ -/*****************************************************************************/ - -void TL_ClearOldTimelinesDB (void) - { - /***** Remove timelines for expired sessions *****/ - DB_QueryDELETE ("can not remove old timelines", - "DELETE LOW_PRIORITY FROM tl_timelines" - " WHERE SessionId NOT IN (SELECT SessionId FROM sessions)"); - } - -/*****************************************************************************/ -/**************** Clear timeline for this session in database ****************/ -/*****************************************************************************/ - -static void TL_ClearTimelineThisSession (void) - { - /***** Remove timeline for this session *****/ - DB_QueryDELETE ("can not remove timeline", - "DELETE FROM tl_timelines" - " WHERE SessionId='%s'", - Gbl.Session.Id); - } - -/*****************************************************************************/ -/***************** Get notification of a new publication *********************/ -/*****************************************************************************/ - -void TL_GetNotifPublication (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], - char **ContentStr, - long PubCod,bool GetContent) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - struct TL_Publication Pub; - struct TL_Not_Note Not; - struct TL_PostContent Content; - size_t Length; - bool ContentCopied = false; - - /***** Return nothing on error *****/ - Pub.PubType = TL_PUB_UNKNOWN; - SummaryStr[0] = '\0'; // Return nothing on error - Content.Txt[0] = '\0'; - - /***** Get summary and content from post from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get data of publication", - "SELECT PubCod," // row[0] - "NotCod," // row[1] - "PublisherCod," // row[2] - "PubType" // row[3] - " FROM tl_pubs WHERE PubCod=%ld", - PubCod) == 1) // Result should have a unique row - /* Get data of publication from row */ - TL_GetDataOfPublicationFromNextRow (mysql_res,&Pub); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - /***** Get summary and content *****/ - switch (Pub.PubType) - { - case TL_PUB_UNKNOWN: - break; - case TL_PUB_ORIGINAL_NOTE: - case TL_PUB_SHARED_NOTE: - /* Get data of note */ - Not.NotCod = Pub.NotCod; - TL_Not_GetDataOfNoteByCod (&Not); - - if (Not.NoteType == TL_NOTE_POST) - { - /***** Get content of post from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get the content of a post", - "SELECT Txt" // row[0] - " FROM tl_posts" - " WHERE PstCod=%ld", - Not.Cod) == 1) // Result should have a unique row - { - /***** Get row *****/ - row = mysql_fetch_row (mysql_res); - - /****** Get content (row[0]) *****/ - Str_Copy (Content.Txt,row[0], - Cns_MAX_BYTES_LONG_TEXT); - } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - /***** Copy content string *****/ - if (GetContent) - { - Length = strlen (Content.Txt); - if ((*ContentStr = (char *) malloc (Length + 1)) != NULL) - { - Str_Copy (*ContentStr,Content.Txt, - Length); - ContentCopied = true; - } - } - - /***** Copy summary string *****/ - Str_LimitLengthHTMLStr (Content.Txt,Ntf_MAX_CHARS_SUMMARY); - Str_Copy (SummaryStr,Content.Txt, - Ntf_MAX_BYTES_SUMMARY); - } - else - TL_Not_GetNoteSummary (&Not,SummaryStr); - break; - case TL_PUB_COMMENT_TO_NOTE: - /***** Get content of post from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get the content" - " of a comment to a note", - "SELECT Txt" // row[0] - " FROM tl_comments" - " WHERE PubCod=%ld", - Pub.PubCod) == 1) // Result should have a unique row - { - /***** Get row *****/ - row = mysql_fetch_row (mysql_res); - - /****** Get content (row[0]) *****/ - Str_Copy (Content.Txt,row[0], - Cns_MAX_BYTES_LONG_TEXT); - } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - /***** Copy content string *****/ - if (GetContent) - { - Length = strlen (Content.Txt); - if ((*ContentStr = (char *) malloc (Length + 1)) != NULL) - { - Str_Copy (*ContentStr,Content.Txt, - Length); - ContentCopied = true; - } - } - - /***** Copy summary string *****/ - Str_LimitLengthHTMLStr (Content.Txt,Ntf_MAX_CHARS_SUMMARY); - Str_Copy (SummaryStr,Content.Txt, - Ntf_MAX_BYTES_SUMMARY); - break; - } - - /***** Create empty content string if nothing copied *****/ - if (GetContent && !ContentCopied) - if ((*ContentStr = (char *) malloc (1)) != NULL) - (*ContentStr)[0] = '\0'; - } - -/*****************************************************************************/ -/****************** Get number of publications from a user *******************/ -/*****************************************************************************/ - -unsigned long TL_GetNumPubsUsr (long UsrCod) - { - /***** Get number of posts from a user from database *****/ - return DB_QueryCOUNT ("can not get number of publications from a user", - "SELECT COUNT(*) FROM tl_pubs" - " WHERE PublisherCod=%ld", - UsrCod); - } diff --git a/swad_timeline.h b/swad_timeline.h index a54daa32..f8ecf7b3 100644 --- a/swad_timeline.h +++ b/swad_timeline.h @@ -94,8 +94,8 @@ struct TL_Timeline TL_WhatToGet_t WhatToGet; struct { - struct TL_Publication *Top; // Points to first element in list of publications - struct TL_Publication *Bottom; // Points to last element in list of publications + struct TL_Pub_Publication *Top; // Points to first element in list of publications + struct TL_Pub_Publication *Bottom; // Points to last element in list of publications } Pubs; long NotCod; // Used as parameter about social note to be edited, removed... long PubCod; // Used as parameter about social publishing to be edited, removed... @@ -107,27 +107,6 @@ typedef enum TL_SHOW_ALL_USRS, // Show all favers/sharers } TL_HowManyUsrs_t; -#define TL_NUM_PUB_TYPES 4 -// If the numbers assigned to each event type change, -// it is necessary to change old numbers to new ones in database table tl_notes -typedef enum - { - TL_PUB_UNKNOWN = 0, - TL_PUB_ORIGINAL_NOTE = 1, - TL_PUB_SHARED_NOTE = 2, - TL_PUB_COMMENT_TO_NOTE = 3, - } TL_PubType_t; - -struct TL_Publication - { - long PubCod; - long NotCod; - long PublisherCod; // Sharer or writer of the publication - TL_PubType_t PubType; - TL_TopMessage_t TopMessage; // Used to show feedback on the action made - struct TL_Publication *Next; // Used for chained list - }; - struct TL_PostContent { char Txt[Cns_MAX_BYTES_LONG_TEXT + 1]; @@ -183,22 +162,11 @@ void TL_WriteDateTime (time_t TimeUTC); void TL_GetAndWritePost (long PstCod); -void TL_PublishPubInTimeline (struct TL_Publication *Pub); - void TL_PutTextarea (const char *Placeholder,const char *ClassTextArea); void TL_ReceivePostUsr (void); void TL_ReceivePostGbl (void); -void TL_Com_ShowHiddenCommentsUsr (void); -void TL_Com_ShowHiddenCommentsGbl (void); - -void TL_PutHiddenParamPubCod (long PubCod); -long TL_GetParamPubCod (void); - -void TL_CreateNotifToAuthor (long AuthorCod,long PubCod, - Ntf_NotifyEvent_t NotifyEvent); - void TL_RemoveUsrContent (long UsrCod); void TL_ShowNumSharersOrFavers (unsigned NumUsrs); @@ -211,12 +179,4 @@ void TL_FormFavSha (Act_Action_t ActionGbl,Act_Action_t ActionUsr, const char *ParamFormat,long ParamCod, const char *Icon,const char *Title); -void TL_ClearOldTimelinesDB (void); - -void TL_GetNotifPublication (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], - char **ContentStr, - long PubCod,bool GetContent); - -unsigned long TL_GetNumPubsUsr (long UsrCod); - #endif diff --git a/swad_timeline_comment.c b/swad_timeline_comment.c index ad7a7aaf..d52c51c7 100644 --- a/swad_timeline_comment.c +++ b/swad_timeline_comment.c @@ -38,6 +38,7 @@ #include "swad_timeline.h" #include "swad_timeline_favourite.h" #include "swad_timeline_note.h" +#include "swad_timeline_publication.h" #include "swad_timeline_share.h" /*****************************************************************************/ @@ -185,7 +186,7 @@ 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); + NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE); } /*****************************************************************************/ @@ -237,7 +238,7 @@ void TL_Com_WriteCommentsInNote (struct TL_Timeline *Timeline, " ORDER BY tl_pubs.PubCod DESC LIMIT %u" ") AS comments" " ORDER BY PubCod", - Not->NotCod,(unsigned) TL_PUB_COMMENT_TO_NOTE, + Not->NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE, NumFinalCommentsToGet); /* @@ -454,7 +455,7 @@ static unsigned TL_Com_WriteHiddenComments (struct TL_Timeline *Timeline, " AND tl_pubs.PubCod=tl_comments.PubCod" " ORDER BY tl_pubs.PubCod" " LIMIT %lu", - NotCod,(unsigned) TL_PUB_COMMENT_TO_NOTE, + NotCod,(unsigned) TL_Pub_COMMENT_TO_NOTE, NumInitialCommentsToGet); /***** List with comments *****/ @@ -699,7 +700,7 @@ static void TL_Com_PutFormToRemoveComment (const struct TL_Timeline *Timeline, /***** Form to remove publication *****/ TL_FormStart (Timeline,ActReqRemTL_ComGbl,ActReqRemTL_ComUsr); - TL_PutHiddenParamPubCod (PubCod); + TL_Pub_PutHiddenParamPubCod (PubCod); Ico_PutIconLink ("trash.svg",Txt_Remove); Frm_EndForm (); } @@ -754,7 +755,7 @@ 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_Publication Pub; + struct TL_Pub_Publication Pub; /***** Get data of note *****/ Not.NotCod = TL_Not_GetParamNotCod (); @@ -786,8 +787,8 @@ static long TL_Com_ReceiveComment (void) /* Insert into publications */ Pub.NotCod = Not.NotCod; Pub.PublisherCod = Gbl.Usrs.Me.UsrDat.UsrCod; - Pub.PubType = TL_PUB_COMMENT_TO_NOTE; - TL_PublishPubInTimeline (&Pub); // Set Pub.PubCod + 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", @@ -872,7 +873,7 @@ static void TL_Com_RequestRemovalComment (struct TL_Timeline *Timeline) Med_MediaConstructor (&Com.Content.Media); /***** Get data of comment *****/ - Com.PubCod = TL_GetParamPubCod (); + Com.PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (&Com); if (Com.PubCod > 0) @@ -920,7 +921,7 @@ static void TL_Com_PutParamsRemoveComment (void *Timeline) Usr_PutParamOtherUsrCodEncrypted (Gbl.Usrs.Other.UsrDat.EncryptedUsrCod); else Usr_PutHiddenParamWho (((struct TL_Timeline *) Timeline)->Who); - TL_PutHiddenParamPubCod (((struct TL_Timeline *) Timeline)->PubCod); + TL_Pub_PutHiddenParamPubCod (((struct TL_Timeline *) Timeline)->PubCod); } } @@ -979,7 +980,7 @@ static void TL_Com_RemoveComment (void) Med_MediaConstructor (&Com.Content.Media); /***** Get data of comment *****/ - Com.PubCod = TL_GetParamPubCod (); + Com.PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (&Com); if (Com.PubCod > 0) @@ -1058,7 +1059,7 @@ void TL_Com_RemoveCommentMediaAndDBEntries (long PubCod) " AND PubType=%u", // Extra check: it's a comment PubCod, Gbl.Usrs.Me.UsrDat.UsrCod, - (unsigned) TL_PUB_COMMENT_TO_NOTE); + (unsigned) TL_Pub_COMMENT_TO_NOTE); } /*****************************************************************************/ @@ -1084,7 +1085,7 @@ void TL_Com_GetDataOfCommByCod (struct TL_Com_Comment *Com) " 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)) + Com->PubCod,(unsigned) TL_Pub_COMMENT_TO_NOTE)) { /***** Get data of comment *****/ row = mysql_fetch_row (mysql_res); diff --git a/swad_timeline_favourite.c b/swad_timeline_favourite.c index eb534934..545f9332 100644 --- a/swad_timeline_favourite.c +++ b/swad_timeline_favourite.c @@ -29,6 +29,7 @@ #include "swad_global.h" #include "swad_timeline.h" #include "swad_timeline_favourite.h" +#include "swad_timeline_publication.h" /*****************************************************************************/ /****************************** Public constants *****************************/ @@ -273,7 +274,7 @@ static void TL_Fav_FavNote (struct TL_Not_Note *Not) for the author of the post *****/ OriginalPubCod = TL_Not_GetPubCodOfOriginalNote (Not->NotCod); if (OriginalPubCod > 0) - TL_CreateNotifToAuthor (Not->UsrCod,OriginalPubCod,Ntf_EVENT_TIMELINE_FAV); + TL_Pub_CreateNotifToAuthor (Not->UsrCod,OriginalPubCod,Ntf_EVENT_TIMELINE_FAV); } } } @@ -332,7 +333,7 @@ void TL_Fav_ShowAllFaversComGbl (void) /***** Get data of comment *****/ Med_MediaConstructor (&Com.Content.Media); - Com.PubCod = TL_GetParamPubCod (); + Com.PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (&Com); Med_MediaDestructor (&Com.Content.Media); @@ -418,7 +419,7 @@ static void TL_Fav_FavComment (struct TL_Com_Comment *Com) Med_MediaConstructor (&Com->Content.Media); /***** Get data of comment *****/ - Com->PubCod = TL_GetParamPubCod (); + Com->PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (Com); if (Com->PubCod > 0) @@ -442,7 +443,7 @@ static void TL_Fav_FavComment (struct TL_Com_Comment *Com) /**** Create notification about favourite post for the author of the post ***/ - TL_CreateNotifToAuthor (Com->UsrCod,Com->PubCod,Ntf_EVENT_TIMELINE_FAV); + TL_Pub_CreateNotifToAuthor (Com->UsrCod,Com->PubCod,Ntf_EVENT_TIMELINE_FAV); } } @@ -458,7 +459,7 @@ static void TL_Fav_UnfComment (struct TL_Com_Comment *Com) Med_MediaConstructor (&Com->Content.Media); /***** Get data of comment *****/ - Com->PubCod = TL_GetParamPubCod (); + Com->PubCod = TL_Pub_GetParamPubCod (); TL_Com_GetDataOfCommByCod (Com); if (Com->PubCod > 0) diff --git a/swad_timeline_note.c b/swad_timeline_note.c index f913bf2c..fd65de40 100644 --- a/swad_timeline_note.c +++ b/swad_timeline_note.c @@ -41,6 +41,7 @@ #include "swad_profile.h" #include "swad_timeline.h" #include "swad_timeline_favourite.h" +#include "swad_timeline_publication.h" #include "swad_timeline_share.h" /*****************************************************************************/ @@ -660,12 +661,12 @@ void TL_Not_GetNoteSummary (const struct TL_Not_Note *Not, void TL_Not_StoreAndPublishNote (TL_Not_NoteType_t NoteType,long Cod) { - struct TL_Publication Pub; + struct TL_Pub_Publication Pub; TL_Not_StoreAndPublishNoteInternal (NoteType,Cod,&Pub); } -void TL_Not_StoreAndPublishNoteInternal (TL_Not_NoteType_t NoteType,long Cod,struct TL_Publication *Pub) +void TL_Not_StoreAndPublishNoteInternal (TL_Not_NoteType_t NoteType,long Cod,struct TL_Pub_Publication *Pub) { long HieCod; // Hierarchy code (institution/centre/degree/course) @@ -707,7 +708,7 @@ void TL_Not_StoreAndPublishNoteInternal (TL_Not_NoteType_t NoteType,long Cod,str /***** Publish note in timeline *****/ Pub->PublisherCod = Gbl.Usrs.Me.UsrDat.UsrCod; Pub->PubType = TL_PUB_ORIGINAL_NOTE; - TL_PublishPubInTimeline (Pub); + TL_Pub_PublishPubInTimeline (Pub); } /*****************************************************************************/ @@ -1084,7 +1085,7 @@ static void TL_Not_RemoveNoteMediaAndDBEntries (struct TL_Not_Note *Not) " FROM tl_pubs" " WHERE NotCod=%ld AND PubType=%u", Not->NotCod, - (unsigned) TL_PUB_COMMENT_TO_NOTE); + (unsigned) TL_Pub_COMMENT_TO_NOTE); /* For each comment... */ for (NumCom = 0; @@ -1309,3 +1310,27 @@ void TL_Not_GetDataOfNoteByCod (struct TL_Not_Note *Not) TL_Not_ResetNote (Not); } +/*****************************************************************************/ +/******************* Clear unused old timelines in database ******************/ +/*****************************************************************************/ + +void TL_Not_ClearOldTimelinesNotesFromDB (void) + { + /***** Remove timelines for expired sessions *****/ + DB_QueryDELETE ("can not remove old timelines", + "DELETE LOW_PRIORITY FROM tl_timelines" + " WHERE SessionId NOT IN (SELECT SessionId FROM sessions)"); + } + +/*****************************************************************************/ +/**************** Clear timeline for this session in database ****************/ +/*****************************************************************************/ + +void TL_Not_ClearTimelineNotesThisSessionFromDB (void) + { + /***** Remove timeline for this session *****/ + DB_QueryDELETE ("can not remove timeline", + "DELETE FROM tl_timelines" + " WHERE SessionId='%s'", + Gbl.Session.Id); + } diff --git a/swad_timeline_note.h b/swad_timeline_note.h index ddf5bcd0..96934c82 100644 --- a/swad_timeline_note.h +++ b/swad_timeline_note.h @@ -102,7 +102,7 @@ void TL_Not_GetNoteSummary (const struct TL_Not_Note *Not, char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1]); void TL_Not_StoreAndPublishNote (TL_Not_NoteType_t NoteType,long Cod); -void TL_Not_StoreAndPublishNoteInternal (TL_Not_NoteType_t NoteType,long Cod,struct TL_Publication *Pub); +void TL_Not_StoreAndPublishNoteInternal (TL_Not_NoteType_t NoteType,long Cod,struct TL_Pub_Publication *Pub); void TL_Not_MarkNoteAsUnavailable (TL_Not_NoteType_t NoteType,long Cod); void TL_Not_MarkNoteOneFileAsUnavailable (const char *Path); void TL_Not_MarkNotesChildrenOfFolderAsUnavailable (const char *Path); @@ -121,4 +121,7 @@ long TL_Not_GetPubCodOfOriginalNote (long NotCod); void TL_Not_GetDataOfNoteByCod (struct TL_Not_Note *Not); +void TL_Not_ClearOldTimelinesNotesFromDB (void); +void TL_Not_ClearTimelineNotesThisSessionFromDB (void); + #endif diff --git a/swad_timeline_publication.c b/swad_timeline_publication.c new file mode 100644 index 00000000..fb9b3638 --- /dev/null +++ b/swad_timeline_publication.c @@ -0,0 +1,988 @@ +// swad_timeline_publication.c: social timeline publications + +/* + 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 // For malloc and free +#include // For string functions +#include // For time_t + +#include "swad_database.h" +#include "swad_exam_announcement.h" +#include "swad_figure.h" +#include "swad_follow.h" +#include "swad_form.h" +#include "swad_forum.h" +#include "swad_global.h" +#include "swad_message.h" +#include "swad_notice.h" +#include "swad_photo.h" +#include "swad_profile.h" +#include "swad_setting.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_Pub_MAX_BYTES_SUBQUERY (128 - 1) +struct TL_Pub_SubQueries + { + char *TablePublishers; + char Publishers [TL_Pub_MAX_BYTES_SUBQUERY + 1]; + char RangeBottom [TL_Pub_MAX_BYTES_SUBQUERY + 1]; + char RangeTop [TL_Pub_MAX_BYTES_SUBQUERY + 1]; + char AlreadyExists[TL_Pub_MAX_BYTES_SUBQUERY + 1]; + }; + +struct TL_Pub_RangePubsToGet + { + long Top; + long Bottom; + }; + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/************************* Private global variables **************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ****************************/ +/*****************************************************************************/ + +static unsigned TL_Pub_GetMaxPubsToGet (const struct TL_Timeline *Timeline); + +static void TL_Pub_CreateTmpTableCurrentTimeline (const struct TL_Timeline *Timeline); +static void TL_Pub_CreateTmpTablePublishers (void); +static void TL_Pub_DropTmpTablesUsedToQueryTimeline (void); + +static void TL_Pub_CreateSubQueryPublishers (const struct TL_Timeline *Timeline, + struct TL_Pub_SubQueries *SubQueries); +static void TL_Pub_CreateSubQueryAlreadyExists (const struct TL_Timeline *Timeline, + struct TL_Pub_SubQueries *SubQueries); +static void TL_Pub_CreateSubQueryRangeBottom (const struct TL_Pub_RangePubsToGet *RangePubsToGet, + struct TL_Pub_SubQueries *SubQueries); +static void TL_Pub_CreateSubQueryRangeTop (const struct TL_Pub_RangePubsToGet *RangePubsToGet, + struct TL_Pub_SubQueries *SubQueries); + +static long TL_Pub_GetPubCodFromSession (const char *FieldName); +static void TL_Pub_UpdateFirstLastPubCodesIntoSession (const struct TL_Timeline *Timeline); + +static struct TL_Pub_Publication *TL_Pub_SelectTheMostRecentPub (const struct TL_Pub_SubQueries *SubQueries); + +static void TL_Pub_GetDataOfPublicationFromNextRow (MYSQL_RES *mysql_res, + struct TL_Pub_Publication *Pub); +static TL_Pub_PubType_t TL_Pub_GetPubTypeFromStr (const char *Str); + +/*****************************************************************************/ +/*************** Get list of pubications to show in timeline *****************/ +/*****************************************************************************/ + +void TL_Pub_GetListPubsToShowInTimeline (struct TL_Timeline *Timeline) + { + struct TL_Pub_SubQueries SubQueries; + struct TL_Pub_RangePubsToGet RangePubsToGet; + unsigned MaxPubsToGet = TL_Pub_GetMaxPubsToGet (Timeline); + unsigned NumPub; + struct TL_Pub_Publication *Pub; + + /***** Clear timeline for this session in database *****/ + if (Timeline->WhatToGet == TL_GET_RECENT_TIMELINE) + TL_Not_ClearTimelineNotesThisSessionFromDB (); + + /***** Create temporary table with notes in current timeline *****/ + TL_Pub_CreateTmpTableCurrentTimeline (Timeline); + + /***** Create temporary table and subquery with potential publishers *****/ + TL_Pub_CreateSubQueryPublishers (Timeline,&SubQueries); + + /***** Create subquery to get only notes not present in timeline *****/ + TL_Pub_CreateSubQueryAlreadyExists (Timeline,&SubQueries); + + /***** Get the publications in timeline *****/ + /* Initialize range of pubs: + + tl_pubs + _____ + |_____|11 + |_____|10 + _|_____| 9 <-- RangePubsToGet.Top + Get / |_____| 8 + pubs | |_____| 7 + from < |_____| 6 + this | |_____| 5 + range \_|_____| 4 + |_____| 3 <-- RangePubsToGet.Bottom + |_____| 2 + |_____| 1 + 0 + */ + switch (Timeline->WhatToGet) + { + case TL_GET_ONLY_NEW_PUBS: // Get the publications (without limit) newer than LastPubCod + /* This query is made via AJAX automatically from time to time */ + RangePubsToGet.Top = 0; // +Infinite + RangePubsToGet.Bottom = TL_Pub_GetPubCodFromSession ("LastPubCod"); + break; + case TL_GET_ONLY_OLD_PUBS: // Get some limited publications older than FirstPubCod + /* This query is made via AJAX + when I click in link to get old publications */ + RangePubsToGet.Top = TL_Pub_GetPubCodFromSession ("FirstPubCod"); + RangePubsToGet.Bottom = 0; // -Infinite + break; + case TL_GET_RECENT_TIMELINE: // Get some limited recent publications + default: + /* This is the first query to get initial timeline shown + ==> no notes yet in current timeline table */ + RangePubsToGet.Top = 0; // +Infinite + RangePubsToGet.Bottom = 0; // -Infinite + break; + } + /* Create subquery with bottom range of publications to get from tl_pubs. + Bottom publication code remains unchanged in all iterations of the next loop. */ + TL_Pub_CreateSubQueryRangeBottom (&RangePubsToGet,&SubQueries); + + /* + With the current approach, we select one by one + the publications and notes in a loop. In each iteration, + we get the more recent publication (original, shared or commment) + of every set of publications corresponding to the same note, + checking that the note is not already retrieved. + After getting a publication, its note code is stored + in order to not get it again. + + As an alternative, we tried to get the maximum PubCod, + i.e more recent publication (original, shared or commment), + of every set of publications corresponding to the same note: + "SELECT MAX(PubCod) AS NewestPubCod FROM tl_pubs ... + " GROUP BY NotCod ORDER BY NewestPubCod DESC LIMIT ..." + but this query is slow (several seconds) with a big table. + */ + + /* + Chained list of publications: + + Timeline->Pubs.Top Pub #0 + ______ ______ Pub #1 + |______|------>|______| ______ Pub #2 + |______| -> |______| ______ Pub #3 + |______| / |______| ->|______| ______ + |______| / |______| / |______| ->|______| + |_Next_|-- |______| / |______| // |______| + |_Next_|-- |______| // |______| + ______ |_Next_|--/ |______| + |______|---------------------------------------------- |_NULL_| + + Timeline->Pubs.Bottom + + */ + Timeline->Pubs.Top = + Timeline->Pubs.Bottom = NULL; + + for (NumPub = 0; + NumPub < MaxPubsToGet; + NumPub++) + { + /* Create subquery with top range of publications to get from tl_pubs + In each iteration of this loop, top publication code is changed to a lower value */ + TL_Pub_CreateSubQueryRangeTop (&RangePubsToGet,&SubQueries); + + /* Select the most recent publication from tl_pubs */ + Pub = TL_Pub_SelectTheMostRecentPub (&SubQueries); + + /* Chain the previous publication with the current one */ + if (NumPub == 0) + Timeline->Pubs.Top = Pub; // Pointer to top publication + else + Timeline->Pubs.Bottom->Next = Pub; // Chain the previous publication with the current one + Timeline->Pubs.Bottom = Pub; // Update pointer to bottom publication + + if (Pub == NULL) // Nothing got ==> abort loop + break; // Last publication + + /* Insert note in temporary tables with just retrieved notes. + These tables will be used to not get notes already shown */ + TL_Not_InsertNoteInJustRetrievedNotes (Pub->NotCod); + if (Timeline->WhatToGet == TL_GET_ONLY_OLD_PUBS) + TL_Not_InsertNoteInVisibleTimeline (Pub->NotCod); + + /* Narrow the range for the next iteration */ + RangePubsToGet.Top = Pub->PubCod; + } + + /***** Update first (oldest) and last (more recent) publication codes + into session for next refresh *****/ + TL_Pub_UpdateFirstLastPubCodesIntoSession (Timeline); + + /***** Add notes just retrieved to current timeline for this session *****/ + TL_Not_AddNotesJustRetrievedToTimelineThisSession (); + + /***** Drop temporary tables *****/ + TL_Pub_DropTmpTablesUsedToQueryTimeline (); + } + +/*****************************************************************************/ +/********* Get maximum number of publications to get from database ***********/ +/*****************************************************************************/ + +static unsigned TL_Pub_GetMaxPubsToGet (const struct TL_Timeline *Timeline) + { + static const unsigned MaxPubsToGet[TL_NUM_WHAT_TO_GET] = + { + [TL_GET_RECENT_TIMELINE] = TL_Pub_MAX_REC_PUBS_TO_GET_AND_SHOW, + [TL_GET_ONLY_NEW_PUBS ] = TL_Pub_MAX_NEW_PUBS_TO_GET_AND_SHOW, + [TL_GET_ONLY_OLD_PUBS ] = TL_Pub_MAX_OLD_PUBS_TO_GET_AND_SHOW, + }; + + return MaxPubsToGet[Timeline->WhatToGet]; + } + +/*****************************************************************************/ +/************* Create temporary tables used to query timeline ****************/ +/*****************************************************************************/ + +static void TL_Pub_CreateTmpTableCurrentTimeline (const struct TL_Timeline *Timeline) + { + /***** Create temporary table with notes just retrieved *****/ + DB_Query ("can not create temporary table", + "CREATE TEMPORARY TABLE tl_tmp_just_retrieved_notes " + "(NotCod BIGINT NOT NULL,UNIQUE INDEX(NotCod))" + " ENGINE=MEMORY"); + + if (Timeline->WhatToGet == TL_GET_ONLY_OLD_PUBS) + /***** Create temporary table with all notes visible in timeline *****/ + DB_Query ("can not create temporary table", + "CREATE TEMPORARY TABLE tl_tmp_visible_timeline " + "(NotCod BIGINT NOT NULL,UNIQUE INDEX(NotCod))" + " ENGINE=MEMORY" + " SELECT NotCod FROM tl_timelines WHERE SessionId='%s'", + Gbl.Session.Id); + } + +static void TL_Pub_CreateTmpTablePublishers (void) + { + /***** Create temporary table with me and the users I follow *****/ + DB_Query ("can not create temporary table", + "CREATE TEMPORARY TABLE tl_tmp_publishers " + "(UsrCod INT NOT NULL," + "UNIQUE INDEX(UsrCod))" + " ENGINE=MEMORY" + " SELECT %ld AS UsrCod" // Me + " UNION" + " SELECT FollowedCod AS UsrCod" // Users I follow + " FROM usr_follow" + " WHERE FollowerCod=%ld", + Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.Usrs.Me.UsrDat.UsrCod); + } + +/*****************************************************************************/ +/*************** Drop temporary tables used to query timeline ****************/ +/*****************************************************************************/ + +static void TL_Pub_DropTmpTablesUsedToQueryTimeline (void) + { + DB_Query ("can not remove temporary tables", + "DROP TEMPORARY TABLE IF EXISTS " + "tl_tmp_just_retrieved_notes," + "tl_tmp_visible_timeline," + "tl_tmp_publishers"); + } + +/*****************************************************************************/ +/******* Create temporary table and subquery with potential publishers *******/ +/*****************************************************************************/ + +static void TL_Pub_CreateSubQueryPublishers (const struct TL_Timeline *Timeline, + struct TL_Pub_SubQueries *SubQueries) + { + /***** Create temporary table and subquery with potential publishers *****/ + switch (Timeline->UsrOrGbl) + { + case TL_TIMELINE_USR: // Show the timeline of a user + SubQueries->TablePublishers = ""; + sprintf (SubQueries->Publishers,"tl_pubs.PublisherCod=%ld AND ", + Gbl.Usrs.Other.UsrDat.UsrCod); + break; + case TL_TIMELINE_GBL: // Show the global timeline + switch (Timeline->Who) + { + case Usr_WHO_ME: // Show my timeline + SubQueries->TablePublishers = ""; + snprintf (SubQueries->Publishers,sizeof (SubQueries->Publishers), + "tl_pubs.PublisherCod=%ld AND ", + Gbl.Usrs.Me.UsrDat.UsrCod); + break; + case Usr_WHO_FOLLOWED: // Show the timeline of the users I follow + TL_Pub_CreateTmpTablePublishers (); + SubQueries->TablePublishers = ",tl_tmp_publishers"; + Str_Copy (SubQueries->Publishers, + "tl_pubs.PublisherCod=tl_tmp_publishers.UsrCod AND ", + TL_Pub_MAX_BYTES_SUBQUERY); + break; + case Usr_WHO_ALL: // Show the timeline of all users + SubQueries->TablePublishers = ""; + SubQueries->Publishers[0] = '\0'; + break; + default: + Lay_WrongWhoExit (); + break; + } + break; + } + } + +/*****************************************************************************/ +/********* Create subquery to get only notes not present in timeline *********/ +/*****************************************************************************/ + +static void TL_Pub_CreateSubQueryAlreadyExists (const struct TL_Timeline *Timeline, + struct TL_Pub_SubQueries *SubQueries) + { + switch (Timeline->WhatToGet) + { + case TL_GET_RECENT_TIMELINE: + case TL_GET_ONLY_NEW_PUBS: + Str_Copy (SubQueries->AlreadyExists, + " tl_pubs.NotCod NOT IN" + " (SELECT NotCod FROM tl_tmp_just_retrieved_notes)", // Avoid notes just retrieved + TL_Pub_MAX_BYTES_SUBQUERY); + break; + case TL_GET_ONLY_OLD_PUBS: + Str_Copy (SubQueries->AlreadyExists, + " tl_pubs.NotCod NOT IN" + " (SELECT NotCod FROM tl_tmp_visible_timeline)", // Avoid notes already shown + TL_Pub_MAX_BYTES_SUBQUERY); + break; + } + } + +/*****************************************************************************/ +/***** Create subqueries with range of publications to get from tl_pubs ******/ +/*****************************************************************************/ + +static void TL_Pub_CreateSubQueryRangeBottom (const struct TL_Pub_RangePubsToGet *RangePubsToGet, + struct TL_Pub_SubQueries *SubQueries) + { + if (RangePubsToGet->Bottom > 0) + sprintf (SubQueries->RangeBottom,"tl_pubs.PubCod>%ld AND ", + RangePubsToGet->Bottom); + else + SubQueries->RangeBottom[0] = '\0'; + } + +static void TL_Pub_CreateSubQueryRangeTop (const struct TL_Pub_RangePubsToGet *RangePubsToGet, + struct TL_Pub_SubQueries *SubQueries) + { + if (RangePubsToGet->Top > 0) + sprintf (SubQueries->RangeTop,"tl_pubs.PubCod<%ld AND ", + RangePubsToGet->Top); + else + SubQueries->RangeTop[0] = '\0'; + } + +/*****************************************************************************/ +/************* Get last/first publication code stored in session *************/ +/*****************************************************************************/ +// FieldName can be: +// "LastPubCod" +// "FirstPubCod" + +static long TL_Pub_GetPubCodFromSession (const char *FieldName) + { + extern const char *Txt_The_session_has_expired; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long PubCod; + + /***** Get last publication code from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get publication code from session", + "SELECT %s FROM sessions" + " WHERE SessionId='%s'", + FieldName,Gbl.Session.Id) != 1) + Lay_ShowErrorAndExit (Txt_The_session_has_expired); + + /***** Get last publication code *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%ld",&PubCod) != 1) + PubCod = 0; + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return PubCod; + } + +/*****************************************************************************/ +/************* Update first (oldest) and last (more recent) ***************/ +/************* publication codes into session for next refresh ***************/ +/*****************************************************************************/ + +static void TL_Pub_UpdateFirstLastPubCodesIntoSession (const struct TL_Timeline *Timeline) + { + long FirstPubCod; + + switch (Timeline->WhatToGet) + { + case TL_GET_ONLY_NEW_PUBS: + DB_QueryUPDATE ("can not update first/last publication codes into session", + "UPDATE sessions" + " SET LastPubCod=" + "(SELECT IFNULL(MAX(PubCod),0)" + " FROM tl_pubs)" // The most recent publication + " WHERE SessionId='%s'", + Gbl.Session.Id); + break; + case TL_GET_ONLY_OLD_PUBS: + // The oldest publication code retrieved and shown + FirstPubCod = Timeline->Pubs.Bottom ? Timeline->Pubs.Bottom->PubCod : + 0; + + DB_QueryUPDATE ("can not update first/last publication codes into session", + "UPDATE sessions" + " SET FirstPubCod=%ld" + " WHERE SessionId='%s'", + FirstPubCod, + Gbl.Session.Id); + break; + case TL_GET_RECENT_TIMELINE: + // The oldest publication code retrieved and shown + FirstPubCod = Timeline->Pubs.Bottom ? Timeline->Pubs.Bottom->PubCod : + 0; + + DB_QueryUPDATE ("can not update first/last publication codes into session", + "UPDATE sessions" + " SET FirstPubCod=%ld," + "LastPubCod=" + "(SELECT IFNULL(MAX(PubCod),0)" + " FROM tl_pubs)" // The most recent publication + " WHERE SessionId='%s'", + FirstPubCod, + Gbl.Session.Id); + break; + } + } + +/*****************************************************************************/ +/************** Free chained list of publications in timeline ****************/ +/*****************************************************************************/ + +void TL_Pub_FreeListPubs (struct TL_Timeline *Timeline) + { + struct TL_Pub_Publication *Pub; + struct TL_Pub_Publication *Next; + + /***** Go over the list freeing memory *****/ + for (Pub = Timeline->Pubs.Top; + Pub; + Pub = Next) + { + /* Save a copy of pointer to next element before freeing it */ + Next = Pub->Next; + + /* Free memory used for this publication */ + free (Pub); + } + + /***** Reset pointers to top and bottom elements *****/ + Timeline->Pubs.Top = + Timeline->Pubs.Bottom = NULL; + } + +/*****************************************************************************/ +/************** Select the most recent publication from tl_pubs **************/ +/*****************************************************************************/ + +static struct TL_Pub_Publication *TL_Pub_SelectTheMostRecentPub (const struct TL_Pub_SubQueries *SubQueries) + { + MYSQL_RES *mysql_res; + unsigned NumPubs = 0; // Initialized to avoid warning + struct TL_Pub_Publication *Pub; + + NumPubs = + (unsigned) DB_QuerySELECT (&mysql_res,"can not get publication", + "SELECT tl_pubs.PubCod," // row[0] + "tl_pubs.NotCod," // row[1] + "tl_pubs.PublisherCod," // row[2] + "tl_pubs.PubType" // row[3] + " FROM tl_pubs%s" + " WHERE %s%s%s%s" + " ORDER BY tl_pubs.PubCod DESC LIMIT 1", + SubQueries->TablePublishers, + SubQueries->RangeBottom, + SubQueries->RangeTop, + SubQueries->Publishers, + SubQueries->AlreadyExists); + + if (NumPubs == 1) + { + /* Allocate space for publication */ + if ((Pub = (struct TL_Pub_Publication *) malloc (sizeof (struct TL_Pub_Publication))) == NULL) + Lay_ShowErrorAndExit ("Error allocating memory publication."); + + /* Get data of publication */ + TL_Pub_GetDataOfPublicationFromNextRow (mysql_res,Pub); + Pub->Next = NULL; + } + else + Pub = NULL; + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return Pub; + } + +/*****************************************************************************/ +/******************* Show new publications in timeline ***********************/ +/*****************************************************************************/ +// The publications are inserted as list elements of a hidden list + +void TL_Pub_InsertNewPubsInTimeline (struct TL_Timeline *Timeline) + { + struct TL_Pub_Publication *Pub; + struct TL_Not_Note Not; + + /***** List new publications timeline *****/ + for (Pub = Timeline->Pubs.Top; + Pub; + Pub = Pub->Next) + { + /* Get data of note */ + Not.NotCod = Pub->NotCod; + TL_Not_GetDataOfNoteByCod (&Not); + + /* Write note */ + TL_Not_WriteNote (Timeline,&Not, + Pub->TopMessage, + Pub->PublisherCod, + TL_DONT_HIGHLIGHT, + TL_DONT_SHOW_ALONE); + } + } + +/*****************************************************************************/ +/********************* Show old publications in timeline *********************/ +/*****************************************************************************/ +// The publications are inserted as list elements of a hidden list + +void TL_Pub_ShowOldPubsInTimeline (struct TL_Timeline *Timeline) + { + struct TL_Pub_Publication *Pub; + struct TL_Not_Note Not; + + /***** List old publications in timeline *****/ + for (Pub = Timeline->Pubs.Top; + Pub; + Pub = Pub->Next) + { + /* Get data of note */ + Not.NotCod = Pub->NotCod; + TL_Not_GetDataOfNoteByCod (&Not); + + /* Write note */ + TL_Not_WriteNote (Timeline,&Not, + Pub->TopMessage, + Pub->PublisherCod, + TL_DONT_HIGHLIGHT, + TL_DONT_SHOW_ALONE); + } + } + +/*****************************************************************************/ +/***************** Put link to view new publications in timeline *************/ +/*****************************************************************************/ + +void TL_Pub_PutLinkToViewNewPublications (void) + { + extern const char *The_ClassFormInBoxBold[The_NUM_THEMES]; + extern const char *Txt_See_new_activity; + + /***** Link to view (show hidden) new publications *****/ + // div is hidden. When new posts arrive to the client via AJAX, div is shown + HTM_DIV_Begin ("id=\"view_new_posts_container\"" + " class=\"TL_WIDTH TL_SEP VERY_LIGHT_BLUE\"" + " style=\"display:none;\""); + HTM_A_Begin ("href=\"\" class=\"%s\"" + " onclick=\"moveNewTimelineToTimeline();return false;\"", + The_ClassFormInBoxBold[Gbl.Prefs.Theme]); + HTM_TxtF ("%s (",Txt_See_new_activity); + HTM_SPAN_Begin ("id=\"view_new_posts_count\""); + HTM_Unsigned (0); + HTM_SPAN_End (); + HTM_Txt (")"); + HTM_A_End (); + HTM_DIV_End (); + } + +/*****************************************************************************/ +/***************** Put link to view old publications in timeline *************/ +/*****************************************************************************/ + +void TL_Pub_PutLinkToViewOldPublications (void) + { + extern const char *The_ClassFormInBoxBold[The_NUM_THEMES]; + extern const char *Txt_See_more; + + /***** Animated link to view old publications *****/ + HTM_DIV_Begin ("id=\"view_old_posts_container\"" + " class=\"TL_WIDTH TL_SEP VERY_LIGHT_BLUE\""); + HTM_A_Begin ("href=\"\" class=\"%s\" onclick=\"" + "document.getElementById('get_old_timeline').style.display='none';" // Icon to be hidden on click + "document.getElementById('getting_old_timeline').style.display='';" // Icon to be shown on click + "refreshOldTimeline();" + "return false;\"", + The_ClassFormInBoxBold[Gbl.Prefs.Theme]); + HTM_IMG (Cfg_URL_ICON_PUBLIC,"recycle16x16.gif","Txt_See_more", + "class=\"ICO20x20\" id=\"get_old_timeline\""); + HTM_IMG (Cfg_URL_ICON_PUBLIC,"working16x16.gif",Txt_See_more, + "class=\"ICO20x20\" style=\"display:none;\" id=\"getting_old_timeline\""); // Animated icon hidden + HTM_IMG (Cfg_URL_ICON_PUBLIC,"recycle16x16.gif","Txt_See_more", + "class=\"ICO20x20\" style=\"display:none;\" id=\"get_old_timeline\""); + HTM_TxtF (" %s",Txt_See_more); + HTM_A_End (); + HTM_DIV_End (); + } + +/*****************************************************************************/ +/*************** Put parameter with the code of a publication ****************/ +/*****************************************************************************/ + +void TL_Pub_PutHiddenParamPubCod (long PubCod) + { + Par_PutHiddenParamLong (NULL,"PubCod",PubCod); + } + +/*****************************************************************************/ +/**************** Get parameter with the code of a publication ***************/ +/*****************************************************************************/ + +long TL_Pub_GetParamPubCod (void) + { + /***** Get comment code *****/ + return Par_GetParToLong ("PubCod"); + } + +/*****************************************************************************/ +/*********** Create a notification for the author of a post/comment **********/ +/*****************************************************************************/ + +void TL_Pub_CreateNotifToAuthor (long AuthorCod,long PubCod, + Ntf_NotifyEvent_t NotifyEvent) + { + struct UsrData UsrDat; + bool CreateNotif; + bool NotifyByEmail; + + /***** Initialize structure with user's data *****/ + Usr_UsrDataConstructor (&UsrDat); + + UsrDat.UsrCod = AuthorCod; + if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS)) + { + /***** This fav must be notified by email? *****/ + CreateNotif = (UsrDat.NtfEvents.CreateNotif & (1 << NotifyEvent)); + NotifyByEmail = CreateNotif && + (UsrDat.NtfEvents.SendEmail & (1 << NotifyEvent)); + + /***** Create notification for the author of the post. + If this author wants to receive notifications by email, + activate the sending of a notification *****/ + if (CreateNotif) + Ntf_StoreNotifyEventToOneUser (NotifyEvent,&UsrDat,PubCod, + (Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL : + 0), + Gbl.Hierarchy.Ins.InsCod, + Gbl.Hierarchy.Ctr.CtrCod, + Gbl.Hierarchy.Deg.DegCod, + Gbl.Hierarchy.Crs.CrsCod); + } + + /***** Free memory used for user's data *****/ + Usr_UsrDataDestructor (&UsrDat); + } + +/*****************************************************************************/ +/*********************** Get code of note of a publication *******************/ +/*****************************************************************************/ + +long TL_Pub_GetNotCodFromPubCod (long PubCod) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long NotCod = -1L; + + /***** Get code of note from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get code of note", + "SELECT NotCod FROM tl_pubs" + " WHERE PubCod=%ld", + PubCod) == 1) // Result should have a unique row + { + /* Get code of note */ + row = mysql_fetch_row (mysql_res); + NotCod = Str_ConvertStrCodToLongCod (row[0]); + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NotCod; + } + +/*****************************************************************************/ +/***************** Get data of publication using its code ********************/ +/*****************************************************************************/ + +static void TL_Pub_GetDataOfPublicationFromNextRow (MYSQL_RES *mysql_res, + struct TL_Pub_Publication *Pub) + { + static const TL_TopMessage_t TopMessages[TL_NUM_PUB_TYPES] = + { + [TL_PUB_UNKNOWN ] = TL_TOP_MESSAGE_NONE, + [TL_PUB_ORIGINAL_NOTE ] = TL_TOP_MESSAGE_NONE, + [TL_PUB_SHARED_NOTE ] = TL_TOP_MESSAGE_SHARED, + [TL_Pub_COMMENT_TO_NOTE] = TL_TOP_MESSAGE_COMMENTED, + }; + MYSQL_ROW row; + + /***** Get next row from result *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0]: PubCod + row[1]: NotCod + row[2]: PublisherCod + row[3]: PubType + */ + + /***** Get code of publication (row[0]) *****/ + Pub->PubCod = Str_ConvertStrCodToLongCod (row[0]); + + /***** Get note code (row[1]) *****/ + Pub->NotCod = Str_ConvertStrCodToLongCod (row[1]); + + /***** Get publisher's code (row[2]) *****/ + Pub->PublisherCod = Str_ConvertStrCodToLongCod (row[2]); + + /***** Get type of publication (row[3]) *****/ + Pub->PubType = TL_Pub_GetPubTypeFromStr ((const char *) row[3]); + Pub->TopMessage = TopMessages[Pub->PubType]; + } + +/*****************************************************************************/ +/******* Get publication type from string number coming from database ********/ +/*****************************************************************************/ + +static TL_Pub_PubType_t TL_Pub_GetPubTypeFromStr (const char *Str) + { + unsigned UnsignedNum; + + if (sscanf (Str,"%u",&UnsignedNum) == 1) + if (UnsignedNum < TL_NUM_PUB_TYPES) + return (TL_Pub_PubType_t) UnsignedNum; + + return TL_PUB_UNKNOWN; + } + +/*****************************************************************************/ +/***************** Get notification of a new publication *********************/ +/*****************************************************************************/ + +void TL_Pub_GetNotifPublication (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], + char **ContentStr, + long PubCod,bool GetContent) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + struct TL_Pub_Publication Pub; + struct TL_Not_Note Not; + struct TL_PostContent Content; + size_t Length; + bool ContentCopied = false; + + /***** Return nothing on error *****/ + Pub.PubType = TL_PUB_UNKNOWN; + SummaryStr[0] = '\0'; // Return nothing on error + Content.Txt[0] = '\0'; + + /***** Get summary and content from post from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get data of publication", + "SELECT PubCod," // row[0] + "NotCod," // row[1] + "PublisherCod," // row[2] + "PubType" // row[3] + " FROM tl_pubs WHERE PubCod=%ld", + PubCod) == 1) // Result should have a unique row + /* Get data of publication from row */ + TL_Pub_GetDataOfPublicationFromNextRow (mysql_res,&Pub); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** Get summary and content *****/ + switch (Pub.PubType) + { + case TL_PUB_UNKNOWN: + break; + case TL_PUB_ORIGINAL_NOTE: + case TL_PUB_SHARED_NOTE: + /* Get data of note */ + Not.NotCod = Pub.NotCod; + TL_Not_GetDataOfNoteByCod (&Not); + + if (Not.NoteType == TL_NOTE_POST) + { + /***** Get content of post from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get the content of a post", + "SELECT Txt" // row[0] + " FROM tl_posts" + " WHERE PstCod=%ld", + Not.Cod) == 1) // Result should have a unique row + { + /***** Get row *****/ + row = mysql_fetch_row (mysql_res); + + /****** Get content (row[0]) *****/ + Str_Copy (Content.Txt,row[0], + Cns_MAX_BYTES_LONG_TEXT); + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** Copy content string *****/ + if (GetContent) + { + Length = strlen (Content.Txt); + if ((*ContentStr = (char *) malloc (Length + 1)) != NULL) + { + Str_Copy (*ContentStr,Content.Txt, + Length); + ContentCopied = true; + } + } + + /***** Copy summary string *****/ + Str_LimitLengthHTMLStr (Content.Txt,Ntf_MAX_CHARS_SUMMARY); + Str_Copy (SummaryStr,Content.Txt, + Ntf_MAX_BYTES_SUMMARY); + } + else + TL_Not_GetNoteSummary (&Not,SummaryStr); + break; + case TL_Pub_COMMENT_TO_NOTE: + /***** Get content of post from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get the content" + " of a comment to a note", + "SELECT Txt" // row[0] + " FROM tl_comments" + " WHERE PubCod=%ld", + Pub.PubCod) == 1) // Result should have a unique row + { + /***** Get row *****/ + row = mysql_fetch_row (mysql_res); + + /****** Get content (row[0]) *****/ + Str_Copy (Content.Txt,row[0], + Cns_MAX_BYTES_LONG_TEXT); + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** Copy content string *****/ + if (GetContent) + { + Length = strlen (Content.Txt); + if ((*ContentStr = (char *) malloc (Length + 1)) != NULL) + { + Str_Copy (*ContentStr,Content.Txt, + Length); + ContentCopied = true; + } + } + + /***** Copy summary string *****/ + Str_LimitLengthHTMLStr (Content.Txt,Ntf_MAX_CHARS_SUMMARY); + Str_Copy (SummaryStr,Content.Txt, + Ntf_MAX_BYTES_SUMMARY); + break; + } + + /***** Create empty content string if nothing copied *****/ + if (GetContent && !ContentCopied) + if ((*ContentStr = (char *) malloc (1)) != NULL) + (*ContentStr)[0] = '\0'; + } + +/*****************************************************************************/ +/********************* Publish note/comment in timeline **********************/ +/*****************************************************************************/ +// Pub->PubCod is set by the function + +void TL_Pub_PublishPubInTimeline (struct TL_Pub_Publication *Pub) + { + /***** Publish note in timeline *****/ + Pub->PubCod = + DB_QueryINSERTandReturnCode ("can not publish note/comment", + "INSERT INTO tl_pubs" + " (NotCod,PublisherCod,PubType,TimePublish)" + " VALUES" + " (%ld,%ld,%u,NOW())", + Pub->NotCod, + Pub->PublisherCod, + (unsigned) Pub->PubType); + + /***** Increment number of publications in user's figures *****/ + Prf_IncrementNumPubsUsr (Pub->PublisherCod); + } + +/*****************************************************************************/ +/****************** Get number of publications from a user *******************/ +/*****************************************************************************/ + +unsigned long TL_Pub_GetNumPubsUsr (long UsrCod) + { + /***** Get number of posts from a user from database *****/ + return DB_QueryCOUNT ("can not get number of publications from a user", + "SELECT COUNT(*) FROM tl_pubs" + " WHERE PublisherCod=%ld", + UsrCod); + } diff --git a/swad_timeline_publication.h b/swad_timeline_publication.h new file mode 100644 index 00000000..ad859e79 --- /dev/null +++ b/swad_timeline_publication.h @@ -0,0 +1,98 @@ +// swad_timeline_publication.h: social timeline publications + +#ifndef _SWAD_TL_PUB +#define _SWAD_TL_PUB +/* + SWAD (Shared Workspace At a Distance in Spanish), + 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 Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/*****************************************************************************/ +/********************************** Headers **********************************/ +/*****************************************************************************/ + +#include "swad_form.h" +#include "swad_media.h" +#include "swad_notification.h" +#include "swad_user.h" + +/*****************************************************************************/ +/****************************** Public constants *****************************/ +/*****************************************************************************/ + +// Number of recent publishings got and shown the first time, before refreshing +#define TL_Pub_MAX_REC_PUBS_TO_GET_AND_SHOW 10 // Recent publishings to show (first time) +#define TL_Pub_MAX_NEW_PUBS_TO_GET_AND_SHOW 10000 // New publishings retrieved (big number) +#define TL_Pub_MAX_OLD_PUBS_TO_GET_AND_SHOW 20 // Old publishings are retrieved in packs of this size + +/*****************************************************************************/ +/******************************** Public types *******************************/ +/*****************************************************************************/ + +#define TL_NUM_PUB_TYPES 4 +// If the numbers assigned to each event type change, +// it is necessary to change old numbers to new ones in database table tl_notes +typedef enum + { + TL_PUB_UNKNOWN = 0, + TL_PUB_ORIGINAL_NOTE = 1, + TL_PUB_SHARED_NOTE = 2, + TL_Pub_COMMENT_TO_NOTE = 3, + } TL_Pub_PubType_t; + +struct TL_Pub_Publication + { + long PubCod; + long NotCod; + long PublisherCod; // Sharer or writer of the publication + TL_Pub_PubType_t PubType; + TL_TopMessage_t TopMessage; // Used to show feedback on the action made + struct TL_Pub_Publication *Next; // Used for chained list + }; + +/*****************************************************************************/ +/****************************** Public prototypes ****************************/ +/*****************************************************************************/ + +void TL_Pub_GetListPubsToShowInTimeline (struct TL_Timeline *Timeline); +void TL_Pub_FreeListPubs (struct TL_Timeline *Timeline); + +void TL_Pub_InsertNewPubsInTimeline (struct TL_Timeline *Timeline); +void TL_Pub_ShowOldPubsInTimeline (struct TL_Timeline *Timeline); + +void TL_Pub_PutLinkToViewNewPublications (void); +void TL_Pub_PutLinkToViewOldPublications (void); + +void TL_Pub_PutHiddenParamPubCod (long PubCod); +long TL_Pub_GetParamPubCod (void); + +void TL_Pub_CreateNotifToAuthor (long AuthorCod,long PubCod, + Ntf_NotifyEvent_t NotifyEvent); + +long TL_Pub_GetNotCodFromPubCod (long PubCod); + +void TL_Pub_GetNotifPublication (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], + char **ContentStr, + long PubCod,bool GetContent); + +void TL_Pub_PublishPubInTimeline (struct TL_Pub_Publication *Pub); + +unsigned long TL_Pub_GetNumPubsUsr (long UsrCod); + +#endif diff --git a/swad_timeline_share.c b/swad_timeline_share.c index dda26cf8..a8b4dcb2 100644 --- a/swad_timeline_share.c +++ b/swad_timeline_share.c @@ -28,6 +28,7 @@ #include "swad_database.h" #include "swad_global.h" #include "swad_timeline.h" +#include "swad_timeline_publication.h" #include "swad_timeline_share.h" /*****************************************************************************/ @@ -161,8 +162,7 @@ void TL_Sha_ShaNoteGbl (void) static void TL_Sha_ShaNote (struct TL_Not_Note *Not) { - // extern const char *Txt_The_original_post_no_longer_exists; - struct TL_Publication Pub; + struct TL_Pub_Publication Pub; bool ItsMe; long OriginalPubCod; @@ -181,7 +181,7 @@ static void TL_Sha_ShaNote (struct TL_Not_Note *Not) Pub.NotCod = Not->NotCod; Pub.PublisherCod = Gbl.Usrs.Me.UsrDat.UsrCod; Pub.PubType = TL_PUB_SHARED_NOTE; - TL_PublishPubInTimeline (&Pub); // Set Pub.PubCod + TL_Pub_PublishPubInTimeline (&Pub); // Set Pub.PubCod /* Update number of times this note is shared */ TL_Sha_UpdateNumTimesANoteHasBeenShared (Not); @@ -190,7 +190,7 @@ static void TL_Sha_ShaNote (struct TL_Not_Note *Not) for the author of the post ***/ OriginalPubCod = TL_Not_GetPubCodOfOriginalNote (Not->NotCod); if (OriginalPubCod > 0) - TL_CreateNotifToAuthor (Not->UsrCod,OriginalPubCod,Ntf_EVENT_TIMELINE_SHARE); + TL_Pub_CreateNotifToAuthor (Not->UsrCod,OriginalPubCod,Ntf_EVENT_TIMELINE_SHARE); } } }