From 406cdf2076b5be29e892d8ea3ffdfd975590b803 Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Sat, 26 Jun 2010 13:20:38 +0000 Subject: [PATCH] Board ReadMarkers implemented; fixes in Thread ReadMarkers --- Builder/IISMainHandler/build.txt | 2 +- Builder/IISUploadHandler/build.txt | 2 +- Common/SqlObject.cs | 12 +++- Common/UserContext.cs | 7 ++ Common/actions/ChangeSet.cs | 1 + Common/dataobjects/Board.cs | 91 ++++++++++++++++++++++-- Common/dataobjects/Thread.cs | 27 ++----- IISMainHandler/WebContext.cs | 9 +++ IISMainHandler/handlers/BoardHandler.cs | 13 +++- IISMainHandler/handlers/PostHandler.cs | 17 +++-- IISMainHandler/handlers/ThreadHandler.cs | 21 +++--- templates/Full/elems/Main.xslt | 2 + 12 files changed, 159 insertions(+), 45 deletions(-) diff --git a/Builder/IISMainHandler/build.txt b/Builder/IISMainHandler/build.txt index d35d5f7..52f6c1a 100644 --- a/Builder/IISMainHandler/build.txt +++ b/Builder/IISMainHandler/build.txt @@ -1 +1 @@ -347 \ No newline at end of file +352 \ No newline at end of file diff --git a/Builder/IISUploadHandler/build.txt b/Builder/IISUploadHandler/build.txt index eb13855..3ca9062 100644 --- a/Builder/IISUploadHandler/build.txt +++ b/Builder/IISUploadHandler/build.txt @@ -1 +1 @@ -79 \ No newline at end of file +84 \ No newline at end of file diff --git a/Common/SqlObject.cs b/Common/SqlObject.cs index d2e129b..7e99404 100644 --- a/Common/SqlObject.cs +++ b/Common/SqlObject.cs @@ -99,7 +99,7 @@ namespace FLocal.Common { } - abstract public class SqlObject : SqlObject where T : SqlObject, new() { + abstract public class SqlObject : SqlObject, IComparable where T : SqlObject, new() { public static List LoadByIds(IEnumerable ids) { @@ -135,6 +135,16 @@ namespace FLocal.Common { return res; } + int IComparable.CompareTo(T other) { + if(other.id > this.id) { + return -1; + } else if(other.id == this.id) { + return 0; + } else { + return 1; + } + } + } } diff --git a/Common/UserContext.cs b/Common/UserContext.cs index 386831f..78f8ba2 100644 --- a/Common/UserContext.cs +++ b/Common/UserContext.cs @@ -25,6 +25,13 @@ namespace FLocal.Common { abstract public XElement formatTotalPosts(long posts); + /// + /// May be null + /// + abstract public dataobjects.Account account { + get; + } + } public static class UserContext_Extensions { diff --git a/Common/actions/ChangeSet.cs b/Common/actions/ChangeSet.cs index 749846d..63f47e6 100644 --- a/Common/actions/ChangeSet.cs +++ b/Common/actions/ChangeSet.cs @@ -24,6 +24,7 @@ namespace FLocal.Common.actions { dataobjects.Board.TableSpec.TABLE, dataobjects.Thread.TableSpec.TABLE, dataobjects.Post.TableSpec.TABLE, + dataobjects.Board.ReadMarkerTableSpec.TABLE, dataobjects.Thread.ReadMarkerTableSpec.TABLE, dataobjects.Session.TableSpec.TABLE, } diff --git a/Common/dataobjects/Board.cs b/Common/dataobjects/Board.cs index e26da2a..e2e4d8c 100644 --- a/Common/dataobjects/Board.cs +++ b/Common/dataobjects/Board.cs @@ -6,6 +6,7 @@ using System.Xml.Linq; using FLocal.Core; using FLocal.Core.DB; using FLocal.Core.DB.conditions; +using FLocal.Common.actions; namespace FLocal.Common.dataobjects { public class Board : SqlObject { @@ -27,6 +28,18 @@ namespace FLocal.Common.dataobjects { public void refreshSqlObject(int id) { Refresh(id); } } + public class ReadMarkerTableSpec : ISqlObjectTableSpec { + public const string TABLE = "Boards_ReadMarkers"; + public const string FIELD_ID = "Id"; + public const string FIELD_BOARDID = "BoardId"; + public const string FIELD_ACCOUNTID = "AccountId"; + public const string FIELD_LASTREADDATE = "LastReadDate"; + public static readonly ReadMarkerTableSpec instance = new ReadMarkerTableSpec(); + public string name { get { return TABLE; } } + public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { } + } + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } private int _sortOrder; @@ -149,8 +162,12 @@ namespace FLocal.Common.dataobjects { Cache>.instance.delete(this.subBoards_Locker); } - private bool hasNewPosts() { - return Core.Util.RandomInt(0, 1000) < 500; + public bool hasNewPosts(Account account) { + if(!this.lastPostId.HasValue) { + return false; + } else { + return this.getLastReadDate(account) < this.lastPost.postDate; + } } private XElement exportLastPostInfo(UserContext context) { @@ -170,7 +187,7 @@ namespace FLocal.Common.dataobjects { ); } - public XElement exportToXml(UserContext context, bool includeSubBoards) { + public XElement exportToXml(UserContext context, bool includeSubBoards, params XElement[] additional) { XElement result = new XElement("board", new XElement("id", this.id), new XElement("sortOrder", this.sortOrder), @@ -179,16 +196,23 @@ namespace FLocal.Common.dataobjects { new XElement("totalThreads", this.totalThreads), new XElement("name", this.name), new XElement("description", this.description), - new XElement("hasNewPosts", this.hasNewPosts().ToPlainString()), new XElement("lastPostInfo", this.exportLastPostInfo(context)) ); + if(context.account != null) { + result.Add(new XElement("hasNewPosts", this.hasNewPosts(context.account).ToPlainString())); + } + if(includeSubBoards) { result.Add(new XElement("subBoards", from board in this.subBoards select board.exportToXml(context, false) )); } + if(additional.Length > 0) { + result.Add(additional); + } + return result; } @@ -225,5 +249,64 @@ namespace FLocal.Common.dataobjects { ); } + public DateTime getLastReadDate(Account account) { + List stringIds = Config.instance.mainConnection.LoadIdsByConditions( + ReadMarkerTableSpec.instance, + new ComplexCondition( + ConditionsJoinType.AND, + new ComparisonCondition( + ReadMarkerTableSpec.instance.getColumnSpec(ReadMarkerTableSpec.FIELD_BOARDID), + ComparisonType.EQUAL, + this.id.ToString() + ), + new ComparisonCondition( + ReadMarkerTableSpec.instance.getColumnSpec(ReadMarkerTableSpec.FIELD_ACCOUNTID), + ComparisonType.EQUAL, + account.id.ToString() + ) + ), + Diapasone.unlimited + ); + if(stringIds.Count > 1) { + throw new CriticalException("more than one row"); + } + if(stringIds.Count < 1) { + return new DateTime(0); + } + Dictionary data = Config.instance.mainConnection.LoadById(ReadMarkerTableSpec.instance, stringIds[0]); + return Util.ParseDateTimeFromTimestamp(data[ReadMarkerTableSpec.FIELD_LASTREADDATE]).Value; + } + + public void markAsRead(Account account) { + if(this.lastPostId.HasValue) { + ChangeSetUtil.ApplyChanges( + new InsertOrUpdateChange( + ReadMarkerTableSpec.instance, + new Dictionary { + { ReadMarkerTableSpec.FIELD_BOARDID, new ScalarFieldValue(this.id.ToString()) }, + { ReadMarkerTableSpec.FIELD_ACCOUNTID, new ScalarFieldValue(account.id.ToString()) }, + { ReadMarkerTableSpec.FIELD_LASTREADDATE, new ScalarFieldValue(DateTime.Now.ToUTCString()) }, + }, + new Dictionary { + { ReadMarkerTableSpec.FIELD_LASTREADDATE, new ScalarFieldValue(DateTime.Now.ToUTCString()) }, + }, + new ComplexCondition( + ConditionsJoinType.AND, + new ComparisonCondition( + ReadMarkerTableSpec.instance.getColumnSpec(ReadMarkerTableSpec.FIELD_BOARDID), + ComparisonType.EQUAL, + this.id.ToString() + ), + new ComparisonCondition( + ReadMarkerTableSpec.instance.getColumnSpec(ReadMarkerTableSpec.FIELD_ACCOUNTID), + ComparisonType.EQUAL, + account.id.ToString() + ) + ) + ) + ); + } + } + } } diff --git a/Common/dataobjects/Thread.cs b/Common/dataobjects/Thread.cs index db5216f..5f4128e 100644 --- a/Common/dataobjects/Thread.cs +++ b/Common/dataobjects/Thread.cs @@ -152,10 +152,6 @@ namespace FLocal.Common.dataobjects { this._totalViews = int.Parse(data[TableSpec.FIELD_TOTALVIEWS]); } - private bool hasNewPosts() { - return Core.Util.RandomInt(0, 1000) < 500; - } - public XElement exportToXmlSimpleWithParent(UserContext context) { return new XElement("thread", new XElement("id", this.id), @@ -182,6 +178,9 @@ namespace FLocal.Common.dataobjects { if(includeFirstPost) { result.Add(new XElement("firstPost", this.firstPost.exportToXmlWithoutThread(context, false))); } + if(context.account != null) { + result.Add(new XElement("afterLastRead", this.getLastReadId(context.account) + 1)); + } if(additional.Length > 0) { result.Add(additional); } @@ -224,7 +223,7 @@ namespace FLocal.Common.dataobjects { }); } - private Post getLastRead(Account account) { + public int getLastReadId(Account account) { List stringIds = Config.instance.mainConnection.LoadIdsByConditions( ReadMarkerTableSpec.instance, new ComplexCondition( @@ -246,24 +245,13 @@ namespace FLocal.Common.dataobjects { throw new CriticalException("more than one row"); } if(stringIds.Count < 1) { - return null; + return 0; } Dictionary data = Config.instance.mainConnection.LoadById(ReadMarkerTableSpec.instance, stringIds[0]); if((data[ReadMarkerTableSpec.FIELD_POSTID] == "") || (data[ReadMarkerTableSpec.FIELD_POSTID] == null)) { - return null; - } - return Post.LoadById(int.Parse(data[ReadMarkerTableSpec.FIELD_POSTID])); - } - - public int getLastReadId(Session session) { - if(session == null) { return 0; } - Post post = this.getLastRead(session.account); - if(post == null) { - return 0; - } - return post.id; + return int.Parse(data[ReadMarkerTableSpec.FIELD_POSTID]); } public void markAsRead(Account account, Post minPost, Post maxPost) { @@ -282,7 +270,7 @@ namespace FLocal.Common.dataobjects { { ReadMarkerTableSpec.FIELD_POSTID, new ScalarFieldValue( - (minPost.id < this.firstPostId) + (minPost.id <= this.firstPostId) ? maxPost.id.ToString() : @@ -330,7 +318,6 @@ namespace FLocal.Common.dataobjects { } ) } - }, new ComplexCondition( ConditionsJoinType.AND, diff --git a/IISMainHandler/WebContext.cs b/IISMainHandler/WebContext.cs index bb697cc..94b1cb9 100644 --- a/IISMainHandler/WebContext.cs +++ b/IISMainHandler/WebContext.cs @@ -62,6 +62,15 @@ namespace FLocal.IISHandler { public Session session; + public override Account account { + get { + if(this.session == null) { + return null; + } + return this.session.account; + } + } + public WebContext(HttpContext httpcontext) { this.httpcontext = httpcontext; this.requestTime = DateTime.Now; diff --git a/IISMainHandler/handlers/BoardHandler.cs b/IISMainHandler/handlers/BoardHandler.cs index e8cd4c3..048b77f 100644 --- a/IISMainHandler/handlers/BoardHandler.cs +++ b/IISMainHandler/handlers/BoardHandler.cs @@ -6,6 +6,7 @@ using System.Web; using System.Xml.Linq; using FLocal.Common; using FLocal.Common.dataobjects; +using FLocal.Core; using FLocal.Core.DB; namespace FLocal.IISHandler.handlers { @@ -22,14 +23,22 @@ namespace FLocal.IISHandler.handlers { Board board = Board.LoadById(int.Parse(context.requestParts[1])); PageOuter pageOuter = PageOuter.createFromGet(context.requestParts, context.userSettings.threadsPerPage, 2); IEnumerable threads = board.getThreads(pageOuter, context); - return new XElement[] { + XElement[] result = new XElement[] { new XElement("currentLocation", board.exportToXmlSimpleWithParent(context)), new XElement("boards", from subBoard in board.subBoards select subBoard.exportToXml(context, true)), new XElement("threads", - (from thread in threads select thread.exportToXml(context, false, new XElement("afterLastRead", thread.getLastReadId(context.session) + 1))).addNumbers(), + (from thread in threads select thread.exportToXml(context, false)).addNumbers(), pageOuter.exportToXml(1, 5, 1) ) }; + + if(context.session != null) { + if(pageOuter.start == 0) { + board.markAsRead(context.session.account); + } + } + + return result; } } diff --git a/IISMainHandler/handlers/PostHandler.cs b/IISMainHandler/handlers/PostHandler.cs index 0b51bd0..4dcf6ad 100644 --- a/IISMainHandler/handlers/PostHandler.cs +++ b/IISMainHandler/handlers/PostHandler.cs @@ -21,18 +21,23 @@ namespace FLocal.IISHandler.handlers { override protected XElement[] getSpecificData(WebContext context) { Post post = Post.LoadById(int.Parse(context.requestParts[1])); - int lastReadId = post.thread.getLastReadId(context.session); - - post.thread.incrementViewsCounter(); + int lastReadId = 0; if(context.session != null) { - post.thread.markAsRead(context.session.account, post, post); + lastReadId = post.thread.getLastReadId(context.session.account); } - return new XElement[] { + XElement[] result = new XElement[] { new XElement("currentLocation", post.exportToXmlSimpleWithParent(context)), new XElement("posts", post.exportToXmlWithoutThread(context, true, new XElement("isUnread", (post.id > lastReadId).ToPlainString()))) }; - } + + post.thread.incrementViewsCounter(); + if(context.session != null) { + post.thread.markAsRead(context.session.account, post, post); + } + + return result; + } } diff --git a/IISMainHandler/handlers/ThreadHandler.cs b/IISMainHandler/handlers/ThreadHandler.cs index be09504..2311562 100644 --- a/IISMainHandler/handlers/ThreadHandler.cs +++ b/IISMainHandler/handlers/ThreadHandler.cs @@ -51,24 +51,25 @@ namespace FLocal.IISHandler.handlers { ); IEnumerable posts = thread.getPosts(pageOuter, context); - int lastReadId = thread.getLastReadId(context.session); - - thread.incrementViewsCounter(); - if((context.session != null) && (posts.Count() > 0)) { - thread.markAsRead( - context.session.account, - (from post in posts orderby post.id ascending select post).First(), - (from post in posts orderby post.id descending select post).First() - ); + int lastReadId = 0; + if(context.session != null) { + lastReadId = thread.getLastReadId(context.session.account); } - return new XElement[] { + XElement[] result = new XElement[] { new XElement("currentLocation", thread.exportToXmlSimpleWithParent(context)), new XElement("posts", from post in posts select post.exportToXmlWithoutThread(context, true, new XElement("isUnread", (post.id > lastReadId).ToPlainString())), pageOuter.exportToXml(2, 5, 2) ) }; + + thread.incrementViewsCounter(); + if((context.session != null) && (posts.Count() > 0)) { + thread.markAsRead(context.session.account, posts.Min(), posts.Max()); + } + + return result; } } diff --git a/templates/Full/elems/Main.xslt b/templates/Full/elems/Main.xslt index 65ab652..4b3a6c1 100644 --- a/templates/Full/elems/Main.xslt +++ b/templates/Full/elems/Main.xslt @@ -13,9 +13,11 @@ +
Data used for authoring this XHTML document: <xsl:copy-of select="/"/> + ]]>