Auto restrictions implemented

main
Inga 🏳‍🌈 14 years ago
parent 89a08790bf
commit 7904c55b41
  1. 2
      Builder/IISMainHandler/build.txt
  2. 1
      Common/Common.csproj
  3. 1
      Common/TableManager.cs
  4. 1
      Common/actions/ChangeSet.cs
  5. 19
      Common/dataobjects/Board.cs
  6. 4
      Common/dataobjects/Post.cs
  7. 22
      Common/dataobjects/PostLayer.cs
  8. 31
      Common/dataobjects/Punishment.cs
  9. 237
      Common/dataobjects/Restriction.cs
  10. 2
      Common/dataobjects/User.cs
  11. 4
      IISMainHandler/handlers/response/CreateThreadHandler.cs
  12. 4
      IISMainHandler/handlers/response/EditHandler.cs
  13. 4
      IISMainHandler/handlers/response/ReplyHandler.cs
  14. 2
      templates/Full/NewThread.xslt
  15. 2
      templates/Full/PostEdit.xslt
  16. 2
      templates/Full/PostPunish.xslt
  17. 2
      templates/Full/PostReply.xslt
  18. 25
      templates/Full/elems/TextEditor.xslt
  19. 4
      templates/Lite/NewThread.xslt
  20. 2
      templates/Lite/PostEdit.xslt
  21. 2
      templates/Lite/PostPunish.xslt
  22. 2
      templates/Lite/PostReply.xslt
  23. 25
      templates/Lite/elems/TextEditor.xslt

@ -108,6 +108,7 @@
<Compile Include="dataobjects\PunishmentTransfer.cs" />
<Compile Include="dataobjects\PunishmentType.cs" />
<Compile Include="dataobjects\QuickLink.cs" />
<Compile Include="dataobjects\Restriction.cs" />
<Compile Include="dataobjects\Revision.cs" />
<Compile Include="dataobjects\Session.cs" />
<Compile Include="dataobjects\Skin.cs" />

@ -26,6 +26,7 @@ namespace FLocal.Common {
dataobjects.PunishmentLayerChange.TableSpec.instance,
dataobjects.PunishmentTransfer.TableSpec.instance,
dataobjects.PunishmentType.TableSpec.instance,
dataobjects.Restriction.TableSpec.instance,
dataobjects.QuickLink.TableSpec.instance,
dataobjects.Revision.TableSpec.instance,
dataobjects.Session.TableSpec.instance,

@ -39,6 +39,7 @@ namespace FLocal.Common.actions {
dataobjects.Punishment.TableSpec.TABLE,
dataobjects.PunishmentTransfer.TableSpec.TABLE,
dataobjects.PunishmentLayerChange.TableSpec.TABLE,
dataobjects.Restriction.TableSpec.TABLE,
dataobjects.TexImage.TableSpec.TABLE,
dataobjects.Session.TableSpec.TABLE,
}

@ -435,5 +435,24 @@ namespace FLocal.Common.dataobjects {
}
}
public XElement exportLayersInfoForUser(UserContext context) {
Dictionary<int, DateTime> restrictionData = new Dictionary<int,DateTime>();
if(context.account != null) {
restrictionData = Restriction.GetRestrictionData(context.account.user, this);
}
return new XElement("layers",
from layer in PostLayer.allLayers
select layer.exportToXml(
context,
new XElement("isRestricted",
(restrictionData.ContainsKey(layer.id) && restrictionData[layer.id].CompareTo(DateTime.Now) >= 0).ToPlainString()
),
new XElement("restrictionExpires",
restrictionData.ContainsKey(layer.id) ? restrictionData[layer.id].ToXml() : null
)
)
);
}
}
}

@ -608,6 +608,10 @@ namespace FLocal.Common.dataobjects {
newMessage.conversation.markAsRead(account, newMessage, newMessage);
}
HashSet<int> punishmentsBoards = new HashSet<int>(from punishment in this.punishments select punishment.originalBoardId);
foreach(int boardId in punishmentsBoards) {
Restriction.RecalculateRestrictions(Board.LoadById(boardId), this.poster);
}
}
}
}

@ -19,6 +19,7 @@ namespace FLocal.Common.dataobjects {
public const string TABLE = "Layers";
public const string FIELD_ID = "Id";
public const string FIELD_NAME = "Name";
public const string FIELD_MAXPUNISHMENTS = "MaxPunishments";
public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } }
@ -35,8 +36,17 @@ namespace FLocal.Common.dataobjects {
}
}
private int? _maxPunishments;
public int? maxPunishments {
get {
this.LoadIfNotLoaded();
return this._maxPunishments;
}
}
protected override void doFromHash(Dictionary<string, string> data) {
this._name = data[TableSpec.FIELD_NAME];
this._maxPunishments = Util.ParseInt(data[TableSpec.FIELD_MAXPUNISHMENTS]);
}
private static readonly object allLayers_Locker = new object();
@ -46,11 +56,11 @@ namespace FLocal.Common.dataobjects {
from id in Cache<IEnumerable<int>>.instance.get(
allLayers_Locker,
() => {
IEnumerable<int> ids = from stringId in Config.instance.mainConnection.LoadIdsByConditions(
IEnumerable<int> ids = (from stringId in Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new FLocal.Core.DB.conditions.EmptyCondition(),
Diapasone.unlimited
) select int.Parse(stringId);
) select int.Parse(stringId)).ToList();
PostLayer.LoadByIds(ids);
return ids;
}
@ -64,11 +74,15 @@ namespace FLocal.Common.dataobjects {
Cache<IEnumerable<int>>.instance.delete(allLayers_Locker);
}
public XElement exportToXml(UserContext context) {
return new XElement("layer",
public XElement exportToXml(UserContext context, params XElement[] additional) {
XElement result = new XElement("layer",
new XElement("id", this.id),
new XElement("name", this.name)
);
if(additional.Length > 0) {
result.Add(additional);
}
return result;
}
}

@ -185,5 +185,36 @@ namespace FLocal.Common.dataobjects {
);
}
public static IEnumerable<Punishment> getEffectivePunishments(User user, Board board) {
return
from stringId in Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new ComplexCondition(
ConditionsJoinType.AND,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_OWNERID),
ComparisonType.EQUAL,
user.id.ToString()
),
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_ORIGINALBOARDID),
ComparisonType.EQUAL,
board.id.ToString()
),
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_ISWITHDRAWED),
ComparisonType.EQUAL,
"0"
),
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_EXPIRES),
ComparisonType.GREATEROREQUAL,
DateTime.Now.ToUTCString()
)
),
Diapasone.unlimited
) select Punishment.LoadById(int.Parse(stringId));
}
}
}

@ -0,0 +1,237 @@
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;
using FLocal.Common.actions;
namespace FLocal.Common.dataobjects {
public class Restriction : SqlObject<Restriction> {
public class TableSpec : ISqlObjectTableSpec {
public const string TABLE = "Restrictions";
public const string FIELD_ID = "Id";
public const string FIELD_USERID = "UserId";
public const string FIELD_BOARDID = "BoardId";
public const string FIELD_DATA = "Data";
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 restriction = Restriction.LoadById(id);
byUser_Recalculate(restriction.userId);
byBoard_Recalculate(restriction.boardId);
lock(restrictionId_cache) {
if(!restrictionId_cache.ContainsKey(restriction.userId)) restrictionId_cache[restriction.userId] = new Dictionary<int, int?>();
restrictionId_cache[restriction.userId][restriction.boardId] = restriction.id;
}
}
}
protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } }
private int _userId;
public int userId {
get {
this.LoadIfNotLoaded();
return this._userId;
}
}
public User user {
get {
return User.LoadById(this.userId);
}
}
private int _boardId;
public int boardId {
get {
this.LoadIfNotLoaded();
return this._boardId;
}
}
public Board board {
get {
return Board.LoadById(this.boardId);
}
}
private Dictionary<int, DateTime> _data;
public Dictionary<int, DateTime> data {
get {
this.LoadIfNotLoaded();
return this._data;
}
}
protected override void doFromHash(Dictionary<string, string> data) {
this._userId = int.Parse(data[TableSpec.FIELD_USERID]);
this._boardId = int.Parse(data[TableSpec.FIELD_BOARDID]);
this._data = (
from part in data[TableSpec.FIELD_DATA].Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries)
let subparts = part.Split(new char[] {':'}, 2)
select new KeyValuePair<int, DateTime>(
int.Parse(subparts[0]),
new DateTime(long.Parse(subparts[1]))
)
).ToDictionary();
}
private static readonly Dictionary<int, Dictionary<int, int?>> restrictionId_cache = new Dictionary<int,Dictionary<int, int?>>();
public static Restriction GetRestriction(User user, Board board) {
if(!restrictionId_cache.ContainsKey(user.id) || !restrictionId_cache[user.id].ContainsKey(board.id)) {
lock(restrictionId_cache) {
if(!restrictionId_cache.ContainsKey(user.id) || !restrictionId_cache[user.id].ContainsKey(board.id)) {
if(!restrictionId_cache.ContainsKey(user.id)) restrictionId_cache[user.id] = new Dictionary<int, int?>();
List<string> ids = Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new ComplexCondition(
ConditionsJoinType.AND,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_USERID),
ComparisonType.EQUAL,
user.id.ToString()
),
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_BOARDID),
ComparisonType.EQUAL,
board.id.ToString()
)
),
Diapasone.unlimited
);
if(ids.Count < 1) {
restrictionId_cache[user.id][board.id] = null;
} else {
restrictionId_cache[user.id][board.id] = Restriction.LoadById(int.Parse(ids.Single())).id;
}
}
}
}
if(restrictionId_cache[user.id][board.id].HasValue) {
return Restriction.LoadById(restrictionId_cache[user.id][board.id].Value);
} else {
return null;
}
}
public static Dictionary<int, DateTime> GetRestrictionData(User user, Board board) {
Restriction restriction = GetRestriction(user, board);
if(restriction != null) {
return restriction.data;
} else {
return new Dictionary<int,DateTime>();
}
}
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 Restriction.LoadById(int.Parse(stringId)).id;
}
}
public static IEnumerable<User> GetRestrictedUsers(Board board) {
if(!byBoard_cache.ContainsKey(board.id)) {
byBoard_Recalculate(board.id);
}
return from id in byBoard_cache[board.id] select Restriction.LoadById(id).user;
}
private static readonly Dictionary<int, IEnumerable<int>> byUser_cache = new Dictionary<int,IEnumerable<int>>();
private static void byUser_Recalculate(int userId) {
lock(byUser_cache) {
byUser_cache[userId] =
from stringId in Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_USERID),
ComparisonType.EQUAL,
userId.ToString()
),
Diapasone.unlimited
)
select Restriction.LoadById(int.Parse(stringId)).id;
}
}
public static IEnumerable<Board> GetRestrictions(User user) {
if(!byUser_cache.ContainsKey(user.id)) {
byUser_Recalculate(user.id);
}
return from id in byUser_cache[user.id] select Restriction.LoadById(id).board;
}
public static void RecalculateRestrictions(Board board, User user) {
List<Punishment> punishments = (from punishment in Punishment.getEffectivePunishments(user, board) where punishment.punishmentType.weight > 0 orderby punishment.expires descending select punishment).ToList();
Dictionary<int, DateTime> layer2expirationDate = new Dictionary<int,DateTime>();
foreach(var layer in PostLayer.allLayers) {
if(!layer.maxPunishments.HasValue) continue;
bool restricted = false;
int accumulated = 0;
DateTime? expirationDate = null;
foreach(var punishment in punishments) {
accumulated += punishment.punishmentType.weight;
if(accumulated >= layer.maxPunishments.Value) {
expirationDate = punishment.expires;
restricted = true;
break;
}
}
if(restricted) {
layer2expirationDate[layer.id] = expirationDate.Value;
}
}
string data = (from kvp in layer2expirationDate select string.Format("{0}:{1}", kvp.Key, kvp.Value.Ticks)).Join(";");
ChangeSetUtil.ApplyChanges(
new InsertOrUpdateChange(
TableSpec.instance,
new Dictionary<string,AbstractFieldValue> {
{ TableSpec.FIELD_BOARDID, new ScalarFieldValue(board.id.ToString()) },
{ TableSpec.FIELD_USERID, new ScalarFieldValue(user.id.ToString()) },
{ TableSpec.FIELD_DATA, new ScalarFieldValue(data) },
},
new Dictionary<string,AbstractFieldValue> {
{ TableSpec.FIELD_DATA, new ScalarFieldValue(data) },
},
new ComplexCondition(
ConditionsJoinType.AND,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_BOARDID),
ComparisonType.EQUAL,
board.id.ToString()
),
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_USERID),
ComparisonType.EQUAL,
user.id.ToString()
)
)
)
);
}
}
}

@ -226,6 +226,8 @@ namespace FLocal.Common.dataobjects {
}
public PostLayer getActualLayer(Board board, PostLayer desiredLayer) {
Dictionary<int, DateTime> restrictionData = Restriction.GetRestrictionData(this, board);
if(restrictionData.ContainsKey(desiredLayer.id) && (restrictionData[desiredLayer.id].CompareTo(DateTime.Now) >= 0)) throw new FLocalException("You're restricted from posting in this layer until " + restrictionData[desiredLayer.id].ToString());
return desiredLayer;
}

@ -23,9 +23,7 @@ namespace FLocal.IISHandler.handlers.response {
return new XElement[] {
board.exportToXml(context, Board.SubboardsOptions.None),
new XElement("layers",
from layer in PostLayer.allLayers select layer.exportToXml(context)
),
board.exportLayersInfoForUser(context),
};
}
}

@ -26,9 +26,7 @@ namespace FLocal.IISHandler.handlers.response {
post.thread.exportToXml(context),
post.exportToXml(context),
post.latestRevision.exportToXml(context),
new XElement("layers",
from layer in PostLayer.allLayers select layer.exportToXml(context)
),
post.thread.board.exportLayersInfoForUser(context),
};
}
}

@ -34,9 +34,7 @@ namespace FLocal.IISHandler.handlers.response {
post.thread.board.exportToXml(context, Board.SubboardsOptions.None),
post.thread.exportToXml(context),
post.exportToXml(context),
new XElement("layers",
from layer in PostLayer.allLayers select layer.exportToXml(context)
),
post.thread.board.exportLayersInfoForUser(context),
new XElement("quoted", quoted),
};
}

@ -38,7 +38,7 @@
<input type="text" tabindex="1" name="title" maxlength="70" class="formboxes" size="60"/>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<!--xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param-->
</xsl:apply-templates>
</select>

@ -40,7 +40,7 @@
</input>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -51,7 +51,7 @@
</label>
<select name="layerChange_layerId">
<option value="-1">Âûáåðèòå ñëîé</option>
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -50,7 +50,7 @@
</input>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -319,11 +319,32 @@ function insertInBody(str) {
<xsl:param name="defaultLayerId"/>
<option>
<xsl:attribute name="value"><xsl:value-of select="id"/></xsl:attribute>
<xsl:if test="id=$defaultLayerId">
<xsl:choose>
<xsl:when test="isRestricted='true'">
<xsl:attribute name="disabled">disabled</xsl:attribute>
</xsl:when>
<xsl:when test="id=$defaultLayerId">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
</xsl:when>
</xsl:choose>
<xsl:value-of select="name"/>
</option>
</xsl:template>
<xsl:template match="layers">
<xsl:param name="defaultLayerId"/>
<xsl:apply-templates select="layer">
<xsl:with-param name="defaultLayerId">
<xsl:choose>
<xsl:when test="$defaultLayerId and not(layer[id=$defaultLayerId]/isRestricted='true')">
<xsl:value-of select="defaultLayerId"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="layer[not(isRestricted='true')][1]/id"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>

@ -33,9 +33,7 @@
<input type="text" tabindex="1" name="title" maxlength="70" class="formboxes" size="60"/>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<!--xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param-->
</xsl:apply-templates>
<xsl:apply-templates select="layers"/>
</select>
<br/>
<br/>

@ -35,7 +35,7 @@
</input>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -46,7 +46,7 @@
</label>
<select name="layerChange_layerId">
<option value="-1">Âûáåðèòå ñëîé</option>
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -45,7 +45,7 @@
</input>
<span class="small">Ñëîé ñîîáùåíèÿ:</span>
<select class="formboxes" name="layerId">
<xsl:apply-templates select="layers/layer">
<xsl:apply-templates select="layers">
<xsl:with-param name="defaultLayerId"><xsl:value-of select="post/layerId"/></xsl:with-param>
</xsl:apply-templates>
</select>

@ -47,11 +47,32 @@ function insertInBody(str) {
<xsl:param name="defaultLayerId"/>
<option>
<xsl:attribute name="value"><xsl:value-of select="id"/></xsl:attribute>
<xsl:if test="id=$defaultLayerId">
<xsl:choose>
<xsl:when test="isRestricted='true'">
<xsl:attribute name="disabled">disabled</xsl:attribute>
</xsl:when>
<xsl:when test="id=$defaultLayerId">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:if>
</xsl:when>
</xsl:choose>
<xsl:value-of select="name"/>
</option>
</xsl:template>
<xsl:template match="layers">
<xsl:param name="defaultLayerId"/>
<xsl:apply-templates select="layer">
<xsl:with-param name="defaultLayerId">
<xsl:choose>
<xsl:when test="$defaultLayerId and not(layer[id=$defaultLayerId]/isRestricted='true')">
<xsl:value-of select="defaultLayerId"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="layer[not(isRestricted='true')][1]/id"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Loading…
Cancel
Save