Version20.25

This commit is contained in:
acanas 2021-02-11 13:10:08 +01:00
parent d5439d6032
commit 636665abda
14 changed files with 1177 additions and 1067 deletions

View File

@ -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 \

View File

@ -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)

View File

@ -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);

View File

@ -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))

View File

@ -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 ();
}
/*****************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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

988
swad_timeline_publication.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/*********************************** Headers *********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include <linux/limits.h> // For PATH_MAX
#include <stdio.h> // For asprintf
#include <stdlib.h> // For malloc and free
#include <string.h> // For string functions
#include <sys/types.h> // 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 ("&nbsp;%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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************** 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

View File

@ -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);
}
}
}