diff --git a/css/swad15.102.css b/css/swad15.105.css similarity index 99% rename from css/swad15.102.css rename to css/swad15.105.css index 49fc92930..78217a158 100644 --- a/css/swad15.102.css +++ b/css/swad15.105.css @@ -1675,7 +1675,7 @@ a:hover img.CENTRE_PHOTO_SHOW text-align:center; vertical-align:middle; } -#recent_timeline +#recent_timeline_list { display:none; } diff --git a/js/swad15.104.js b/js/swad15.105.js similarity index 97% rename from js/swad15.104.js rename to js/swad15.105.js index b34673a91..534340a3e 100644 --- a/js/swad15.104.js +++ b/js/swad15.105.js @@ -26,9 +26,6 @@ var Gbl_HTMLContent; // Global variable used to call SWAD via AJAX var ActionAJAX; -// Global variable that stores last publishing code got from database in timeline -var LastPubCod = 0; - // Global variables used in writeLocalClock() var secondsSince1970UTC; @@ -358,8 +355,7 @@ function refreshSocialTimeline() { objXMLHttpReqSoc = AJAXCreateObject(); if (objXMLHttpReqSoc) { var RefreshParams = RefreshParamNxtActSoc + '&' + - RefreshParamIdSes + '&' + - 'LastPubCod=' + LastPubCod; + RefreshParamIdSes; objXMLHttpReqSoc.onreadystatechange = readSocialTimelineData; // onreadystatechange must be lowercase objXMLHttpReqSoc.open('POST',ActionAJAX,true); @@ -454,14 +450,11 @@ function readLastClicksData() { function readSocialTimelineData() { if (objXMLHttpReqSoc.readyState == 4) { // Check if data have been received if (objXMLHttpReqSoc.status == 200) { - var endOfDelay = objXMLHttpReqSoc.responseText.indexOf('|',0); // Get separator position - var endOfLastPubCod = objXMLHttpReqSoc.responseText.indexOf('|',endOfDelay+1); // Get separator position + var endOfDelay = objXMLHttpReqSoc.responseText.indexOf('|',0); // Get separator position + var delay = parseInt(objXMLHttpReqSoc.responseText.substring(0,endOfDelay)); // Get refresh delay + var htmlRecentTimeline = objXMLHttpReqSoc.responseText.substring(endOfDelay+1); // Get HTML code for social timeline - var delay = parseInt(objXMLHttpReqSoc.responseText.substring(0,endOfDelay)); // Get refresh delay - LastPubCod = parseInt(objXMLHttpReqSoc.responseText.substring(endOfDelay+1,endOfLastPubCod)); // Get last publishing code - var htmlRecentTimeline = objXMLHttpReqSoc.responseText.substring(endOfLastPubCod+1); // Get HTML code for social timeline - - var recentTimeline = document.getElementById('recent_timeline'); // Access to UL with the recent timeline + var recentTimeline = document.getElementById('recent_timeline_list'); // Access to UL with the recent timeline if (recentTimeline) { recentTimeline.innerHTML = htmlRecentTimeline + recentTimeline.innerHTML; // Update list of publishings in recent timeline var countRecentTimeline = recentTimeline.childNodes.length; @@ -488,11 +481,11 @@ function readSocialTimelineData() { function moveRecentTimelineToTimeline() { var viewNewPostsContainer = document.getElementById('view_new_posts_container'); var viewNewPostsCount = document.getElementById('view_new_posts_count'); - var recentTimeline = document.getElementById('recent_timeline'); // Access to social timeline DIV + var recentTimeline = document.getElementById('recent_timeline_list'); // Access to social timeline DIV var countRecentTimeline = recentTimeline.childNodes.length; if (countRecentTimeline) { - var timeline = document.getElementById("timeline"); + var timeline = document.getElementById("timeline_list"); // Move all the LI elements in UL 'recentTimeline' to the top of UL 'timeline' for(var i=0; i < countRecentTimeline; i++) timeline.insertBefore(recentTimeline.lastChild, timeline.childNodes[0]); diff --git a/sql/swad.sql b/sql/swad.sql index 344d74921..14c1dd9f4 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -905,6 +905,7 @@ CREATE TABLE IF NOT EXISTS sessions ( CrsCod INT NOT NULL DEFAULT -1, LastTime DATETIME, LastRefresh DATETIME, + LastPubCod BIGINT NOT NULL DEFAULT 0, LastPageMsgRcv INT NOT NULL DEFAULT 1, LastPageMsgSnt INT NOT NULL DEFAULT 1, WhatToSearch TINYINT NOT NULL DEFAULT 0, diff --git a/swad_action.c b/swad_action.c index 9a956bcab..a81dd0267 100644 --- a/swad_action.c +++ b/swad_action.c @@ -1339,7 +1339,7 @@ struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = /* ActMnu */{ 2,-1,TabUnk,ActMnu ,0x1FF,0x1FF,0x1FF,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,NULL ,NULL}, /* ActRefCon */{ 845,-1,TabUnk,ActRefCon ,0x1FF,0x1FF,0x1FF,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Lay_RefreshNotifsAndConnected ,NULL}, /* ActRefLstClk */{ 994,-1,TabUnk,ActRefLstClk ,0x1FE,0x1FE,0x1FE,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Lay_RefreshLastClicks ,NULL}, - /* ActRefSocTim */{1509,-1,TabUnk,ActRefSocTim ,0x1FE,0x1FE,0x1FE,Act_CONTENT_NORM,Act_MAIN_WINDOW,Soc_GetParamLastPubCod ,Lay_RefreshSocialTimeline ,NULL}, + /* ActRefSocTim */{1509,-1,TabUnk,ActRefSocTim ,0x1FE,0x1FE,0x1FE,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Lay_RefreshSocialTimeline ,NULL}, /* ActWebSvc */{ 892,-1,TabUnk,ActWebSvc ,0x1FF,0x1FF,0x1FF,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Plg_WebService ,NULL}, // TabSys ****************************************************************** diff --git a/swad_changelog.h b/swad_changelog.h index 52fd4a4f6..90519fe23 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -113,18 +113,24 @@ // TODO: Forum SWAD should be always named "SWAD"? // TODO: Enable chat for guests? // TODO: Go to forum post (or at least to forum thread) from social timeline? +// TODO: Include time of last comment in table social_timeline to display social publishings with new comments when refreshing +// TODO: Change refreshing time from 5 seconds to 1 minute or so. Increment one second after each refresh? /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.104.4 (2016-01-09)" +#define Log_PLATFORM_VERSION "SWAD 15.105 (2016-01-10)" #define CSS_FILE "swad15.102.css" #define JS_FILE "swad15.104.js" // Number of lines (includes comments but not blank lines) has been got with the following command: // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1 /* + Version 15.105: Jan 10, 2016 Get only publishings newest than a give publishing. (191912 lines) + 1 change necessary in database: +ALTER TABLE sessions ADD COLUMN LastPubCod BIGINT NOT NULL DEFAULT 0 AFTER LastRefresh; + Version 15.104.4: Jan 09, 2016 Last social publishing code is sent and got via AJAX. (191831 lines) Version 15.104.3: Jan 09, 2016 Changes in layout of social timeline. (191784 lines) Version 15.104.2: Jan 09, 2016 Refresh recent social timeline via AJAX. (191769 lines) diff --git a/swad_database.c b/swad_database.c index 96560167b..15499c7cc 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1908,12 +1908,14 @@ mysql> DESCRIBE sessions; | CrsCod | int(11) | NO | | -1 | | | LastTime | datetime | YES | | NULL | | | LastRefresh | datetime | YES | | NULL | | +| LastPubCod | bigint(20) | NO | | 0 | | | LastPageMsgRcv | int(11) | NO | | 1 | | | LastPageMsgSnt | int(11) | NO | | 1 | | | WhatToSearch | tinyint(4) | NO | | 0 | | | SearchString | varchar(255) | NO | | NULL | | +| SideCols | tinyint(4) | NO | | 3 | | +----------------+--------------+------+-----+---------+-------+ -15 rows in set (0.00 sec) +17 rows in set (0.00 sec) */ DB_CreateTable ("CREATE TABLE IF NOT EXISTS sessions (" "SessionId CHAR(43) NOT NULL," @@ -1927,6 +1929,7 @@ mysql> DESCRIBE sessions; "CrsCod INT NOT NULL DEFAULT -1," "LastTime DATETIME," "LastRefresh DATETIME," + "LastPubCod BIGINT NOT NULL DEFAULT 0" "LastPageMsgRcv INT NOT NULL DEFAULT 1," "LastPageMsgSnt INT NOT NULL DEFAULT 1," "WhatToSearch TINYINT NOT NULL DEFAULT 0," diff --git a/swad_global.h b/swad_global.h index 8ad311d8a..4ee752597 100644 --- a/swad_global.h +++ b/swad_global.h @@ -382,10 +382,6 @@ struct Globals bool Error; // To signal that an error has happened const char *NicknameForQR; // Used as parameter in contextual links } Usrs; - struct - { - long LastPubCod; // Last code of publishing got from database when refreshing timeline via AJAX - } Social; struct { Sco_Scope_t Current; diff --git a/swad_layout.c b/swad_layout.c index 1302b39e3..96f12b271 100644 --- a/swad_layout.c +++ b/swad_layout.c @@ -1498,9 +1498,8 @@ void Lay_RefreshLastClicks (void) void Lay_RefreshSocialTimeline (void) { // Send, before the HTML, the refresh time and the last publishing got from database - fprintf (Gbl.F.Out,"%lu|%ld|", - Cfg_TIME_TO_REFRESH_SOCIAL_TIMELINE, - Gbl.Social.LastPubCod); + fprintf (Gbl.F.Out,"%lu|", + Cfg_TIME_TO_REFRESH_SOCIAL_TIMELINE); Soc_GetAndShowRecentTimelineGbl (); /***** All the output is made, so don't write anymore *****/ diff --git a/swad_pagination.c b/swad_pagination.c index 60a0cac85..43c798d83 100644 --- a/swad_pagination.c +++ b/swad_pagination.c @@ -568,7 +568,7 @@ void Pag_GetParamPagNum (Pag_WhatPaginate_t WhatPaginate) void Pag_SaveLastPageMsgIntoSession (Pag_WhatPaginate_t WhatPaginate,unsigned NumPage) { - char Query[512]; + char Query[128+Ses_LENGTH_SESSION_ID]; /***** Save last page of received/sent messages *****/ sprintf (Query,"UPDATE sessions SET %s='%u' WHERE SessionId='%s'", @@ -584,7 +584,7 @@ void Pag_SaveLastPageMsgIntoSession (Pag_WhatPaginate_t WhatPaginate,unsigned Nu unsigned Pag_GetLastPageMsgFromSession (Pag_WhatPaginate_t WhatPaginate) { - char Query[512]; + char Query[128+Ses_LENGTH_SESSION_ID]; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; diff --git a/swad_social.c b/swad_social.c index 390b51ac7..c49fdb37d 100644 --- a/swad_social.c +++ b/swad_social.c @@ -178,13 +178,21 @@ extern struct Globals Gbl; /***************************** Private prototypes ****************************/ /*****************************************************************************/ +static void Soc_BuildQueryToGetTimelineGbl (bool GetOnlyNewPubs,char *Query); +static long Soc_GetLastPubCodFromSession (void); +static void Soc_UpdateLastPubCodIntoSession (void); +static void Soc_DropTemporaryTableWithPubCods (void); + static void Soc_ShowTimeline (const char *Query,const char *Title); +static void Soc_ShowRecentTimeline (const char *Query); + static void Soc_GetDataOfSocialPublishingFromRow (MYSQL_ROW row,struct SocialPublishing *SocPub); static void Soc_PutLinkToViewRecentPublishings (void); static void Soc_WriteSocialNote (const struct SocialPublishing *SocPub, const struct SocialNote *SocNot, bool ShowAlone, - bool ViewTopLine); + bool ViewTopLine, + const char *Style); static void Soc_WriteDateTime (time_t TimeUTC); static void Soc_GetAndWriteSocialPost (long PstCod); static void Soc_PutFormGoToAction (const struct SocialNote *SocNot); @@ -280,58 +288,15 @@ void Soc_ShowTimelineGbl (void) if (!Fol_GetNumFollowing (Gbl.Usrs.Me.UsrDat.UsrCod)) Lay_ShowAlert (Lay_INFO,Txt_You_dont_follow_any_user); - /***** Create temporary table with publishing codes *****/ - sprintf (Query,"DROP TEMPORARY TABLE IF EXISTS pub_cods"); - if (mysql_query (&Gbl.mysql,Query)) - DB_ExitOnMySQLError ("can not remove temporary tables"); - - sprintf (Query,"CREATE TEMPORARY TABLE pub_cods (PubCod BIGINT NOT NULL,UNIQUE INDEX(PubCod)) ENGINE=MEMORY" - " SELECT MIN(PubCod) AS PubCod" - " FROM social_timeline" - " WHERE PublisherCod IN" - " (SELECT '%ld'" - " UNION" - " SELECT FollowedCod FROM usr_follow WHERE FollowerCod='%ld')" - " GROUP BY NotCod" - " ORDER BY PubCod DESC LIMIT %u", - Gbl.Usrs.Me.UsrDat.UsrCod, - Gbl.Usrs.Me.UsrDat.UsrCod, - Soc_NUM_PUBS_IN_TIMELINE); - if (mysql_query (&Gbl.mysql,Query)) - DB_ExitOnMySQLError ("can not create temporary table"); - - /***** Build query to show timeline including the users I am following *****/ - sprintf (Query,"SELECT PubCod,NotCod,PublisherCod,AuthorCod,UNIX_TIMESTAMP(TimePublish)" - " FROM social_timeline WHERE PubCod IN " - "(SELECT PubCod FROM pub_cods)" - " ORDER BY PubCod DESC"); + /***** Build query to get timeline *****/ + Soc_BuildQueryToGetTimelineGbl (false, // Do not get only new publishings + Query); /***** Show timeline *****/ Soc_ShowTimeline (Query,Txt_Public_activity); /***** Drop temporary table with publishing codes *****/ - sprintf (Query,"DROP TEMPORARY TABLE IF EXISTS pub_cods"); - if (mysql_query (&Gbl.mysql,Query)) - DB_ExitOnMySQLError ("can not remove temporary tables"); - } - -/*****************************************************************************/ -/**** Get parameter with the more recent publishing code got from database ***/ -/*****************************************************************************/ -// This parameter is sent and receiveda again via AJAX -// As an alternative, it could be stored in database with the code of session - -void Soc_GetParamLastPubCod (void) - { - char LongStr[1+10+1]; - long LongNum; - - /***** Get the more recent publishing code *****/ - Gbl.Social.LastPubCod = 0; - Par_GetParToText ("LastPubCod",LongStr,1+10); - if (LongStr[0]) // Parameter "LastPubCod" available - if (sscanf (LongStr,"%ld",&LongNum) == 1) - Gbl.Social.LastPubCod = LongNum; + Soc_DropTemporaryTableWithPubCods (); } /*****************************************************************************/ @@ -340,14 +305,124 @@ void Soc_GetParamLastPubCod (void) void Soc_GetAndShowRecentTimelineGbl (void) { - fprintf (Gbl.F.Out,"
  • " - "PID = %lu; " - "Time = %s; " - "Gbl.Social.LastPubCod = %ld" - "
  • ", - (unsigned long) Gbl.PID, - Gbl.Now.YYYYMMDDHHMMSS, - Gbl.Social.LastPubCod); + char Query[512]; + + /***** Build query to get timeline *****/ + Soc_BuildQueryToGetTimelineGbl (true, // Get only new publishings + Query); + + /***** Show recent timeline *****/ + Soc_ShowRecentTimeline (Query); + + /***** Drop temporary table with publishing codes *****/ + Soc_DropTemporaryTableWithPubCods (); + } + +/*****************************************************************************/ +/************************ Build query to get timeline ************************/ +/*****************************************************************************/ + +static void Soc_BuildQueryToGetTimelineGbl (bool GetOnlyNewPubs,char *Query) + { + char SubQuery[64]; + long LastPubCod; + + /****** Build subquery in order to get only the publishings + more recent than LastPubCod *****/ + SubQuery[0] = '\0'; + if (GetOnlyNewPubs) + { + LastPubCod = Soc_GetLastPubCodFromSession (); + if (LastPubCod > 0) + sprintf (SubQuery,"PubCod>'%ld' AND ",LastPubCod); + } + + /***** Remove temporary table with publishing codes *****/ + sprintf (Query,"DROP TEMPORARY TABLE IF EXISTS pub_cods"); + if (mysql_query (&Gbl.mysql,Query)) + DB_ExitOnMySQLError ("can not remove temporary tables"); + + /***** Create temporary table with publishing codes *****/ + sprintf (Query,"CREATE TEMPORARY TABLE pub_cods" + " (PubCod BIGINT NOT NULL,UNIQUE INDEX(PubCod)) ENGINE=MEMORY" + " SELECT MIN(PubCod) AS PubCod" + " FROM social_timeline" + " WHERE %sPublisherCod IN" + " (SELECT '%ld'" + " UNION" + " SELECT FollowedCod FROM usr_follow WHERE FollowerCod='%ld')" + " GROUP BY NotCod" + " ORDER BY PubCod DESC LIMIT %u", + SubQuery, + Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.Usrs.Me.UsrDat.UsrCod, + Soc_NUM_PUBS_IN_TIMELINE); + if (mysql_query (&Gbl.mysql,Query)) + DB_ExitOnMySQLError ("can not create temporary table"); + + /***** Update last publishing code into session for next refresh *****/ + // Do this inmediately after getting the publishings codes + Soc_UpdateLastPubCodIntoSession (); + + /***** Build query to show timeline including the users I am following *****/ + sprintf (Query,"SELECT PubCod,NotCod,PublisherCod,AuthorCod,UNIX_TIMESTAMP(TimePublish)" + " FROM social_timeline WHERE PubCod IN " + "(SELECT PubCod FROM pub_cods)" + " ORDER BY PubCod DESC"); + } + +/*****************************************************************************/ +/******** Get last publishing code of last refresh stored in session *********/ +/*****************************************************************************/ + +static long Soc_GetLastPubCodFromSession (void) + { + char Query[128+Ses_LENGTH_SESSION_ID]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long LastPubCod; + + /***** Get last page of received/sent messages from database *****/ + sprintf (Query,"SELECT LastPubCod FROM sessions WHERE SessionId='%s'", + Gbl.Session.Id); + if (DB_QuerySELECT (Query,&mysql_res,"can not get last publishing code") != 1) + Lay_ShowErrorAndExit ("Error when getting last publishing code."); + + /***** Get last publishing code *****/ + row = mysql_fetch_row (mysql_res); + if (sscanf (row[0],"%ld",&LastPubCod) != 1) + LastPubCod = 0; + + return LastPubCod; + } + +/*****************************************************************************/ +/*********************** Update last publishing code *************************/ +/*****************************************************************************/ + +static void Soc_UpdateLastPubCodIntoSession (void) + { + char Query[128+Ses_LENGTH_SESSION_ID]; + + /***** Update last publishing code *****/ + sprintf (Query,"UPDATE sessions" + " SET LastPubCod=(SELECT MAX(PubCod) FROM social_timeline)" + " WHERE SessionId='%s'", + Gbl.Session.Id); + DB_QueryUPDATE (Query,"can not update last page of messages"); + } + +/*****************************************************************************/ +/**************** Drop temporary table with publishing codes *****************/ +/*****************************************************************************/ + +static void Soc_DropTemporaryTableWithPubCods (void) + { + char Query[128]; + + sprintf (Query,"DROP TEMPORARY TABLE IF EXISTS pub_cods"); + if (mysql_query (&Gbl.mysql,Query)) + DB_ExitOnMySQLError ("can not remove temporary tables"); } /*****************************************************************************/ @@ -378,12 +453,12 @@ static void Soc_ShowTimeline (const char *Query,const char *Title) Gbl.Usrs.Other.UsrDat.UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod) // It's me Soc_PutHiddenFormToWriteNewPost (); - /***** Hidden list where insert new publishings via AJAX *****/ + /***** Hidden div where insert new publishings via AJAX *****/ Soc_PutLinkToViewRecentPublishings (); - fprintf (Gbl.F.Out,""); + fprintf (Gbl.F.Out,""); /***** List publishings in timeline one by one *****/ - fprintf (Gbl.F.Out,"