Moderation implemented

main
Inga 🏳‍🌈 15 years ago
parent 8252fcdbfc
commit 29f54df117
  1. 2
      Builder/IISMainHandler/build.txt
  2. 3
      Common/Common.csproj
  3. 3
      Common/TableManager.cs
  4. 2
      Common/actions/ChangeSet.cs
  5. 11
      Common/dataobjects/Board.cs
  6. 172
      Common/dataobjects/Moderator.cs
  7. 99
      Common/dataobjects/Post.cs
  8. 146
      Common/dataobjects/Punishment.cs
  9. 92
      Common/dataobjects/PunishmentType.cs
  10. 1
      Common/dataobjects/Thread.cs
  11. 3
      Common/dataobjects/UserGroup.cs
  12. 4
      IISMainHandler/HandlersFactory.cs
  13. 2
      IISMainHandler/IISMainHandler.csproj
  14. 7
      IISMainHandler/handlers/PostHandler.cs
  15. 5
      IISMainHandler/handlers/ThreadHandler.cs
  16. 34
      IISMainHandler/handlers/request/PunishHandler.cs
  17. 42
      IISMainHandler/handlers/response/PunishHandler.cs
  18. 11
      static/css/global.css
  19. BIN
      static/images/mod.gif
  20. BIN
      static/images/punish.gif
  21. 98
      templates/Full/PostPunish.xslt
  22. 4
      templates/Full/elems/BoardInfo.xslt
  23. 3
      templates/Full/elems/Main.xslt
  24. 29
      templates/Full/elems/PostInfo.xslt
  25. 48
      templates/Full/result/MessagePunished.xslt
  26. 94
      templates/Lite/PostPunish.xslt
  27. 3
      templates/Lite/elems/Main.xslt
  28. 7
      templates/Lite/elems/PostInfo.xslt
  29. 48
      templates/Lite/result/MessagePunished.xslt

@ -91,11 +91,14 @@
<Compile Include="dataobjects\IUserSettings.cs" />
<Compile Include="dataobjects\AnonymousUserSettings.cs" />
<Compile Include="dataobjects\LocalNetwork.cs" />
<Compile Include="dataobjects\Moderator.cs" />
<Compile Include="dataobjects\PMConversation.cs" />
<Compile Include="dataobjects\PMMessage.cs" />
<Compile Include="dataobjects\Poll.cs" />
<Compile Include="dataobjects\Post.cs" />
<Compile Include="dataobjects\PostLayer.cs" />
<Compile Include="dataobjects\Punishment.cs" />
<Compile Include="dataobjects\PunishmentType.cs" />
<Compile Include="dataobjects\QuickLink.cs" />
<Compile Include="dataobjects\Revision.cs" />
<Compile Include="dataobjects\Session.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,

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

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

@ -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<Moderator> {
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<int,bool>();
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<string, string> 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<int, Dictionary<int, bool>> isModerator_cache = new Dictionary<int,Dictionary<int,bool>>();
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<int,bool>();
List<string> 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<int, IEnumerable<int>> byBoard_cache = new Dictionary<int,IEnumerable<int>>();
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<Account> 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<int, IEnumerable<int>> byAccount_cache = new Dictionary<int,IEnumerable<int>>();
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<Board> 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);
}
}
}

@ -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<Punishment> punishments {
get {
return
from id in Cache<IEnumerable<int>>.instance.get(
this.punishments_Locker,
() => {
IEnumerable<int> 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<IEnumerable<int>>.instance.delete(this.punishments_Locker);
}
protected override void doFromHash(Dictionary<string, string> 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<string,AbstractFieldValue> {
{ TableSpec.FIELD_TOTALPUNISHMENTS, new IncrementFieldValue() },
},
this.id
),
new InsertChange(
Punishment.TableSpec.instance,
new Dictionary<string,AbstractFieldValue> {
{ 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);
}
}
}
}

@ -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<Punishment> {
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<string, string> 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)
);
}
}
}

@ -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<PunishmentType> {
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<string, string> 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<PunishmentType> allTypes {
get {
return
from id in Cache<IEnumerable<int>>.instance.get(
allTypes_Locker,
() => {
IEnumerable<int> 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<IEnumerable<int>>.instance.delete(allTypes_Locker);
}
}
}

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

@ -10,6 +10,9 @@ using FLocal.Core.DB.conditions;
namespace FLocal.Common.dataobjects {
public class UserGroup : SqlObject<UserGroup> {
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";

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

@ -71,6 +71,7 @@
<Compile Include="handlers\request\maintenance\CleanCacheHandler.cs" />
<Compile Include="handlers\request\MarkThreadAsReadHandler.cs" />
<Compile Include="handlers\request\MigrateAccountHandler.cs" />
<Compile Include="handlers\request\PunishHandler.cs" />
<Compile Include="handlers\request\RegisterByInviteHandler.cs" />
<Compile Include="handlers\request\RegisterHandler.cs" />
<Compile Include="handlers\request\ReturnPostHandler.cs" />
@ -98,6 +99,7 @@
<Compile Include="handlers\response\PMReplyToPostHandler.cs" />
<Compile Include="handlers\response\PMSendHandler.cs" />
<Compile Include="handlers\response\PollHandler.cs" />
<Compile Include="handlers\response\PunishHandler.cs" />
<Compile Include="handlers\response\QuickLinkHandler.cs" />
<Compile Include="handlers\response\RedirectGetHandler.cs" />
<Compile Include="handlers\response\RegisterByInviteHandler.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();

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

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

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="Windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:import href="elems\Main.xslt"/>
<xsl:template name="specificTitle">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ - </xsl:text>
<xsl:value-of select="post/title"/>
</xsl:template>
<xsl:template name="specific">
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ (</xsl:text>
<xsl:value-of select="board/name"/>
<xsl:text>)</xsl:text>
</td>
</tr>
<tr class="darktable">
<td>
<xsl:text>Çàïîëíèòå ïðèâåäåííóþ íèæå ôîðìó äëÿ ìîäåðèðîâàíèÿ ñîîáùåíèÿ</xsl:text>
</td>
</tr>
<tr>
<td class="lighttable">
<form method="post" action="/do/Punish/" name="replier">
<input type="hidden" name="postId">
<xsl:attribute name="value"><xsl:value-of select="post/id"/></xsl:attribute>
</input>
<xsl:text>Òèï:</xsl:text><br/>
<xsl:apply-templates select="punishmentTypes/punishmentType"/>
<br/>
<br/>
<xsl:text>Êîììåíòàðèé: </xsl:text>
<br/>
<input type="text" tabindex="1" name="comment" class="formboxes" size="60"/>
<input type="submit" tabindex="3" name="textcont" taborder="2" value="Ïðîäîëæèòü" class="buttons"/>
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br/>
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Îòâåò íà ñîîáùåíèå</xsl:text>
</td>
</tr>
<tr class="darktable">
<td>
<b>
<xsl:text>Àâòîð: </xsl:text>
<xsl:value-of select="post/poster/user/name"/>
<br/>
<xsl:text>Òåìà: </xsl:text>
<xsl:value-of select="post/title"/>
</b>
</td>
</tr>
<tr>
<td class="lighttable">
<xsl:value-of select="post/body" disable-output-escaping="yes"/>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="punishmentType">
<input type="radio" name="punishmentTypeId">
<xsl:attribute name="id">punishmentTypeId_<xsl:value-of select="id"/></xsl:attribute>
<xsl:attribute name="value"><xsl:value-of select="id"/></xsl:attribute>
</input>
<label>
<xsl:attribute name="for">punishmentTypeId_<xsl:value-of select="id"/></xsl:attribute>
<xsl:text> </xsl:text>
<xsl:value-of select="description"/>
<xsl:text>, âåñ íàêàçàíèÿ </xsl:text>
<xsl:value-of select="weight"/>
<xsl:text> (</xsl:text>
<xsl:value-of select="weightDescription"/>
<xsl:text>)</xsl:text>
</label>
<br/>
</xsl:template>
</xsl:stylesheet>

@ -47,9 +47,7 @@
<xsl:apply-templates select="lastPostInfo"/>
</td>
<td width="10%" class="modcolumn" align="center">
<a>Sash</a>
<xsl:text>, </xsl:text>
<a>DeadmoroZ</a>
<xsl:apply-templates select="moderators/user" mode="userLink"/>
</td>
</tr>
</xsl:template>

@ -176,6 +176,9 @@
</xsl:attribute>
<xsl:attribute name="href">/User/<xsl:value-of select="id"/>/</xsl:attribute>
<xsl:value-of select="name"/>
<xsl:if test="isModerator='true'">
<img src="/static/images/mod.gif" border="0"/>
</xsl:if>
</a>
</xsl:template>

@ -54,6 +54,14 @@
<td align="right">
<table class="tablesurround" border="0">
<tr>
<xsl:if test="isPunishmentEnabled='true'">
<td class="navigation">
<a>
<xsl:attribute name="href">/Post/<xsl:value-of select="id"/>/Punish/</xsl:attribute>
<img src="/static/images/punish.gif" border="0" alt="Ìîäåðèðîâàòü ñîîáùåíèå" title="Ìîäåðèðîâàòü ñîîáùåíèå" style="vertical-align: text-bottom" />
</a>
</td>
</xsl:if>
<td class="navigation">
<a>
<xsl:if test="$isReplyDisabled='false'">
@ -158,6 +166,27 @@
</xsl:if>
</xsl:template>
<xsl:template match="specific/punishment">
<tr>
<td>
<font size="-2" class="punishment">
<xsl:value-of select="punishmentType/description"/>
<xsl:text> (</xsl:text>
<xsl:value-of select="punishmentType/weightDescription"/>
<xsl:text>). </xsl:text>
<xsl:value-of select="comment"/>
<xsl:text> (</xsl:text>
<xsl:apply-templates select="moderator/user" mode="userLink"/>
<xsl:text>, </xsl:text>
<xsl:apply-templates select="punishmentDate/date" mode="dateTime"/>
<xsl:text>)</xsl:text>
<br/>
<br/>
</font>
</td>
</tr>
</xsl:template>
<xsl:template match="specific/thread">
<tr>
<td>

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="Windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:import href="..\elems\Main.xslt"/>
<xsl:template name="specificTitle">Ñîîáùåíèå îòìîäåðèðîâàíî</xsl:template>
<xsl:template name="specific">
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ</xsl:text>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="lighttable">
<p>Ñîîáùåíèå áûëî óñïåøíî îòìîäåðèðîâàíî</p>
<p align="center">
<xsl:text>[&#8592;] </xsl:text>
<a id="actionLink_left">
<xsl:attribute name="href">/Board/<xsl:value-of select="board/id"/>/</xsl:attribute>
<xsl:text>Âåðíóòüñÿ â ðàçäåë</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a id="actionLink_right">
<xsl:attribute name="href">/Thread/<xsl:value-of select="post/threadId"/>/p<xsl:value-of select="post/id"/></xsl:attribute>
<xsl:text>Ïðîñìîòðåòü ñîîáùåíèå</xsl:text>
</a>
<xsl:text> [&#8594;]</xsl:text>
</p>
<script type="text/javascript" language="Javascript">
<xsl:text>assignArrowsHandlers();</xsl:text>
</script>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="Windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:import href="elems\Main.xslt"/>
<xsl:import href="elems\TextEditor.xslt"/>
<xsl:template name="specificTitle">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ - </xsl:text>
<xsl:value-of select="post/title"/>
</xsl:template>
<xsl:template name="specific">
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ (</xsl:text>
<xsl:value-of select="board/name"/>
<xsl:text>)</xsl:text>
</td>
</tr>
<tr>
<td class="lighttable">
<form method="post" action="/do/Punish/" name="replier">
<input type="hidden" name="postId">
<xsl:attribute name="value"><xsl:value-of select="post/id"/></xsl:attribute>
</input>
<xsl:text>Òèï:</xsl:text><br/>
<xsl:apply-templates select="punishmentTypes/punishmentType"/>
<br/>
<br/>
<xsl:text>Êîììåíòàðèé: </xsl:text>
<br/>
<input type="text" tabindex="1" name="comment" class="formboxes" size="60"/>
<input type="submit" tabindex="3" name="textcont" taborder="2" value="Ïðîäîëæèòü" class="buttons"/>
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br/>
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Îòâåò íà ñîîáùåíèå</xsl:text>
</td>
</tr>
<tr class="darktable">
<td>
<b>
<xsl:text>Àâòîð: </xsl:text>
<xsl:value-of select="post/poster/user/name"/>
<br/>
<xsl:text>Òåìà: </xsl:text>
<xsl:value-of select="post/title"/>
</b>
</td>
</tr>
<tr>
<td class="lighttable">
<xsl:value-of select="post/body" disable-output-escaping="yes"/>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="punishmentType">
<input type="radio" name="punishmentTypeId">
<xsl:attribute name="id">punishmentTypeId_<xsl:value-of select="id"/></xsl:attribute>
<xsl:attribute name="value"><xsl:value-of select="id"/></xsl:attribute>
</input>
<label>
<xsl:attribute name="for">punishmentTypeId_<xsl:value-of select="id"/></xsl:attribute>
<xsl:text> </xsl:text>
<xsl:value-of select="description"/>
<xsl:text>, âåñ íàêàçàíèÿ </xsl:text>
<xsl:value-of select="weight"/>
<xsl:text> (</xsl:text>
<xsl:value-of select="weightDescription"/>
<xsl:text>)</xsl:text>
</label>
<br/>
</xsl:template>
</xsl:stylesheet>

@ -182,6 +182,9 @@
</xsl:attribute>
<xsl:attribute name="href">/User/<xsl:value-of select="id"/>/</xsl:attribute>
<xsl:value-of select="name"/>
<xsl:if test="isModerator='true'">
<xsl:text>^M</xsl:text>
</xsl:if>
</a>
</xsl:template>

@ -31,6 +31,13 @@
</xsl:if>
<font class="small" style="padding-left:2em"><xsl:apply-templates select="postDate/date" mode="dateTime"/></font>
<span style="padding-left:1em">
<xsl:if test="isPunishmentEnabled='true'">
<xsl:text> | </xsl:text>
<a class="mod">
<xsl:attribute name="href">/Post/<xsl:value-of select="id"/>/Punish/</xsl:attribute>
<xsl:text>Mod</xsl:text>
</a>
</xsl:if>
<xsl:text> | </xsl:text>
<a>
<xsl:if test="$isReplyDisabled='false'">

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="Windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:import href="..\elems\Main.xslt"/>
<xsl:template name="specificTitle">Ñîîáùåíèå îòìîäåðèðîâàíî</xsl:template>
<xsl:template name="specific">
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="tdheader">
<xsl:text>Ìîäåðèðîâàíèå ñîîáùåíèÿ</xsl:text>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="3" cellspacing="1" width="100%" class="tableborders">
<tr>
<td class="lighttable">
<p>Ñîîáùåíèå áûëî óñïåøíî îòìîäåðèðîâàíî</p>
<p align="center">
<xsl:text>[&#8592;] </xsl:text>
<a id="actionLink_left">
<xsl:attribute name="href">/Board/<xsl:value-of select="board/id"/>/</xsl:attribute>
<xsl:text>Âåðíóòüñÿ â ðàçäåë</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a id="actionLink_right">
<xsl:attribute name="href">/Thread/<xsl:value-of select="post/threadId"/>/p<xsl:value-of select="post/id"/></xsl:attribute>
<xsl:text>Ïðîñìîòðåòü ñîîáùåíèå</xsl:text>
</a>
<xsl:text> [&#8594;]</xsl:text>
</p>
<script type="text/javascript" language="Javascript">
<xsl:text>assignArrowsHandlers();</xsl:text>
</script>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
Loading…
Cancel
Save