mirror of https://github.com/acanas/swad-core.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
12 KiB
C
349 lines
12 KiB
C
// swad_timeline_post.c: social timeline posts
|
|
|
|
/*
|
|
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-2023 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 <stdio.h> // For asprintf
|
|
#include <stdlib.h> // For free
|
|
|
|
#include "swad_alert.h"
|
|
#include "swad_database.h"
|
|
#include "swad_error.h"
|
|
#include "swad_global.h"
|
|
#include "swad_info.h"
|
|
#include "swad_media.h"
|
|
#include "swad_message.h"
|
|
#include "swad_parameter.h"
|
|
#include "swad_profile.h"
|
|
#include "swad_timeline.h"
|
|
#include "swad_timeline_database.h"
|
|
#include "swad_timeline_form.h"
|
|
#include "swad_timeline_note.h"
|
|
#include "swad_timeline_post.h"
|
|
#include "swad_timeline_publication.h"
|
|
|
|
/*****************************************************************************/
|
|
/************************* Private constants and types ***********************/
|
|
/*****************************************************************************/
|
|
|
|
#define TmlPst_MAX_CHARS_IN_POST 1000 // Maximum number of characters in a post
|
|
|
|
/*****************************************************************************/
|
|
/************** External global variables from others modules ****************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private prototypes ****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void TmlPst_GetPostContent (long PstCod,struct TmlPst_Content *Content);
|
|
static void TmlPst_ShowPostContent (struct TmlPst_Content *Content);
|
|
|
|
static void TmlPst_PutFormToWriteNewPost (struct Tml_Timeline *Timeline);
|
|
|
|
static long TmlPst_ReceivePost (void);
|
|
|
|
/*****************************************************************************/
|
|
/***************** Get from database and write public post *******************/
|
|
/*****************************************************************************/
|
|
|
|
void TmlPst_GetAndWritePost (long PstCod)
|
|
{
|
|
struct TmlPst_Content Content;
|
|
|
|
/***** Initialize media *****/
|
|
Med_MediaConstructor (&Content.Media);
|
|
|
|
/***** Get post content from database *****/
|
|
TmlPst_GetPostContent (PstCod,&Content);
|
|
|
|
/***** Show post content *****/
|
|
TmlPst_ShowPostContent (&Content);
|
|
|
|
/***** Free media *****/
|
|
Med_MediaDestructor (&Content.Media);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************************** Get post content *****************************/
|
|
/*****************************************************************************/
|
|
// Media must be initialized before calling this function
|
|
|
|
static void TmlPst_GetPostContent (long PstCod,struct TmlPst_Content *Content)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
|
|
/***** Get post from database *****/
|
|
if (Tml_DB_GetPostByCod (PstCod,&mysql_res) == 1)
|
|
{
|
|
/* Get row */
|
|
row = mysql_fetch_row (mysql_res);
|
|
/*
|
|
row[0] Txt
|
|
row[1] MedCod
|
|
*/
|
|
/* Get content (row[0]) */
|
|
Str_Copy (Content->Txt,row[0],sizeof (Content->Txt) - 1);
|
|
|
|
/* Get media (row[1]) */
|
|
Content->Media.MedCod = Str_ConvertStrCodToLongCod (row[1]);
|
|
Med_GetMediaDataByCod (&Content->Media);
|
|
}
|
|
else
|
|
{
|
|
Content->Txt[0] = '\0';
|
|
Med_ResetMedia (&Content->Media);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************************** Get post content *****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void TmlPst_ShowPostContent (struct TmlPst_Content *Content)
|
|
{
|
|
/***** Trivial check *****/
|
|
if (Content == NULL)
|
|
Err_ShowErrorAndExit ("Wrong content.");
|
|
|
|
/***** Write content text *****/
|
|
if (Content->Txt[0])
|
|
{
|
|
HTM_DIV_Begin ("class=\"Tml_TXT Tml_TXT_%s\"",The_GetSuffix ());
|
|
Msg_WriteMsgContent (Content->Txt,true,false);
|
|
HTM_DIV_End ();
|
|
}
|
|
|
|
/***** Show media *****/
|
|
Med_ShowMedia (&Content->Media,"Tml_PST_MED_CONT Tml_RIGHT_WIDTH",
|
|
"Tml_PST_MED Tml_RIGHT_WIDTH");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** Form to write a new publication **********************/
|
|
/*****************************************************************************/
|
|
|
|
void TmlPst_PutPhotoAndFormToWriteNewPost (struct Tml_Timeline *Timeline)
|
|
{
|
|
/***** Begin list *****/
|
|
HTM_UL_Begin ("class=\"Tml_LIST\"");
|
|
|
|
/***** Begin list item *****/
|
|
HTM_LI_Begin ("class=\"Tml_WIDTH\"");
|
|
|
|
/***** Left: write author's photo (my photo) *****/
|
|
TmlNot_ShowAuthorPhoto (&Gbl.Usrs.Me.UsrDat);
|
|
|
|
/***** Right: author's name, time, textarea *****/
|
|
TmlPst_PutFormToWriteNewPost (Timeline);
|
|
|
|
/***** End list item *****/
|
|
HTM_LI_End ();
|
|
|
|
/***** End list *****/
|
|
HTM_UL_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************** Author's name, time, and form with textarea ****************/
|
|
/*****************************************************************************/
|
|
|
|
static void TmlPst_PutFormToWriteNewPost (struct Tml_Timeline *Timeline)
|
|
{
|
|
extern const char *Txt_New_TIMELINE_post;
|
|
char *Class;
|
|
|
|
/***** Begin container *****/
|
|
HTM_DIV_Begin ("class=\"Tml_RIGHT_CONT Tml_RIGHT_WIDTH\"");
|
|
|
|
/***** Author name *****/
|
|
if (asprintf (&Class,"Tml_RIGHT_AUTHOR Tml_RIGHT_AUTHOR_WIDTH BT_LINK DAT_STRONG_%s BOLD",
|
|
The_GetSuffix ()) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
TmlNot_WriteAuthorName (&Gbl.Usrs.Me.UsrDat,Class);
|
|
free (Class);
|
|
|
|
/***** Form to write the post *****/
|
|
/* Begin container */
|
|
HTM_DIV_Begin ("class=\"Tml_FORM_NEW_PST Tml_RIGHT_WIDTH\"");
|
|
|
|
/* Form with textarea */
|
|
TmlFrm_BeginForm (Timeline,TmlFrm_RECEIVE_POST);
|
|
if (asprintf (&Class,"Tml_COM_TEXTAREA Tml_RIGHT_WIDTH INPUT_%s",
|
|
The_GetSuffix ()) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
TmlPst_PutTextarea (Txt_New_TIMELINE_post,Class);
|
|
free (Class);
|
|
TmlFrm_EndForm ();
|
|
|
|
/* End container */
|
|
HTM_DIV_End ();
|
|
|
|
/***** End container *****/
|
|
HTM_DIV_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*** Put textarea and button inside a form to submit a new post or comment ***/
|
|
/*****************************************************************************/
|
|
|
|
void TmlPst_PutTextarea (const char *Placeholder,const char *ClassTextArea)
|
|
{
|
|
extern const char *Txt_Post;
|
|
char IdDivImgButton[Frm_MAX_BYTES_ID + 1];
|
|
char *ClassInput;
|
|
|
|
/***** Set unique id for the hidden div *****/
|
|
Frm_SetUniqueId (IdDivImgButton);
|
|
|
|
/***** Textarea to write the content *****/
|
|
HTM_TEXTAREA_Begin ("name=\"Txt\" rows=\"1\" maxlength=\"%u\""
|
|
" placeholder=\"%s…\" class=\"%s\""
|
|
" onfocus=\"expandTextarea(this,'%s','6');\"",
|
|
TmlPst_MAX_CHARS_IN_POST,
|
|
Placeholder,ClassTextArea,
|
|
IdDivImgButton);
|
|
HTM_TEXTAREA_End ();
|
|
|
|
/***** Begin hidden div *****/
|
|
HTM_DIV_Begin ("id=\"%s\" style=\"display:none;\"",IdDivImgButton);
|
|
|
|
/***** Help on editor *****/
|
|
Lay_HelpPlainEditor ();
|
|
|
|
/***** Attached image (optional) *****/
|
|
if (asprintf (&ClassInput,"Tml_MED_INPUT_WIDTH INPUT_%s",
|
|
The_GetSuffix ()) < 0)
|
|
Err_NotEnoughMemoryExit ();
|
|
Med_PutMediaUploader (-1,ClassInput);
|
|
free (ClassInput);
|
|
|
|
/***** Submit button *****/
|
|
HTM_BUTTON_Submit_Begin (NULL,"class=\"BT_SUBMIT_INLINE BT_CREATE\"");
|
|
HTM_Txt (Txt_Post);
|
|
HTM_BUTTON_End ();
|
|
|
|
/***** End hidden div *****/
|
|
HTM_DIV_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************* Receive and store a new public post *********************/
|
|
/*****************************************************************************/
|
|
|
|
void TmlPst_ReceivePostUsr (void)
|
|
{
|
|
struct Tml_Timeline Timeline;
|
|
long NotCod;
|
|
|
|
/***** Reset timeline context *****/
|
|
Tml_ResetTimeline (&Timeline);
|
|
|
|
/***** Get user whom profile is displayed *****/
|
|
Usr_GetParOtherUsrCodEncryptedAndGetUsrData ();
|
|
|
|
/***** Show user's profile *****/
|
|
Prf_ShowUserProfile (&Gbl.Usrs.Other.UsrDat);
|
|
|
|
/***** Begin section *****/
|
|
HTM_SECTION_Begin (Tml_TIMELINE_SECTION_ID);
|
|
|
|
/***** Receive and store post, and
|
|
write updated timeline after publication (user) *****/
|
|
NotCod = TmlPst_ReceivePost ();
|
|
Tml_ShowTimelineUsrHighlighting (&Timeline,NotCod);
|
|
|
|
/***** End section *****/
|
|
HTM_SECTION_End ();
|
|
}
|
|
|
|
void TmlPst_ReceivePostGbl (void)
|
|
{
|
|
struct Tml_Timeline Timeline;
|
|
long NotCod;
|
|
|
|
/***** Initialize timeline *****/
|
|
Tml_InitTimelineGbl (&Timeline);
|
|
|
|
/***** Receive and store post *****/
|
|
NotCod = TmlPst_ReceivePost ();
|
|
|
|
/***** Write updated timeline after publication (global) *****/
|
|
Tml_ShowTimelineGblHighlighting (&Timeline,NotCod);
|
|
}
|
|
|
|
// Returns the code of the note just created
|
|
static long TmlPst_ReceivePost (void)
|
|
{
|
|
struct TmlPst_Content Content;
|
|
long PstCod;
|
|
struct TmlPub_Publication Pub;
|
|
|
|
/***** Get the content of the new post *****/
|
|
Par_GetParAndChangeFormat ("Txt",Content.Txt,Cns_MAX_BYTES_LONG_TEXT,
|
|
Str_TO_RIGOROUS_HTML,Str_REMOVE_SPACES);
|
|
|
|
/***** Initialize image *****/
|
|
Med_MediaConstructor (&Content.Media);
|
|
|
|
/***** Get attached image (action, file and title) *****/
|
|
Content.Media.Width = Tml_IMAGE_SAVED_MAX_WIDTH;
|
|
Content.Media.Height = Tml_IMAGE_SAVED_MAX_HEIGHT;
|
|
Content.Media.Quality = Tml_IMAGE_SAVED_QUALITY;
|
|
Med_GetMediaFromForm (-1L,-1L,-1,&Content.Media,NULL,NULL);
|
|
Ale_ShowAlerts (NULL);
|
|
|
|
if (Content.Txt[0] || // Text not empty
|
|
Content.Media.Status == Med_PROCESSED) // A media is attached
|
|
{
|
|
/***** Store media in filesystem and database *****/
|
|
Med_RemoveKeepOrStoreMedia (-1L,&Content.Media);
|
|
|
|
/***** Publish *****/
|
|
/* Insert post content in the database */
|
|
PstCod = Tml_DB_CreateNewPost (&Content);
|
|
|
|
/* Insert post in notes */
|
|
TmlNot_StoreAndPublishNoteInternal (TmlNot_POST,PstCod,&Pub);
|
|
|
|
/***** Analyze content and store notifications about mentions *****/
|
|
Str_AnalyzeTxtAndStoreNotifyEventToMentionedUsrs (Pub.PubCod,Content.Txt);
|
|
}
|
|
else // Text and image are empty
|
|
Pub.NotCod = -1L;
|
|
|
|
/***** Free image *****/
|
|
Med_MediaDestructor (&Content.Media);
|
|
|
|
return Pub.NotCod;
|
|
}
|