From 29f54df1172130df112848b2007da217fd49445c Mon Sep 17 00:00:00 2001 From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com> Date: Tue, 31 Aug 2010 19:42:32 +0000 Subject: [PATCH] Moderation implemented --- Builder/IISMainHandler/build.txt | 2 +- Common/Common.csproj | 3 + Common/TableManager.cs | 3 + Common/actions/ChangeSet.cs | 2 + Common/dataobjects/Board.cs | 11 +- Common/dataobjects/Moderator.cs | 172 ++++++++++++++++++ Common/dataobjects/Post.cs | 99 +++++++++- Common/dataobjects/Punishment.cs | 146 +++++++++++++++ Common/dataobjects/PunishmentType.cs | 92 ++++++++++ Common/dataobjects/Thread.cs | 1 + Common/dataobjects/UserGroup.cs | 3 + IISMainHandler/HandlersFactory.cs | 4 + IISMainHandler/IISMainHandler.csproj | 2 + IISMainHandler/handlers/PostHandler.cs | 7 +- IISMainHandler/handlers/ThreadHandler.cs | 5 +- .../handlers/request/PunishHandler.cs | 34 ++++ .../handlers/response/PunishHandler.cs | 42 +++++ static/css/global.css | 11 ++ static/images/mod.gif | Bin 0 -> 123 bytes static/images/punish.gif | Bin 0 -> 1039 bytes templates/Full/PostPunish.xslt | 98 ++++++++++ templates/Full/elems/BoardInfo.xslt | 4 +- templates/Full/elems/Main.xslt | 3 + templates/Full/elems/PostInfo.xslt | 29 +++ templates/Full/result/MessagePunished.xslt | 48 +++++ templates/Lite/PostPunish.xslt | 94 ++++++++++ templates/Lite/elems/Main.xslt | 3 + templates/Lite/elems/PostInfo.xslt | 7 + templates/Lite/result/MessagePunished.xslt | 48 +++++ 29 files changed, 964 insertions(+), 9 deletions(-) create mode 100644 Common/dataobjects/Moderator.cs create mode 100644 Common/dataobjects/Punishment.cs create mode 100644 Common/dataobjects/PunishmentType.cs create mode 100644 IISMainHandler/handlers/request/PunishHandler.cs create mode 100644 IISMainHandler/handlers/response/PunishHandler.cs create mode 100644 static/images/mod.gif create mode 100644 static/images/punish.gif create mode 100644 templates/Full/PostPunish.xslt create mode 100644 templates/Full/result/MessagePunished.xslt create mode 100644 templates/Lite/PostPunish.xslt create mode 100644 templates/Lite/result/MessagePunished.xslt diff --git a/Builder/IISMainHandler/build.txt b/Builder/IISMainHandler/build.txt index 1307450..ad12b97 100644 --- a/Builder/IISMainHandler/build.txt +++ b/Builder/IISMainHandler/build.txt @@ -1 +1 @@ -956 \ No newline at end of file +983 \ No newline at end of file diff --git a/Common/Common.csproj b/Common/Common.csproj index 508f4ca..d28ac80 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -91,11 +91,14 @@ + + + diff --git a/Common/TableManager.cs b/Common/TableManager.cs index a3593a7..66a5cfb 100644 --- a/Common/TableManager.cs +++ b/Common/TableManager.cs @@ -15,8 +15,11 @@ namespace FLocal.Common { dataobjects.Category.TableSpec.instance, dataobjects.Invite.TableSpec.instance, dataobjects.LocalNetwork.TableSpec.instance, + dataobjects.Moderator.TableSpec.instance, dataobjects.PMConversation.TableSpec.instance, dataobjects.PMMessage.TableSpec.instance, + dataobjects.Punishment.TableSpec.instance, + dataobjects.PunishmentType.TableSpec.instance, dataobjects.Poll.TableSpec.instance, dataobjects.Post.TableSpec.instance, dataobjects.PostLayer.TableSpec.instance, diff --git a/Common/actions/ChangeSet.cs b/Common/actions/ChangeSet.cs index 6430d20..ac2878a 100644 --- a/Common/actions/ChangeSet.cs +++ b/Common/actions/ChangeSet.cs @@ -34,6 +34,8 @@ namespace FLocal.Common.actions { dataobjects.Poll.TableSpec.TABLE, dataobjects.Poll.Vote.TableSpec.TABLE, dataobjects.Invite.TableSpec.TABLE, + dataobjects.Moderator.TableSpec.TABLE, + dataobjects.Punishment.TableSpec.TABLE, dataobjects.Session.TableSpec.TABLE, } ); diff --git a/Common/dataobjects/Board.cs b/Common/dataobjects/Board.cs index 74274ea..0504c00 100644 --- a/Common/dataobjects/Board.cs +++ b/Common/dataobjects/Board.cs @@ -201,6 +201,14 @@ namespace FLocal.Common.dataobjects { ); } + public XElement exportToXmlSimple(UserContext context) { + return new XElement("board", + new XElement("id", this.id), + new XElement("name", this.name), + new XElement("description", this.description) + ); + } + public XElement exportToXml(UserContext context, bool includeSubBoards, params XElement[] additional) { XElement result = new XElement("board", new XElement("id", this.id), @@ -210,7 +218,8 @@ namespace FLocal.Common.dataobjects { new XElement("totalThreads", this.totalThreads), new XElement("name", this.name), new XElement("description", this.description), - new XElement("lastPostInfo", this.exportLastPostInfo(context)) + new XElement("lastPostInfo", this.exportLastPostInfo(context)), + new XElement("moderators", from moderator in Moderator.GetModerators(this) select moderator.user.exportToXmlForViewing(context)) ); if(context.account != null) { diff --git a/Common/dataobjects/Moderator.cs b/Common/dataobjects/Moderator.cs new file mode 100644 index 0000000..8554569 --- /dev/null +++ b/Common/dataobjects/Moderator.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using FLocal.Core; +using FLocal.Core.DB; +using FLocal.Core.DB.conditions; + +namespace FLocal.Common.dataobjects { + public class Moderator : SqlObject { + + public class TableSpec : ISqlObjectTableSpec { + public const string TABLE = "Moderators"; + public const string FIELD_ID = "Id"; + public const string FIELD_ACCOUNTID = "AccountId"; + public const string FIELD_BOARDID = "BoardId"; + public const string FIELD_ISACTIVE = "IsActive"; + public static readonly TableSpec instance = new TableSpec(); + public string name { get { return TABLE; } } + public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { + Refresh(id); + var moderator = Moderator.LoadById(id); + byAccount_Recalculate(moderator.accountId); + byBoard_Recalculate(moderator.boardId); + lock(isModerator_cache) { + if(!isModerator_cache.ContainsKey(moderator.accountId)) isModerator_cache[moderator.accountId] = new Dictionary(); + isModerator_cache[moderator.accountId][moderator.boardId] = moderator.isActive; + } + } + } + + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } + + private int _accountId; + public int accountId { + get { + this.LoadIfNotLoaded(); + return this._accountId; + } + } + public Account account { + get { + return Account.LoadById(this.accountId); + } + } + + private int _boardId; + public int boardId { + get { + this.LoadIfNotLoaded(); + return this._boardId; + } + } + public Board board { + get { + return Board.LoadById(this.boardId); + } + } + + private bool _isActive; + public bool isActive { + get { + this.LoadIfNotLoaded(); + return this._isActive; + } + } + + protected override void doFromHash(Dictionary data) { + this._accountId = int.Parse(data[TableSpec.FIELD_ACCOUNTID]); + this._boardId = int.Parse(data[TableSpec.FIELD_BOARDID]); + this._isActive = Util.string2bool(data[TableSpec.FIELD_ISACTIVE]); + } + + private static readonly Dictionary> isModerator_cache = new Dictionary>(); + public static bool isModerator(Account account, Board board) { + //slight optimisation... + UserGroup group = account.user.userGroup; + if(group.name != UserGroup.NAME_ADMINISTRATORS && group.name != UserGroup.NAME_MODERATORS) return false; + + if(!isModerator_cache.ContainsKey(account.id) || !isModerator_cache[account.id].ContainsKey(board.id)) { + lock(isModerator_cache) { + if(!isModerator_cache.ContainsKey(account.id) || !isModerator_cache[account.id].ContainsKey(board.id)) { + if(!isModerator_cache.ContainsKey(account.id)) isModerator_cache[account.id] = new Dictionary(); + + List ids = Config.instance.mainConnection.LoadIdsByConditions( + TableSpec.instance, + new ComplexCondition( + ConditionsJoinType.AND, + new ComparisonCondition( + TableSpec.instance.getColumnSpec(TableSpec.FIELD_ACCOUNTID), + ComparisonType.EQUAL, + account.id.ToString() + ), + new ComparisonCondition( + TableSpec.instance.getColumnSpec(TableSpec.FIELD_BOARDID), + ComparisonType.EQUAL, + board.id.ToString() + ) + ), + Diapasone.unlimited + ); + if(ids.Count < 1) { + isModerator_cache[account.id][board.id] = false; + } else { + isModerator_cache[account.id][board.id] = Moderator.LoadById(int.Parse(ids.Single())).isActive; + } + + } + } + } + return isModerator_cache[account.id][board.id]; + } + public static bool isModerator(User user, Board board) { + Account account; + try { + account = Account.LoadByUser(user); + } catch(NotFoundInDBException) { + return false; + } + return isModerator(account, board); + } + + private static readonly Dictionary> byBoard_cache = new Dictionary>(); + private static void byBoard_Recalculate(int boardId) { + lock(byBoard_cache) { + byBoard_cache[boardId] = + from stringId in Config.instance.mainConnection.LoadIdsByConditions( + TableSpec.instance, + new ComparisonCondition( + TableSpec.instance.getColumnSpec(TableSpec.FIELD_BOARDID), + ComparisonType.EQUAL, + boardId.ToString() + ), + Diapasone.unlimited + ) + select Moderator.LoadById(int.Parse(stringId)).accountId; + } + } + public static IEnumerable GetModerators(Board board) { + if(!byBoard_cache.ContainsKey(board.id)) { + byBoard_Recalculate(board.id); + } + return from id in byBoard_cache[board.id] select Account.LoadById(id); + } + + private static readonly Dictionary> byAccount_cache = new Dictionary>(); + private static void byAccount_Recalculate(int accountId) { + lock(byAccount_cache) { + byAccount_cache[accountId] = + from stringId in Config.instance.mainConnection.LoadIdsByConditions( + TableSpec.instance, + new ComparisonCondition( + TableSpec.instance.getColumnSpec(TableSpec.FIELD_ACCOUNTID), + ComparisonType.EQUAL, + accountId.ToString() + ), + Diapasone.unlimited + ) + select Moderator.LoadById(int.Parse(stringId)).boardId; + } + } + public static IEnumerable GetModeratedBoards(Account account) { + if(!byAccount_cache.ContainsKey(account.id)) { + byAccount_Recalculate(account.id); + } + return from id in byAccount_cache[account.id] select Board.LoadById(id); + } + + } +} diff --git a/Common/dataobjects/Post.cs b/Common/dataobjects/Post.cs index dc7c026..e1e3055 100644 --- a/Common/dataobjects/Post.cs +++ b/Common/dataobjects/Post.cs @@ -24,6 +24,7 @@ namespace FLocal.Common.dataobjects { public const string FIELD_BODY = "Body"; public const string FIELD_THREADID = "ThreadId"; public const string FIELD_PARENTPOSTID = "ParentPostId"; + public const string FIELD_TOTALPUNISHMENTS = "TotalPunishments"; public static readonly TableSpec instance = new TableSpec(); public string name { get { return TABLE; } } public string idName { get { return FIELD_ID; } } @@ -155,6 +156,43 @@ namespace FLocal.Common.dataobjects { } } + private int _totalPunishments; + public int totalPunishments { + get { + this.LoadIfNotLoaded(); + return this._totalPunishments; + } + } + + private readonly object punishments_Locker = new object(); + public IEnumerable punishments { + get { + return + from id in Cache>.instance.get( + this.punishments_Locker, + () => { + IEnumerable ids = (from stringId in Config.instance.mainConnection.LoadIdsByConditions( + Punishment.TableSpec.instance, + new ComparisonCondition( + Punishment.TableSpec.instance.getColumnSpec(Punishment.TableSpec.FIELD_POSTID), + ComparisonType.EQUAL, + this.id.ToString() + ), + Diapasone.unlimited + ) select int.Parse(stringId)).ToList(); + Punishment.LoadByIds(ids); + return ids; + } + ) + let punishment = Punishment.LoadById(id) + orderby punishment.id + select punishment; + } + } + internal void punishments_Reset() { + Cache>.instance.delete(this.punishments_Locker); + } + protected override void doFromHash(Dictionary data) { this._posterId = int.Parse(data[TableSpec.FIELD_POSTERID]); this._postDate = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_POSTDATE]).Value; @@ -165,6 +203,7 @@ namespace FLocal.Common.dataobjects { this._body = data[TableSpec.FIELD_BODY]; this._threadId = int.Parse(data[TableSpec.FIELD_THREADID]); this._parentPostId = Util.ParseInt(data[TableSpec.FIELD_PARENTPOSTID]); + this._totalPunishments = Util.ParseInt(data[TableSpec.FIELD_TOTALPUNISHMENTS]).GetValueOrDefault(0); } public XElement exportToXmlSimpleWithParent(UserContext context) { @@ -179,7 +218,8 @@ namespace FLocal.Common.dataobjects { return new XElement("post", new XElement("id", this.id), new XElement("poster", this.poster.exportToXmlForViewing(context)), - new XElement("bodyShort", context.isPostVisible(this) ? this.bodyShort : "") + new XElement("bodyShort", context.isPostVisible(this) ? this.bodyShort : ""), + new XElement("title", this.title) ); } @@ -193,7 +233,12 @@ namespace FLocal.Common.dataobjects { XElement result = new XElement("post", new XElement("id", this.id), - new XElement("poster", this.poster.exportToXmlForViewing(context)), + new XElement("poster", + this.poster.exportToXmlForViewing( + context, + new XElement("isModerator", Moderator.isModerator(this.poster, this.thread.board).ToPlainString()) + ) + ), new XElement("postDate", this.postDate.ToXml()), new XElement("layerId", this.layerId), new XElement("layerName", this.layer.name), @@ -202,6 +247,7 @@ namespace FLocal.Common.dataobjects { //this.XMLBody(context), new XElement("bodyShort", this.bodyShort), new XElement("threadId", this.threadId), + new XElement("isPunishmentEnabled", ((context.account != null) && Moderator.isModerator(context.account, this.thread.board)).ToPlainString()), new XElement("isOwner", ((context.account != null) && (this.poster.id == context.account.user.id)).ToPlainString()), new XElement( "specific", @@ -212,6 +258,9 @@ namespace FLocal.Common.dataobjects { ) ) ); + if(this.totalPunishments > 0) { + result.Add(from punishment in punishments select new XElement("specific", punishment.exportToXml(context))); + } if(this.parentPostId.HasValue) { result.Add(new XElement("parentPost", this.parentPost.exportToXmlBase(context))); } @@ -286,5 +335,51 @@ namespace FLocal.Common.dataobjects { } } + public void Punish(Account account, PunishmentType type, string comment) { + + if(!Moderator.isModerator(account, this.thread.board)) throw new FLocalException(account.id + " is not a moderator in board " + this.thread.board.id); + + if(account.user.id == this.poster.id) throw new FLocalException("You cannot punish your own posts"); + + ChangeSetUtil.ApplyChanges( + new UpdateChange( + TableSpec.instance, + new Dictionary { + { TableSpec.FIELD_TOTALPUNISHMENTS, new IncrementFieldValue() }, + }, + this.id + ), + new InsertChange( + Punishment.TableSpec.instance, + new Dictionary { + { Punishment.TableSpec.FIELD_POSTID, new ScalarFieldValue(this.id.ToString()) }, + { Punishment.TableSpec.FIELD_OWNERID, new ScalarFieldValue(this.poster.id.ToString()) }, + { Punishment.TableSpec.FIELD_ORIGINALBOARDID, new ScalarFieldValue(this.thread.board.id.ToString()) }, + { Punishment.TableSpec.FIELD_MODERATORID, new ScalarFieldValue(account.id.ToString()) }, + { Punishment.TableSpec.FIELD_PUNISHMENTDATE, new ScalarFieldValue(DateTime.Now.ToUTCString()) }, + { Punishment.TableSpec.FIELD_PUNISHMENTTYPE, new ScalarFieldValue(type.id.ToString()) }, + { Punishment.TableSpec.FIELD_ISWITHDRAWED, new ScalarFieldValue("0") }, + { Punishment.TableSpec.FIELD_COMMENT, new ScalarFieldValue(comment) }, + } + ) + ); + + Account posterAccount = null; + try { + posterAccount = Account.LoadByUser(this.poster); + } catch(NotFoundInDBException) { + } + + if(posterAccount != null) { + PMMessage newMessage = PMConversation.SendPMMessage( + account, + posterAccount, + this.title, + type.description + "\r\n" + this.id + ); + newMessage.conversation.markAsRead(account, newMessage, newMessage); + } + } + } } diff --git a/Common/dataobjects/Punishment.cs b/Common/dataobjects/Punishment.cs new file mode 100644 index 0000000..776b377 --- /dev/null +++ b/Common/dataobjects/Punishment.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using FLocal.Core; +using FLocal.Core.DB; +using FLocal.Core.DB.conditions; + +namespace FLocal.Common.dataobjects { + public class Punishment : SqlObject { + + public class TableSpec : ISqlObjectTableSpec { + public const string TABLE = "Punishments"; + public const string FIELD_ID = "Id"; + public const string FIELD_POSTID = "PostId"; + public const string FIELD_OWNERID = "OwnerId"; + public const string FIELD_ORIGINALBOARDID = "OriginalBoardId"; + public const string FIELD_MODERATORID = "ModeratorId"; + public const string FIELD_PUNISHMENTDATE = "PunishmentDate"; + public const string FIELD_PUNISHMENTTYPE = "PunishmentType"; + public const string FIELD_ISWITHDRAWED = "IsWithdrawed"; + public const string FIELD_COMMENT = "Comment"; + public static readonly TableSpec instance = new TableSpec(); + public string name { get { return TABLE; } } + public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } + } + + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } + + private int _postId; + public int postId { + get { + this.LoadIfNotLoaded(); + return this._postId; + } + } + public Post post { + get { + return Post.LoadById(this.postId); + } + } + + private int _ownerId; + public int ownerId { + get { + this.LoadIfNotLoaded(); + return this._ownerId; + } + } + public User owner { + get { + return User.LoadById(this.ownerId); + } + } + + private int _originalBoardId; + public int originalBoardId { + get { + this.LoadIfNotLoaded(); + return this._originalBoardId; + } + } + public Board originalBoard { + get { + return Board.LoadById(this.originalBoardId); + } + } + + private int _moderatorId; + public int moderatorId { + get { + this.LoadIfNotLoaded(); + return this._moderatorId; + } + } + public Account moderator { + get { + return Account.LoadById(this.moderatorId); + } + } + + private DateTime _punishmentDate; + public DateTime punishmentDate { + get { + this.LoadIfNotLoaded(); + return this._punishmentDate; + } + } + + private int _punishmentTypeId; + public int punishmentTypeId { + get { + this.LoadIfNotLoaded(); + return this._punishmentTypeId; + } + } + public PunishmentType punishmentType { + get { + return PunishmentType.LoadById(this.punishmentTypeId); + } + } + + private bool _isWithdrawed; + public bool isWithdrawed { + get { + this.LoadIfNotLoaded(); + return this._isWithdrawed; + } + } + + private string _comment; + public string comment { + get { + this.LoadIfNotLoaded(); + return this._comment; + } + } + + protected override void doFromHash(Dictionary data) { + this._postId = int.Parse(data[TableSpec.FIELD_POSTID]); + this._ownerId = int.Parse(data[TableSpec.FIELD_OWNERID]); + this._originalBoardId = int.Parse(data[TableSpec.FIELD_ORIGINALBOARDID]); + this._moderatorId = int.Parse(data[TableSpec.FIELD_MODERATORID]); + this._punishmentDate = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_PUNISHMENTDATE]).Value; + this._punishmentTypeId = int.Parse(data[TableSpec.FIELD_PUNISHMENTTYPE]); + this._isWithdrawed = Util.string2bool(data[TableSpec.FIELD_ISWITHDRAWED]); + this._comment = data[TableSpec.FIELD_COMMENT]; + } + + public XElement exportToXml(UserContext context) { + return new XElement("punishment", + this.post.exportToXmlBase(context), + new XElement("owner", this.owner.exportToXmlForViewing(context)), + new XElement("originalBoard", this.originalBoard.exportToXmlSimple(context)), + new XElement("moderator", this.moderator.user.exportToXmlForViewing(context)), + new XElement("punishmentDate", this.punishmentDate.ToXml()), + this.punishmentType.exportToXml(context), + new XElement("isWithdrawed", this.isWithdrawed.ToPlainString()), + new XElement("comment", this.comment) + ); + } + + } +} diff --git a/Common/dataobjects/PunishmentType.cs b/Common/dataobjects/PunishmentType.cs new file mode 100644 index 0000000..419cfbb --- /dev/null +++ b/Common/dataobjects/PunishmentType.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using FLocal.Core; +using FLocal.Core.DB; +using FLocal.Core.DB.conditions; + +namespace FLocal.Common.dataobjects { + public class PunishmentType : SqlObject { + + public class TableSpec : ISqlObjectTableSpec { + public const string TABLE = "PunishmentTypes"; + public const string FIELD_ID = "Id"; + public const string FIELD_DESCRIPTION = "Description"; + public const string FIELD_WEIGHT = "Weight"; + public const string FIELD_WEIGHTDESCRIPTION = "WeightDescription"; + public static readonly TableSpec instance = new TableSpec(); + public string name { get { return TABLE; } } + public string idName { get { return FIELD_ID; } } + public void refreshSqlObject(int id) { Refresh(id); } + } + + protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } } + + private string _description; + public string description { + get { + this.LoadIfNotLoaded(); + return this._description; + } + } + + private int _weight; + public int weight { + get { + this.LoadIfNotLoaded(); + return this._weight; + } + } + + private string _weightDescription; + public string weightDescription { + get { + this.LoadIfNotLoaded(); + return this._weightDescription; + } + } + + protected override void doFromHash(Dictionary data) { + this._description = data[TableSpec.FIELD_DESCRIPTION]; + this._weight = int.Parse(data[TableSpec.FIELD_WEIGHT]); + this._weightDescription = data[TableSpec.FIELD_WEIGHTDESCRIPTION]; + } + + public XElement exportToXml(UserContext context) { + return new XElement("punishmentType", + new XElement("id", this.id), + new XElement("description", this.description), + new XElement("weight", this.weight), + new XElement("weightDescription", this.weightDescription) + ); + } + + private static readonly object allTypes_Locker = new object(); + public static IEnumerable allTypes { + get { + return + from id in Cache>.instance.get( + allTypes_Locker, + () => { + IEnumerable ids = (from stringId in Config.instance.mainConnection.LoadIdsByConditions( + TableSpec.instance, + new FLocal.Core.DB.conditions.EmptyCondition(), + Diapasone.unlimited + ) select int.Parse(stringId)).ToList(); + PunishmentType.LoadByIds(ids); + return ids; + } + ) + let type = PunishmentType.LoadById(id) + orderby type.weight + select type; + } + } + internal static void allTypes_Reset() { + Cache>.instance.delete(allTypes_Locker); + } + + } +} diff --git a/Common/dataobjects/Thread.cs b/Common/dataobjects/Thread.cs index ac157ff..52008c9 100644 --- a/Common/dataobjects/Thread.cs +++ b/Common/dataobjects/Thread.cs @@ -396,6 +396,7 @@ namespace FLocal.Common.dataobjects { { Post.TableSpec.FIELD_LAYERID, new ScalarFieldValue(layer.id.ToString()) }, { Post.TableSpec.FIELD_TITLE, new ScalarFieldValue(title) }, { Post.TableSpec.FIELD_BODY, new ScalarFieldValue(bodyIntermediate) }, + { Post.TableSpec.FIELD_TOTALPUNISHMENTS, new ScalarFieldValue("0") }, }; if(forcedPostId.HasValue) { postInsertData[Post.TableSpec.FIELD_ID] = new ScalarFieldValue(forcedPostId.Value.ToString()); diff --git a/Common/dataobjects/UserGroup.cs b/Common/dataobjects/UserGroup.cs index beea4fa..b766a5d 100644 --- a/Common/dataobjects/UserGroup.cs +++ b/Common/dataobjects/UserGroup.cs @@ -10,6 +10,9 @@ using FLocal.Core.DB.conditions; namespace FLocal.Common.dataobjects { public class UserGroup : SqlObject { + public const string NAME_MODERATORS = "Moderators"; + public const string NAME_ADMINISTRATORS = "Administrators"; + public class TableSpec : ISqlObjectTableSpec { public const string TABLE = "UserGroups"; public const string FIELD_ID = "Id"; diff --git a/IISMainHandler/HandlersFactory.cs b/IISMainHandler/HandlersFactory.cs index 9698f2b..345b210 100644 --- a/IISMainHandler/HandlersFactory.cs +++ b/IISMainHandler/HandlersFactory.cs @@ -71,6 +71,8 @@ namespace FLocal.IISHandler { return new handlers.response.ReplyHandler(); case "pmreply": return new handlers.response.PMReplyToPostHandler(); + case "punish": + return new handlers.response.PunishHandler(); default: return new handlers.WrongUrlHandler(); } @@ -175,6 +177,8 @@ namespace FLocal.IISHandler { return new handlers.request.RegisterByInviteHandler(); case "edit": return new handlers.request.EditHandler(); + case "punish": + return new handlers.request.PunishHandler(); case "reply": return new handlers.request.ReplyHandler(); case "newthread": diff --git a/IISMainHandler/IISMainHandler.csproj b/IISMainHandler/IISMainHandler.csproj index f611118..662b9c9 100644 --- a/IISMainHandler/IISMainHandler.csproj +++ b/IISMainHandler/IISMainHandler.csproj @@ -71,6 +71,7 @@ + @@ -98,6 +99,7 @@ + diff --git a/IISMainHandler/handlers/PostHandler.cs b/IISMainHandler/handlers/PostHandler.cs index 04e90ed..86783af 100644 --- a/IISMainHandler/handlers/PostHandler.cs +++ b/IISMainHandler/handlers/PostHandler.cs @@ -29,7 +29,12 @@ namespace FLocal.IISHandler.handlers { XElement[] result = new XElement[] { new XElement("currentLocation", post.exportToXmlSimpleWithParent(context)), post.thread.exportToXml(context), - new XElement("posts", post.exportToXml(context, new XElement("isUnread", (post.id > lastReadId).ToPlainString()))) + new XElement("posts", + post.exportToXml( + context, + new XElement("isUnread", (post.id > lastReadId).ToPlainString()) + ) + ) }; post.thread.incrementViewsCounter(); diff --git a/IISMainHandler/handlers/ThreadHandler.cs b/IISMainHandler/handlers/ThreadHandler.cs index 950ccba..5656424 100644 --- a/IISMainHandler/handlers/ThreadHandler.cs +++ b/IISMainHandler/handlers/ThreadHandler.cs @@ -59,7 +59,10 @@ namespace FLocal.IISHandler.handlers { new XElement("currentLocation", thread.exportToXmlSimpleWithParent(context)), thread.exportToXml(context), new XElement("posts", - from post in posts select post.exportToXml(context, new XElement("isUnread", (post.id > lastReadId).ToPlainString())), + from post in posts select post.exportToXml( + context, + new XElement("isUnread", (post.id > lastReadId).ToPlainString()) + ), pageOuter.exportToXml(2, 5, 2) ) }; diff --git a/IISMainHandler/handlers/request/PunishHandler.cs b/IISMainHandler/handlers/request/PunishHandler.cs new file mode 100644 index 0000000..853fe9f --- /dev/null +++ b/IISMainHandler/handlers/request/PunishHandler.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using FLocal.Common.dataobjects; + +namespace FLocal.IISHandler.handlers.request { + class PunishHandler : AbstractPostHandler { + + protected override string templateName { + get { + return "result/MessagePunished.xslt"; + } + } + + protected override XElement[] Do(WebContext context) { + + Post post = Post.LoadById(int.Parse(context.httprequest.Form["postId"])); + XElement postXml = post.exportToXml(context); + post.Punish( + context.session.account, + PunishmentType.LoadById(int.Parse(context.httprequest.Form["punishmentTypeId"])), + context.httprequest.Form["comment"] + ); + + return new XElement[] { + post.thread.board.exportToXml(context, false), + postXml + }; + } + + } +} diff --git a/IISMainHandler/handlers/response/PunishHandler.cs b/IISMainHandler/handlers/response/PunishHandler.cs new file mode 100644 index 0000000..a121cd3 --- /dev/null +++ b/IISMainHandler/handlers/response/PunishHandler.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Xml.Linq; +using FLocal.Core; +using FLocal.Common; +using FLocal.Common.dataobjects; + +namespace FLocal.IISHandler.handlers.response { + + class PunishHandler : AbstractNewMessageHandler { + + override protected string templateName { + get { + return "PostPunish.xslt"; + } + } + + override protected IEnumerable getSpecificNewMessageData(WebContext context) { + Post post = Post.LoadById(int.Parse(context.requestParts[1])); + + if(!Moderator.isModerator(context.account, post.thread.board)) throw new FLocalException(context.account.id + " is not a moderator in board " + post.thread.board.id); + if(context.account.user.id == post.poster.id) throw new FLocalException("You cannot punish your own posts"); + + return new XElement[] { + post.thread.board.exportToXml(context, false), + post.thread.exportToXml(context), + post.exportToXml(context), + post.latestRevision.exportToXml(context), + new XElement("layers", + from layer in PostLayer.allLayers select layer.exportToXml(context) + ), + new XElement("punishmentTypes", + from punishmentType in PunishmentType.allTypes select punishmentType.exportToXml(context) + ) + }; + } + } + +} \ No newline at end of file diff --git a/static/css/global.css b/static/css/global.css index 16876d5..1803df2 100644 --- a/static/css/global.css +++ b/static/css/global.css @@ -96,6 +96,17 @@ pre background-color:yellow !important; font-weight: bold !important; } +.UG_Moderators { + color:blue !important; + background-color:white !important; +} +.UG_Administrators { + color:black !important; + background-color:white !important; +} p { margin:0em; } +.punishment { + color:red !important; +} diff --git a/static/images/mod.gif b/static/images/mod.gif new file mode 100644 index 0000000000000000000000000000000000000000..a56b77334704c1b204298f9b2e2860385e28c839 GIT binary patch literal 123 zcmZ?wbhEHb zR!;q`g63Og?RT1n@3f8I>6yJVvV3oB_0H7hy@mY;SMLvQz8`&pK1L^gick5RTlA&8 z`b&Aumx|gim35!%np#@-wYKkX>p0Nfb+D`ZU~m87z6pmXO*uAY>anTQkI$HSV&?3V zbLXF4wD{cOrRP_yy0~`T<+bas?A&$hYkT+Cj-IbweP6r#zxGV{+BfO@{6*gvF8#h{ z!}oO?e{9Zry(H;N7D~?;k(@@Z`ydXU{%9d;aO=%g?V~e}4Dw+n+~||2%o} z=gHGQ&z}Ez_3H2Y4<9~!|MKPMzi;1u{`&Lp=g)t?fB*aQ=kMRY|3KhBILJqd!4d+B zKUo+V82&TpfE)zM6AT=082)q0Xat;@qLs{{rLuyJotZ;S%O+!i^0`Befnqld7B62c zXJjPdv(qDmQOq{prt0M4b}uGPuB{>`E*ZAY?$h2@vZd$&&p~c$tG1gHT=-}6>Db&l zVep}+!9un-MH{TDzJdLRcErb`mHq& zH!vQNv1D4u<6`i{vqvKT%a)fbmay^|*h>j~S*Xx^{Jz|29*#u;hZxyUOx8Acc(|ze JIU^&3H2}>CTlfF~ literal 0 HcmV?d00001 diff --git a/templates/Full/PostPunish.xslt b/templates/Full/PostPunish.xslt new file mode 100644 index 0000000..524c5f1 --- /dev/null +++ b/templates/Full/PostPunish.xslt @@ -0,0 +1,98 @@ + + + + + Ìîäåðèðîâàíèå ñîîáùåíèÿ - + + + + + + + +
+ + + + + + + + + + +
+ Ìîäåðèðîâàíèå ñîîáùåíèÿ ( + + ) +
+ Çàïîëíèòå ïðèâåäåííóþ íèæå ôîðìó äëÿ ìîäåðèðîâàíèÿ ñîîáùåíèÿ +
+
+ + + + Òèï:
+ +
+
+ Êîììåíòàðèé: +
+ + + +
+
+ +
+ + + + + +
+ + + + + + + + + + +
+ Îòâåò íà ñîîáùåíèå +
+ + Àâòîð: + +
+ Òåìà: + +
+
+ +
+
+
+ + + + punishmentTypeId_ + + + +
+
+ +
\ No newline at end of file diff --git a/templates/Full/elems/BoardInfo.xslt b/templates/Full/elems/BoardInfo.xslt index beab14f..13e4f3f 100644 --- a/templates/Full/elems/BoardInfo.xslt +++ b/templates/Full/elems/BoardInfo.xslt @@ -47,9 +47,7 @@ - Sash - , - DeadmoroZ + diff --git a/templates/Full/elems/Main.xslt b/templates/Full/elems/Main.xslt index 89d6352..d019be7 100644 --- a/templates/Full/elems/Main.xslt +++ b/templates/Full/elems/Main.xslt @@ -176,6 +176,9 @@ /User// + + + diff --git a/templates/Full/elems/PostInfo.xslt b/templates/Full/elems/PostInfo.xslt index 49e3be1..972185d 100644 --- a/templates/Full/elems/PostInfo.xslt +++ b/templates/Full/elems/PostInfo.xslt @@ -54,6 +54,14 @@ + + + + + + +
+ + + ( + + ). + + ( + + , + + ) +
+
+
+
diff --git a/templates/Full/result/MessagePunished.xslt b/templates/Full/result/MessagePunished.xslt new file mode 100644 index 0000000..7ab95fc --- /dev/null +++ b/templates/Full/result/MessagePunished.xslt @@ -0,0 +1,48 @@ + + + + Ñîîáùåíèå îòìîäåðèðîâàíî + + + + + + + + +
+ + + + +
+ Ìîäåðèðîâàíèå ñîîáùåíèÿ +
+
+ + + + +
+

Ñîîáùåíèå áûëî óñïåøíî îòìîäåðèðîâàíî

+

+ [←] + + /Board// + Âåðíóòüñÿ â ðàçäåë + + | + + /Thread//p + Ïðîñìîòðåòü ñîîáùåíèå + + [→] +

+ +
+
+
+ +
\ No newline at end of file diff --git a/templates/Lite/PostPunish.xslt b/templates/Lite/PostPunish.xslt new file mode 100644 index 0000000..ba5a512 --- /dev/null +++ b/templates/Lite/PostPunish.xslt @@ -0,0 +1,94 @@ + + + + + + Ìîäåðèðîâàíèå ñîîáùåíèÿ - + + + + + + + +
+ + + + + + + +
+ Ìîäåðèðîâàíèå ñîîáùåíèÿ ( + + ) +
+
+ + + + Òèï:
+ +
+
+ Êîììåíòàðèé: +
+ + + +
+
+ +
+ + + + + +
+ + + + + + + + + + +
+ Îòâåò íà ñîîáùåíèå +
+ + Àâòîð: + +
+ Òåìà: + +
+
+ +
+
+
+ + + + punishmentTypeId_ + + + +
+
+ +
\ No newline at end of file diff --git a/templates/Lite/elems/Main.xslt b/templates/Lite/elems/Main.xslt index 65c359e..21eff77 100644 --- a/templates/Lite/elems/Main.xslt +++ b/templates/Lite/elems/Main.xslt @@ -182,6 +182,9 @@ /User// + + ^M + diff --git a/templates/Lite/elems/PostInfo.xslt b/templates/Lite/elems/PostInfo.xslt index 760dfaf..1feb1ff 100644 --- a/templates/Lite/elems/PostInfo.xslt +++ b/templates/Lite/elems/PostInfo.xslt @@ -31,6 +31,13 @@ + + | + + /Post//Punish/ + Mod + + | diff --git a/templates/Lite/result/MessagePunished.xslt b/templates/Lite/result/MessagePunished.xslt new file mode 100644 index 0000000..7ab95fc --- /dev/null +++ b/templates/Lite/result/MessagePunished.xslt @@ -0,0 +1,48 @@ + + + + Ñîîáùåíèå îòìîäåðèðîâàíî + + + + + + + + +
+ + + + +
+ Ìîäåðèðîâàíèå ñîîáùåíèÿ +
+
+ + + + +
+

Ñîîáùåíèå áûëî óñïåøíî îòìîäåðèðîâàíî

+

+ [←] + + /Board// + Âåðíóòüñÿ â ðàçäåë + + | + + /Thread//p + Ïðîñìîòðåòü ñîîáùåíèå + + [→] +

+ +
+
+
+ +
\ No newline at end of file