diff --git a/Builder/IISMainHandler/build.txt b/Builder/IISMainHandler/build.txt
index 0e4cd99..a89dec1 100644
--- a/Builder/IISMainHandler/build.txt
+++ b/Builder/IISMainHandler/build.txt
@@ -1 +1 @@
-1012
\ No newline at end of file
+1034
\ No newline at end of file
diff --git a/Common/Common.csproj b/Common/Common.csproj
index 331fb91..f7812db 100644
--- a/Common/Common.csproj
+++ b/Common/Common.csproj
@@ -100,6 +100,7 @@
+
diff --git a/Common/TableManager.cs b/Common/TableManager.cs
index 66a5cfb..523f437 100644
--- a/Common/TableManager.cs
+++ b/Common/TableManager.cs
@@ -18,11 +18,12 @@ namespace FLocal.Common {
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,
+ dataobjects.Punishment.TableSpec.instance,
+ dataobjects.PunishmentTransfer.TableSpec.instance,
+ dataobjects.PunishmentType.TableSpec.instance,
dataobjects.QuickLink.TableSpec.instance,
dataobjects.Revision.TableSpec.instance,
dataobjects.Session.TableSpec.instance,
diff --git a/Common/actions/ChangeSet.cs b/Common/actions/ChangeSet.cs
index ac2878a..9d8531d 100644
--- a/Common/actions/ChangeSet.cs
+++ b/Common/actions/ChangeSet.cs
@@ -36,6 +36,7 @@ namespace FLocal.Common.actions {
dataobjects.Invite.TableSpec.TABLE,
dataobjects.Moderator.TableSpec.TABLE,
dataobjects.Punishment.TableSpec.TABLE,
+ dataobjects.PunishmentTransfer.TableSpec.TABLE,
dataobjects.Session.TableSpec.TABLE,
}
);
diff --git a/Common/actions/IncrementFieldValue.cs b/Common/actions/IncrementFieldValue.cs
index d1bffca..f7d8be2 100644
--- a/Common/actions/IncrementFieldValue.cs
+++ b/Common/actions/IncrementFieldValue.cs
@@ -6,8 +6,21 @@ using System.Text;
namespace FLocal.Common.actions {
class IncrementFieldValue : AbstractFieldValue {
- public static readonly Func INCREMENTOR = s => (int.Parse(s)+1).ToString();
- public static readonly Func DECREMENTOR = s => (int.Parse(s)-1).ToString();
+ public static Func INCREMENTOR_CUSTOM(int i) {
+ return s => (int.Parse(s)+i).ToString();
+ }
+
+ public static Func DECREMENTOR_CUSTOM(int i) {
+ return s => (int.Parse(s)-i).ToString();
+ }
+
+ public static string INCREMENTOR(string s) {
+ return INCREMENTOR_CUSTOM(1)(s);
+ }
+
+ public static string DECREMENTOR(string s) {
+ return DECREMENTOR_CUSTOM(1)(s);
+ }
public static Func GREATEST(int val) {
return s => {
diff --git a/Common/dataobjects/Board.cs b/Common/dataobjects/Board.cs
index b27e2b9..2fb89c4 100644
--- a/Common/dataobjects/Board.cs
+++ b/Common/dataobjects/Board.cs
@@ -11,6 +11,13 @@ using FLocal.Common.actions;
namespace FLocal.Common.dataobjects {
public class Board : SqlObject {
+ [Flags]
+ public enum SubboardsOptions {
+ None = 0x0,
+ FirstLevel = 0x1,
+ AllLevels = 0x3
+ }
+
public class TableSpec : IComplexSqlObjectTableSpec {
public const string TABLE = "Boards";
public const string FIELD_ID = "Id";
@@ -209,7 +216,7 @@ namespace FLocal.Common.dataobjects {
);
}
- public XElement exportToXml(UserContext context, bool includeSubBoards, params XElement[] additional) {
+ public XElement exportToXml(UserContext context, Board.SubboardsOptions subboardsOptions, params XElement[] additional) {
XElement result = new XElement("board",
new XElement("id", this.id),
new XElement("sortOrder", this.sortOrder),
@@ -226,9 +233,9 @@ namespace FLocal.Common.dataobjects {
result.Add(new XElement("hasNewPosts", this.hasNewPosts(context.account).ToPlainString()));
}
- if(includeSubBoards) {
+ if((subboardsOptions & SubboardsOptions.FirstLevel) == SubboardsOptions.FirstLevel) {
result.Add(new XElement("subBoards",
- from board in this.subBoards select board.exportToXml(context, false)
+ from board in this.subBoards select board.exportToXml(context, (subboardsOptions == SubboardsOptions.AllLevels) ? SubboardsOptions.AllLevels : SubboardsOptions.None)
));
}
@@ -382,5 +389,23 @@ namespace FLocal.Common.dataobjects {
return Thread.LoadById(threadInsert.getId().Value);
}
+ public readonly object locker = new object();
+
+ public void Synchronized(Action action) {
+ lock(this.locker) {
+ if(this.parentBoardId.HasValue) {
+ this.parentBoard.Synchronized(action);
+ } else {
+ action();
+ }
+ }
+ }
+
+ public IEnumerable boardAndParents {
+ get {
+ return this.ToSequence(board => board.parentBoardId.HasValue ? new Board[] { board.parentBoard } : new Board[0]);
+ }
+ }
+
}
}
diff --git a/Common/dataobjects/Category.cs b/Common/dataobjects/Category.cs
index 181313c..93a4d7c 100644
--- a/Common/dataobjects/Category.cs
+++ b/Common/dataobjects/Category.cs
@@ -110,12 +110,12 @@ namespace FLocal.Common.dataobjects {
);
}
- public XElement exportToXmlForMainPage(UserContext context) {
+ public XElement exportToXmlForMainPage(UserContext context, Board.SubboardsOptions subboardsOptions) {
return new XElement("category",
new XElement("id", this.id),
new XElement("name", this.name),
new XElement("sortOrder", this.sortOrder),
- new XElement("boards", from board in this.subBoards select board.exportToXml(context, true))
+ new XElement("boards", from board in this.subBoards select board.exportToXml(context, subboardsOptions))
);
}
diff --git a/Common/dataobjects/Post.cs b/Common/dataobjects/Post.cs
index 10ed61b..12d1889 100644
--- a/Common/dataobjects/Post.cs
+++ b/Common/dataobjects/Post.cs
@@ -281,10 +281,15 @@ namespace FLocal.Common.dataobjects {
PostLayer actualLayer = poster.getActualLayer(this.thread.board, desiredLayer);
- var changes = Thread.getNewPostChanges(this.thread.board, this.threadId, this, poster, actualLayer, title, body, date, forcedPostId);
- ChangeSetUtil.ApplyChanges(changes.Value.ToArray());
-
- return Post.LoadById(changes.Key.getId().Value);
+ Post newPost;
+ lock(this.thread.locker) {
+
+ var changes = Thread.getNewPostChanges(this.thread.board, this.threadId, this, poster, actualLayer, title, body, date, forcedPostId);
+ ChangeSetUtil.ApplyChanges(changes.Value.ToArray());
+
+ newPost = Post.LoadById(changes.Key.getId().Value);
+ }
+ return newPost;
}
private readonly object Edit_locker = new object(); //TODO: move locking to DB
@@ -335,8 +340,24 @@ namespace FLocal.Common.dataobjects {
}
}
+ private IEnumerable subPosts {
+ get {
+ return Post.LoadByIds(
+ from stringId in Config.instance.mainConnection.LoadIdsByConditions(
+ TableSpec.instance,
+ new ComparisonCondition(
+ TableSpec.instance.getColumnSpec(TableSpec.FIELD_PARENTPOSTID),
+ ComparisonType.EQUAL,
+ this.id.ToString()
+ ),
+ Diapasone.unlimited
+ ) select int.Parse(stringId)
+ );
+ }
+ }
+
private readonly object Punish_Locker = new object();
- public void Punish(Account account, PunishmentType type, string comment) {
+ public void Punish(Account account, PunishmentType type, string comment, PunishmentTransfer.NewTransferInfo? transferInfo) {
if(!Moderator.isModerator(account, this.thread.board)) throw new FLocalException(account.id + " is not a moderator in board " + this.thread.board.id);
@@ -344,62 +365,205 @@ namespace FLocal.Common.dataobjects {
lock(this.Punish_Locker) {
- List changes = (
- from punishment in this.punishments
- select (AbstractChange)new UpdateChange(
- Punishment.TableSpec.instance,
- new Dictionary {
- { Punishment.TableSpec.FIELD_ISWITHDRAWED, new ScalarFieldValue("1") },
- },
- punishment.id
- )
- ).ToList();
+ lock(this.thread.locker) {
- changes.Add(
- new UpdateChange(
- TableSpec.instance,
- new Dictionary {
- { TableSpec.FIELD_TOTALPUNISHMENTS, new IncrementFieldValue() },
- },
- this.id
- )
- );
+ IEnumerable changes = (
+ from punishment in this.punishments
+ select (AbstractChange)new UpdateChange(
+ Punishment.TableSpec.instance,
+ new Dictionary {
+ { Punishment.TableSpec.FIELD_ISWITHDRAWED, new ScalarFieldValue("1") },
+ },
+ punishment.id
+ )
+ );
- changes.Add(
- 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) },
- { Punishment.TableSpec.FIELD_EXPIRES, new ScalarFieldValue(DateTime.Now.Add(type.timeSpan).ToUTCString()) },
- }
- )
- );
+ InsertChange transferInsert = null;
+
+
+ if(transferInfo.HasValue) {
+
+ var _transferInfo = transferInfo.Value;
+
+ Post lastAffectedPost;
+ int totalAffectedPosts;
+
+ if(!this.parentPostId.HasValue) {
+ if(!_transferInfo.isSubthreadTransfer) {
+ throw new FLocalException("You cannot move the first post in thread");
+ } else {
+ lastAffectedPost = this.thread.lastPost;
+ totalAffectedPosts = this.thread.totalPosts;
+ changes = changes.Union(
+ new UpdateChange(
+ Thread.TableSpec.instance,
+ new Dictionary {
+ { Thread.TableSpec.FIELD_BOARDID, new ScalarFieldValue(_transferInfo.newBoardId.ToString()) },
+ },
+ this.thread.id
+ )
+ );
+ }
+ } else {
+
+ List postsAffected;
+ if(_transferInfo.isSubthreadTransfer) {
+ postsAffected = this.ToSequence(post => post.subPosts).OrderBy(post => post.id).ToList();
+ } else {
+ postsAffected = new List();
+ postsAffected.Add(this);
+ }
+
+ lastAffectedPost = postsAffected.Last();
+ totalAffectedPosts = postsAffected.Count;
+
+ InsertChange threadCreate = new InsertChange(
+ Thread.TableSpec.instance,
+ new Dictionary {
+ { Thread.TableSpec.FIELD_BOARDID, new ScalarFieldValue(_transferInfo.newBoardId.ToString()) },
+ { Thread.TableSpec.FIELD_FIRSTPOSTID, new ScalarFieldValue(this.id.ToString()) },
+ { Thread.TableSpec.FIELD_ISANNOUNCEMENT, new ScalarFieldValue("0") },
+ { Thread.TableSpec.FIELD_ISLOCKED, new ScalarFieldValue("0") },
+ { Thread.TableSpec.FIELD_LASTPOSTDATE, new ScalarFieldValue(lastAffectedPost.postDate.ToUTCString()) },
+ { Thread.TableSpec.FIELD_LASTPOSTID, new ScalarFieldValue(lastAffectedPost.id.ToString()) },
+ { Thread.TableSpec.FIELD_TITLE, new ScalarFieldValue(this.title) },
+ { Thread.TableSpec.FIELD_TOPICSTARTERID, new ScalarFieldValue(this.posterId.ToString()) },
+ { Thread.TableSpec.FIELD_TOTALPOSTS, new ScalarFieldValue(totalAffectedPosts.ToString()) },
+ { Thread.TableSpec.FIELD_TOTALVIEWS, new ScalarFieldValue("0") },
+ }
+ );
+ changes = changes.Union(threadCreate);
+
+ changes = changes.Union(
+ from post in postsAffected
+ select (AbstractChange)new UpdateChange(
+ TableSpec.instance,
+ new Dictionary {
+ { TableSpec.FIELD_THREADID, new ReferenceFieldValue(threadCreate) },
+ },
+ post.id
+ )
+ );
+
+ if(!_transferInfo.isSubthreadTransfer) {
+ changes = changes.Union(
+ from post in this.subPosts
+ select (AbstractChange)new UpdateChange(
+ TableSpec.instance,
+ new Dictionary {
+ { TableSpec.FIELD_PARENTPOSTID, new ScalarFieldValue(this.parentPostId.ToString()) },
+ },
+ post.id
+ )
+ );
+ }
- ChangeSetUtil.ApplyChanges(changes.ToArray());
+ }
- this.punishments_Reset();
+ changes = changes.Union(
+ from board in this.thread.board.boardAndParents
+ select (AbstractChange)new UpdateChange(
+ Board.TableSpec.instance,
+ new Dictionary {
+ { Board.TableSpec.FIELD_TOTALPOSTS, new IncrementFieldValue(IncrementFieldValue.DECREMENTOR_CUSTOM(totalAffectedPosts)) },
+ { Board.TableSpec.FIELD_TOTALTHREADS, new IncrementFieldValue(IncrementFieldValue.DECREMENTOR_CUSTOM(this.parentPostId.HasValue ? 0 : 1)) },
+ },
+ board.id
+ )
+ );
+
+ changes = changes.Union(
+ from board in _transferInfo.newBoard.boardAndParents
+ select (AbstractChange)new UpdateChange(
+ Board.TableSpec.instance,
+ new Dictionary {
+ { Board.TableSpec.FIELD_TOTALPOSTS, new IncrementFieldValue(IncrementFieldValue.INCREMENTOR_CUSTOM(totalAffectedPosts)) },
+ { Board.TableSpec.FIELD_TOTALTHREADS, new IncrementFieldValue() },
+ { Board.TableSpec.FIELD_LASTPOSTID, new IncrementFieldValue(IncrementFieldValue.GREATEST(lastAffectedPost.id)) },
+ },
+ board.id
+ )
+ );
+
+ transferInsert = new InsertChange(
+ PunishmentTransfer.TableSpec.instance,
+ new Dictionary {
+ { PunishmentTransfer.TableSpec.FIELD_OLDBOARDID, new ScalarFieldValue(this.thread.boardId.ToString()) },
+ { PunishmentTransfer.TableSpec.FIELD_NEWBOARDID, new ScalarFieldValue(_transferInfo.newBoardId.ToString()) },
+ { PunishmentTransfer.TableSpec.FIELD_ISSUBTHREADTRANSFER, new ScalarFieldValue(_transferInfo.isSubthreadTransfer.ToDBString()) },
+ { PunishmentTransfer.TableSpec.FIELD_OLDPARENTPOSTID, new ScalarFieldValue(this.parentPostId.HasValue ? this.parentPostId.ToString() : null) },
+ }
+ );
+ changes = changes.Union(transferInsert);
+
+ changes = changes.Union(
+ new UpdateChange(
+ TableSpec.instance,
+ new Dictionary {
+ { TableSpec.FIELD_PARENTPOSTID, new ScalarFieldValue(null) },
+ },
+ this.id
+ )
+ );
+
+ if(this.parentPostId.HasValue) {
+ changes = changes.Union(
+ new UpdateChange(
+ Thread.TableSpec.instance,
+ new Dictionary {
+ { Thread.TableSpec.FIELD_TOTALPOSTS, new IncrementFieldValue(IncrementFieldValue.DECREMENTOR_CUSTOM(totalAffectedPosts)) },
+ },
+ this.threadId
+ )
+ );
+ }
+ }
- Account posterAccount = null;
- try {
- posterAccount = Account.LoadByUser(this.poster);
- } catch(NotFoundInDBException) {
- }
-
- if(posterAccount != null) {
- PMMessage newMessage = PMConversation.SendPMMessage(
- account,
- posterAccount,
- this.title,
- String.Format("{0}\r\n[post]{2}[/post]\r\n{1}", type.description, comment, this.id)
+ changes = changes.Union(
+ 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) },
+ { Punishment.TableSpec.FIELD_EXPIRES, new ScalarFieldValue(DateTime.Now.Add(type.timeSpan).ToUTCString()) },
+ { Punishment.TableSpec.FIELD_TRANSFERID, (transferInsert != null) ? (AbstractFieldValue)new ReferenceFieldValue(transferInsert) : (AbstractFieldValue)new ScalarFieldValue(null) },
+ }
+ )
);
- newMessage.conversation.markAsRead(account, newMessage, newMessage);
+
+ ChangeSetUtil.ApplyChanges(changes.ToArray());
+
+ this.punishments_Reset();
+
+ Account posterAccount = null;
+ try {
+ posterAccount = Account.LoadByUser(this.poster);
+ } catch(NotFoundInDBException) {
+ }
+
+ if(posterAccount != null) {
+ PMMessage newMessage = PMConversation.SendPMMessage(
+ account,
+ posterAccount,
+ this.title,
+ String.Format("{0}\r\n[post]{2}[/post]\r\n{1}", type.description, comment, this.id)
+ );
+ newMessage.conversation.markAsRead(account, newMessage, newMessage);
+ }
+
}
}
}
diff --git a/Common/dataobjects/Punishment.cs b/Common/dataobjects/Punishment.cs
index 28c06a0..9d57b24 100644
--- a/Common/dataobjects/Punishment.cs
+++ b/Common/dataobjects/Punishment.cs
@@ -22,6 +22,7 @@ namespace FLocal.Common.dataobjects {
public const string FIELD_ISWITHDRAWED = "IsWithdrawed";
public const string FIELD_COMMENT = "Comment";
public const string FIELD_EXPIRES = "Expires";
+ public const string FIELD_TRANSFERID = "TransferId";
public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } }
@@ -127,6 +128,19 @@ namespace FLocal.Common.dataobjects {
}
}
+ private int? _transferId;
+ public int? transferId {
+ get {
+ this.LoadIfNotLoaded();
+ return this._transferId;
+ }
+ }
+ public PunishmentTransfer transfer {
+ get {
+ return PunishmentTransfer.LoadById(this.transferId.Value);
+ }
+ }
+
protected override void doFromHash(Dictionary data) {
this._postId = int.Parse(data[TableSpec.FIELD_POSTID]);
this._ownerId = int.Parse(data[TableSpec.FIELD_OWNERID]);
@@ -137,6 +151,7 @@ namespace FLocal.Common.dataobjects {
this._isWithdrawed = Util.string2bool(data[TableSpec.FIELD_ISWITHDRAWED]);
this._comment = data[TableSpec.FIELD_COMMENT];
this._expires = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_EXPIRES]).Value;
+ this._transferId = Util.ParseInt(data[TableSpec.FIELD_TRANSFERID]);
}
public XElement exportToXml(UserContext context) {
@@ -149,7 +164,8 @@ namespace FLocal.Common.dataobjects {
this.punishmentType.exportToXml(context),
new XElement("isWithdrawed", this.isWithdrawed.ToPlainString()),
new XElement("comment", this.comment),
- new XElement("expires", this.expires)
+ new XElement("expires", this.expires),
+ this.transferId.HasValue ? this.transfer.exportToXml(context) : null
);
}
diff --git a/Common/dataobjects/PunishmentTransfer.cs b/Common/dataobjects/PunishmentTransfer.cs
new file mode 100644
index 0000000..397296c
--- /dev/null
+++ b/Common/dataobjects/PunishmentTransfer.cs
@@ -0,0 +1,111 @@
+п»ї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 PunishmentTransfer : SqlObject {
+
+ public struct NewTransferInfo {
+
+ public readonly int newBoardId;
+ public Board newBoard {
+ get {
+ return Board.LoadById(this.newBoardId);
+ }
+ }
+
+ public readonly bool isSubthreadTransfer;
+
+ public NewTransferInfo(Board newBoard, bool isSubthreadTransfer) {
+ this.newBoardId = newBoard.id;
+ this.isSubthreadTransfer = isSubthreadTransfer;
+ }
+
+ }
+
+ public class TableSpec : ISqlObjectTableSpec {
+ public const string TABLE = "PunishmentTransfers";
+ public const string FIELD_ID = "Id";
+ public const string FIELD_OLDBOARDID = "OldBoardId";
+ public const string FIELD_OLDPARENTPOSTID = "OldParentPostId";
+ public const string FIELD_NEWBOARDID = "NewBoardId";
+ public const string FIELD_ISSUBTHREADTRANSFER = "IsSubthreadMove";
+ 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 _oldBoardId;
+ public int oldBoardId {
+ get {
+ this.LoadIfNotLoaded();
+ return this._oldBoardId;
+ }
+ }
+ public Board oldBoard {
+ get {
+ return Board.LoadById(this.oldBoardId);
+ }
+ }
+
+ private int? _oldParentPostId;
+ public int? oldParentPostId {
+ get {
+ this.LoadIfNotLoaded();
+ return this._oldParentPostId;
+ }
+ }
+ public Post oldParentPost {
+ get {
+ return Post.LoadById(this.oldParentPostId.Value);
+ }
+ }
+
+ private int _newBoardId;
+ public int newBoardId {
+ get {
+ this.LoadIfNotLoaded();
+ return this._newBoardId;
+ }
+ }
+ public Board newBoard {
+ get {
+ return Board.LoadById(this.newBoardId);
+ }
+ }
+
+ private bool _isSubthreadTransfer;
+ public bool isSubthreadTransfer {
+ get {
+ this.LoadIfNotLoaded();
+ return this._isSubthreadTransfer;
+ }
+ }
+
+ protected override void doFromHash(Dictionary data) {
+ this._oldBoardId = int.Parse(data[TableSpec.FIELD_OLDBOARDID]);
+ this._oldParentPostId = Util.ParseInt(data[TableSpec.FIELD_OLDPARENTPOSTID]);
+ this._newBoardId = int.Parse(data[TableSpec.FIELD_NEWBOARDID]);
+ this._isSubthreadTransfer = Util.string2bool(data[TableSpec.FIELD_ISSUBTHREADTRANSFER]);
+ }
+
+ public XElement exportToXml(UserContext context) {
+ return new XElement("transfer",
+ new XElement("id", this.id),
+ new XElement("oldBoard", this.oldBoard.exportToXmlSimple(context)),
+ this.oldParentPostId.HasValue ? new XElement("oldParentPost", this.oldParentPost.exportToXmlBase(context)) : null,
+ new XElement("newBoard", this.newBoard.exportToXmlSimple(context)),
+ new XElement("isSubthreadTransfer", this.isSubthreadTransfer.ToPlainString())
+ );
+ }
+
+ }
+}
diff --git a/Common/dataobjects/Thread.cs b/Common/dataobjects/Thread.cs
index bab5fad..9654521 100644
--- a/Common/dataobjects/Thread.cs
+++ b/Common/dataobjects/Thread.cs
@@ -470,6 +470,14 @@ namespace FLocal.Common.dataobjects {
return new KeyValuePair>(postInsert, changes);
}
+ public readonly object locker = new object();
+
+ public void Synchronized(Action action) {
+ lock(this.locker) {
+ this.board.Synchronized(action);
+ }
+ }
+
}
}
diff --git a/Core/extensions/Extensions.cs b/Core/extensions/Extensions.cs
index 1887b6c..d43904d 100644
--- a/Core/extensions/Extensions.cs
+++ b/Core/extensions/Extensions.cs
@@ -57,7 +57,7 @@ namespace FLocal.Core {
return string.Join(",", (from elem in list select elem.ToString()).ToArray());
}
- public static string ToXmlApiRequestString(this bool val) {
+ public static string ToDBString(this bool val) {
return val ? "1" : "0";
}
@@ -230,5 +230,22 @@ namespace FLocal.Core {
return date.ToUniversalTime().ToString("u");
}
+ public static IEnumerable ToSequence(this T obj, Func> nextElementsGenerator) where T : class {
+ yield return obj;
+ foreach(var sub in nextElementsGenerator(obj)) {
+ foreach(var subsub in sub.ToSequence(nextElementsGenerator)) {
+ yield return subsub;
+ }
+ }
+ }
+
+ public static T Last(this List list) {
+ return list[list.Count-1];
+ }
+
+ public static IEnumerable Union(this IEnumerable enumerable, params T[] second) {
+ return enumerable.Union((IEnumerable)second);
+ }
+
}
}
diff --git a/IISMainHandler/handlers/BoardHandler.cs b/IISMainHandler/handlers/BoardHandler.cs
index 2f8535a..ecb8bd8 100644
--- a/IISMainHandler/handlers/BoardHandler.cs
+++ b/IISMainHandler/handlers/BoardHandler.cs
@@ -25,7 +25,7 @@ namespace FLocal.IISHandler.handlers {
IEnumerable threads = board.getThreads(pageOuter);
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("boards", from subBoard in board.subBoards select subBoard.exportToXml(context, Board.SubboardsOptions.FirstLevel)),
new XElement("threads",
from thread in threads select thread.exportToXml(context),
pageOuter.exportToXml(1, 5, 1)
diff --git a/IISMainHandler/handlers/BoardsHandler.cs b/IISMainHandler/handlers/BoardsHandler.cs
index aba4e20..5194088 100644
--- a/IISMainHandler/handlers/BoardsHandler.cs
+++ b/IISMainHandler/handlers/BoardsHandler.cs
@@ -22,7 +22,7 @@ namespace FLocal.IISHandler.handlers {
override protected IEnumerable getSpecificData(WebContext context) {
return new XElement[] {
- new XElement("categories", from category in Category.allCategories select category.exportToXmlForMainPage(context)),
+ new XElement("categories", from category in Category.allCategories select category.exportToXmlForMainPage(context, Board.SubboardsOptions.FirstLevel)),
new XElement("totalRegistered", Config.instance.mainConnection.GetCountByConditions(User.TableSpec.instance, new EmptyCondition())),
new XElement("activity",
new XElement("threshold", Config.instance.ActivityThreshold.ToString()),
diff --git a/IISMainHandler/handlers/request/CreateThreadHandler.cs b/IISMainHandler/handlers/request/CreateThreadHandler.cs
index fdf3195..8dd9396 100644
--- a/IISMainHandler/handlers/request/CreateThreadHandler.cs
+++ b/IISMainHandler/handlers/request/CreateThreadHandler.cs
@@ -24,7 +24,7 @@ namespace FLocal.IISHandler.handlers.request {
newThread.markAsRead(context.session.account, newPost, newPost);
return new XElement[] {
- newThread.board.exportToXml(context, false),
+ newThread.board.exportToXml(context, Board.SubboardsOptions.None),
newPost.exportToXml(context)
};
}
diff --git a/IISMainHandler/handlers/request/EditHandler.cs b/IISMainHandler/handlers/request/EditHandler.cs
index 1c38f57..40b6a06 100644
--- a/IISMainHandler/handlers/request/EditHandler.cs
+++ b/IISMainHandler/handlers/request/EditHandler.cs
@@ -26,7 +26,7 @@ namespace FLocal.IISHandler.handlers.request {
);
return new XElement[] {
- post.thread.board.exportToXml(context, false),
+ post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
postXml
};
}
diff --git a/IISMainHandler/handlers/request/PunishHandler.cs b/IISMainHandler/handlers/request/PunishHandler.cs
index 853fe9f..4c41c5f 100644
--- a/IISMainHandler/handlers/request/PunishHandler.cs
+++ b/IISMainHandler/handlers/request/PunishHandler.cs
@@ -21,11 +21,16 @@ namespace FLocal.IISHandler.handlers.request {
post.Punish(
context.session.account,
PunishmentType.LoadById(int.Parse(context.httprequest.Form["punishmentTypeId"])),
- context.httprequest.Form["comment"]
+ context.httprequest.Form["comment"],
+ (context.httprequest.Form["transfer"] == "transfer")
+ ?
+ (PunishmentTransfer.NewTransferInfo?)new PunishmentTransfer.NewTransferInfo(Board.LoadById(int.Parse(context.httprequest.Form["transfer_boardId"])), context.httprequest.Form["transfer_subThread"] == "transfer_subThread")
+ :
+ null
);
return new XElement[] {
- post.thread.board.exportToXml(context, false),
+ post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
postXml
};
}
diff --git a/IISMainHandler/handlers/request/ReplyHandler.cs b/IISMainHandler/handlers/request/ReplyHandler.cs
index 35f14a7..cc51ef8 100644
--- a/IISMainHandler/handlers/request/ReplyHandler.cs
+++ b/IISMainHandler/handlers/request/ReplyHandler.cs
@@ -24,7 +24,7 @@ namespace FLocal.IISHandler.handlers.request {
newPost.thread.markAsRead(context.session.account, newPost, newPost);
return new XElement[] {
- newPost.thread.board.exportToXml(context, false),
+ newPost.thread.board.exportToXml(context, Board.SubboardsOptions.None),
newPost.exportToXml(context)
};
}
diff --git a/IISMainHandler/handlers/response/BoardAsThread.cs b/IISMainHandler/handlers/response/BoardAsThread.cs
index f9a1cdb..e82a85b 100644
--- a/IISMainHandler/handlers/response/BoardAsThread.cs
+++ b/IISMainHandler/handlers/response/BoardAsThread.cs
@@ -32,7 +32,7 @@ namespace FLocal.IISHandler.handlers.response {
);
return new XElement[] {
new XElement("currentLocation", board.exportToXmlSimpleWithParent(context)),
- new XElement("boards", from subBoard in board.subBoards select subBoard.exportToXml(context, true)),
+ new XElement("boards", from subBoard in board.subBoards select subBoard.exportToXml(context, Board.SubboardsOptions.FirstLevel)),
new XElement("posts",
from thread in threads select thread.firstPost.exportToXml(
context,
diff --git a/IISMainHandler/handlers/response/CreateThreadHandler.cs b/IISMainHandler/handlers/response/CreateThreadHandler.cs
index ad1ebcb..3eab456 100644
--- a/IISMainHandler/handlers/response/CreateThreadHandler.cs
+++ b/IISMainHandler/handlers/response/CreateThreadHandler.cs
@@ -22,7 +22,7 @@ namespace FLocal.IISHandler.handlers.response {
Board board = Board.LoadById(int.Parse(context.requestParts[1]));
return new XElement[] {
- board.exportToXml(context, false),
+ board.exportToXml(context, Board.SubboardsOptions.None),
new XElement("layers",
from layer in PostLayer.allLayers select layer.exportToXml(context)
),
diff --git a/IISMainHandler/handlers/response/EditHandler.cs b/IISMainHandler/handlers/response/EditHandler.cs
index 248d74b..59a6e0a 100644
--- a/IISMainHandler/handlers/response/EditHandler.cs
+++ b/IISMainHandler/handlers/response/EditHandler.cs
@@ -22,7 +22,7 @@ namespace FLocal.IISHandler.handlers.response {
Post post = Post.LoadById(int.Parse(context.requestParts[1]));
return new XElement[] {
- post.thread.board.exportToXml(context, false),
+ post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
post.thread.exportToXml(context),
post.exportToXml(context),
post.latestRevision.exportToXml(context),
diff --git a/IISMainHandler/handlers/response/PMReplyToPostHandler.cs b/IISMainHandler/handlers/response/PMReplyToPostHandler.cs
index 2434e91..4441b18 100644
--- a/IISMainHandler/handlers/response/PMReplyToPostHandler.cs
+++ b/IISMainHandler/handlers/response/PMReplyToPostHandler.cs
@@ -31,7 +31,7 @@ namespace FLocal.IISHandler.handlers.response {
}
return new XElement[] {
- post.thread.board.exportToXml(context, false),
+ post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
post.thread.exportToXml(context),
post.exportToXml(context),
new XElement("receiver", Account.LoadByUser(post.poster).exportToXml(context)),
diff --git a/IISMainHandler/handlers/response/PunishHandler.cs b/IISMainHandler/handlers/response/PunishHandler.cs
index a121cd3..5d2dc3d 100644
--- a/IISMainHandler/handlers/response/PunishHandler.cs
+++ b/IISMainHandler/handlers/response/PunishHandler.cs
@@ -25,13 +25,17 @@ namespace FLocal.IISHandler.handlers.response {
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.board.exportToXml(context, Board.SubboardsOptions.None),
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("categories",
+ from category in Category.allCategories select
+ category.exportToXmlForMainPage(context, Board.SubboardsOptions.AllLevels)
+ ),
new XElement("punishmentTypes",
from punishmentType in PunishmentType.allTypes select punishmentType.exportToXml(context)
)
diff --git a/IISMainHandler/handlers/response/ReplyHandler.cs b/IISMainHandler/handlers/response/ReplyHandler.cs
index 22ca3c8..ddd13b8 100644
--- a/IISMainHandler/handlers/response/ReplyHandler.cs
+++ b/IISMainHandler/handlers/response/ReplyHandler.cs
@@ -31,7 +31,7 @@ namespace FLocal.IISHandler.handlers.response {
}
return new XElement[] {
- post.thread.board.exportToXml(context, false),
+ post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
post.thread.exportToXml(context),
post.exportToXml(context),
new XElement("layers",
diff --git a/templates/Full/PostPunish.xslt b/templates/Full/PostPunish.xslt
index d04a3e7..40574e2 100644
--- a/templates/Full/PostPunish.xslt
+++ b/templates/Full/PostPunish.xslt
@@ -31,6 +31,19 @@
Тип:
+
+
+
+
+
+
Комментарий:
@@ -52,7 +65,7 @@
@@ -96,4 +109,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/Full/elems/BoardInfo.xslt b/templates/Full/elems/BoardInfo.xslt
index f559d5f..ebe4162 100644
--- a/templates/Full/elems/BoardInfo.xslt
+++ b/templates/Full/elems/BoardInfo.xslt
@@ -53,12 +53,14 @@
-
-
- /Thread//p/
- от
-
-
+
+
+
+ /Thread//p/
+ от
+
+
+
diff --git a/templates/Full/elems/PostInfo.xslt b/templates/Full/elems/PostInfo.xslt
index 048797f..c5d79f9 100644
--- a/templates/Full/elems/PostInfo.xslt
+++ b/templates/Full/elems/PostInfo.xslt
@@ -187,6 +187,37 @@
)
+
+
+
+ Подветка была перенесена
+
+
+ Сообщение было перенесено
+
+
+
+ из обсуждения сообщения
+
+
+ /Post/
+
+ /
+
+
+
+
+ из раздела
+
+
+ /Board/
+
+ /
+
+
+
+
+