Active 'who is online' implemented; last activity of user implemented

main
Inga 🏳‍🌈 14 years ago
parent 05cb92e8ee
commit b94a29b8d8
  1. 2
      Builder/IISMainHandler/build.txt
  2. 22
      Common/dataobjects/Account.cs
  3. 71
      Common/dataobjects/Session.cs
  4. 6
      Core/DB/Diapasone.cs
  5. 2
      IISMainHandler/WebContext.cs
  6. 5
      IISMainHandler/handlers/response/UserInfoHandler.cs
  7. 29
      IISMainHandler/handlers/response/WhoIsOnlineHandler.cs
  8. 2
      templates/Full/UserInfo.xslt
  9. 59
      templates/Full/WhoIsOnline.xslt

@ -20,6 +20,8 @@ namespace FLocal.Common.dataobjects {
public const string FIELD_NAME = "Name"; public const string FIELD_NAME = "Name";
public const string FIELD_IPADDRESS = "IpAddress"; public const string FIELD_IPADDRESS = "IpAddress";
public const string FIELD_REGISTRATIONEMAIL = "RegistrationEmail"; public const string FIELD_REGISTRATIONEMAIL = "RegistrationEmail";
public const string FIELD_ISSTATUSHIDDEN = "IsStatusHidden";
public const string FIELD_ISDETAILEDSTATUSHIDDEN = "IsDetailedStatusHidden";
public static readonly TableSpec instance = new TableSpec(); public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } } public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } } public string idName { get { return FIELD_ID; } }
@ -65,11 +67,29 @@ namespace FLocal.Common.dataobjects {
} }
} }
private bool _isStatusHidden;
public bool isStatusHidden {
get {
this.LoadIfNotLoaded();
return this._isStatusHidden;
}
}
private bool _isDetailedStatusHidden;
public bool isDetailedStatusHidden {
get {
this.LoadIfNotLoaded();
return this._isDetailedStatusHidden;
}
}
protected override void doFromHash(Dictionary<string, string> data) { protected override void doFromHash(Dictionary<string, string> data) {
this._userId = int.Parse(data[TableSpec.FIELD_USERID]); this._userId = int.Parse(data[TableSpec.FIELD_USERID]);
this._passwordHash = data[TableSpec.FIELD_PASSWORDHASH]; this._passwordHash = data[TableSpec.FIELD_PASSWORDHASH];
this._needsMigration = Util.string2bool(data[TableSpec.FIELD_NEEDSMIGRATION]); this._needsMigration = Util.string2bool(data[TableSpec.FIELD_NEEDSMIGRATION]);
this._name = data[TableSpec.FIELD_NAME]; this._name = data[TableSpec.FIELD_NAME];
this._isStatusHidden = Util.string2bool(data[TableSpec.FIELD_ISSTATUSHIDDEN]);
this._isDetailedStatusHidden = Util.string2bool(data[TableSpec.FIELD_ISDETAILEDSTATUSHIDDEN]);
} }
public XElement exportToXml(UserContext context) { public XElement exportToXml(UserContext context) {
@ -205,6 +225,8 @@ namespace FLocal.Common.dataobjects {
{ Account.TableSpec.FIELD_USERID, new ReferenceFieldValue(userInsert) }, { Account.TableSpec.FIELD_USERID, new ReferenceFieldValue(userInsert) },
{ Account.TableSpec.FIELD_IPADDRESS, new ScalarFieldValue(ip) }, { Account.TableSpec.FIELD_IPADDRESS, new ScalarFieldValue(ip) },
{ Account.TableSpec.FIELD_REGISTRATIONEMAIL, new ScalarFieldValue(registrationEmail) }, { Account.TableSpec.FIELD_REGISTRATIONEMAIL, new ScalarFieldValue(registrationEmail) },
{ Account.TableSpec.FIELD_ISSTATUSHIDDEN, new ScalarFieldValue("0") },
{ Account.TableSpec.FIELD_ISDETAILEDSTATUSHIDDEN, new ScalarFieldValue("0") },
} }
); );
var indicatorInsert = new InsertChange( var indicatorInsert = new InsertChange(

@ -48,6 +48,8 @@ namespace FLocal.Common.dataobjects {
public const string FIELD_SESSIONKEY = "SessionKey"; public const string FIELD_SESSIONKEY = "SessionKey";
public const string FIELD_ACCOUNTID = "AccountId"; public const string FIELD_ACCOUNTID = "AccountId";
public const string FIELD_LASTACTIVITY = "LastActivity"; public const string FIELD_LASTACTIVITY = "LastActivity";
public const string FIELD_LASTURL = "LastUrl";
public const string FIELD_ISDELETED = "IsDeleted";
public static readonly TableSpec instance = new TableSpec(); public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } } public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } } public string idName { get { return FIELD_ID; } }
@ -85,13 +87,31 @@ namespace FLocal.Common.dataobjects {
} }
} }
private string _lastUrl;
public string lastUrl {
get {
this.LoadIfNotLoaded();
return this._lastUrl;
}
}
private bool _isDeleted;
public bool isDeleted {
get {
this.LoadIfNotLoaded();
return this._isDeleted;
}
}
protected override void doFromHash(Dictionary<string, string> data) { protected override void doFromHash(Dictionary<string, string> data) {
this._sessionKey = data[TableSpec.FIELD_SESSIONKEY]; this._sessionKey = data[TableSpec.FIELD_SESSIONKEY];
this._lastActivity = new DateTime(long.Parse(data[TableSpec.FIELD_LASTACTIVITY])); this._lastActivity = new DateTime(long.Parse(data[TableSpec.FIELD_LASTACTIVITY]));
this._accountId = int.Parse(data[TableSpec.FIELD_ACCOUNTID]); this._accountId = int.Parse(data[TableSpec.FIELD_ACCOUNTID]);
this._lastUrl = data[TableSpec.FIELD_LASTURL];
this._isDeleted = Util.string2bool(data[TableSpec.FIELD_ISDELETED]);
} }
public void updateLastActivity() { public void updateLastActivity(string lastUrl) {
if(DateTime.Now.Subtract(this.lastActivity).TotalSeconds < 30) return; //to partially remove db load if(DateTime.Now.Subtract(this.lastActivity).TotalSeconds < 30) return; //to partially remove db load
try { try {
Config.Transactional(transaction => { Config.Transactional(transaction => {
@ -100,7 +120,8 @@ namespace FLocal.Common.dataobjects {
TableSpec.instance, TableSpec.instance,
this.id.ToString(), this.id.ToString(),
new Dictionary<string,string>() { new Dictionary<string,string>() {
{ TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() } { TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() },
{ TableSpec.FIELD_LASTURL, (lastUrl != null) ? lastUrl : this.lastUrl },
} }
); );
}); });
@ -128,6 +149,8 @@ namespace FLocal.Common.dataobjects {
{ TableSpec.FIELD_SESSIONKEY, key }, { TableSpec.FIELD_SESSIONKEY, key },
{ TableSpec.FIELD_ACCOUNTID, account.id.ToString() }, { TableSpec.FIELD_ACCOUNTID, account.id.ToString() },
{ TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() }, { TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() },
{ TableSpec.FIELD_LASTURL, "" },
{ TableSpec.FIELD_ISDELETED, "0" },
} }
); );
}); });
@ -135,8 +158,20 @@ namespace FLocal.Common.dataobjects {
} }
public void delete() { public void delete() {
Config.Transactional(transaction => Config.instance.mainConnection.delete(transaction, TableSpec.instance, this.id.ToString())); try {
this.deleteFromRegistry(); Config.Transactional(transaction => {
Config.instance.mainConnection.update(
transaction,
TableSpec.instance,
this.id.ToString(),
new Dictionary<string,string>() {
{ TableSpec.FIELD_ISDELETED, "1" },
}
);
});
} finally {
this.ReLoad();
}
} }
public XElement exportToXml(UserContext context) { public XElement exportToXml(UserContext context) {
@ -149,7 +184,33 @@ namespace FLocal.Common.dataobjects {
} }
public static Session LoadByKey(string sessionKey) { public static Session LoadByKey(string sessionKey) {
return LoadById(SessionKey.Parse(sessionKey)); Session result = LoadById(SessionKey.Parse(sessionKey));
if(result.isDeleted) throw new NotFoundInDBException(TableSpec.instance, sessionKey);
return result;
}
public static Session GetLastSession(Account account) {
var ids = Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_ACCOUNTID),
ComparisonType.EQUAL,
account.id.ToString()
),
Diapasone.first,
new JoinSpec[0],
new SortSpec[] {
new SortSpec(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_LASTACTIVITY),
false
)
}
);
if(ids.Count < 1) {
throw new NotFoundInDBException(TableSpec.instance.getColumnSpec(TableSpec.FIELD_ACCOUNTID), account.id.ToString());
}
return Session.LoadById(SessionKey.Parse(ids[0]));
} }
} }

@ -24,5 +24,11 @@ namespace FLocal.Core.DB {
} }
} }
public static Diapasone first {
get {
return new Diapasone(0, 1);
}
}
} }
} }

@ -92,7 +92,7 @@ namespace FLocal.IISHandler {
var session = Session.LoadByKey(sessionCookie.Value); var session = Session.LoadByKey(sessionCookie.Value);
var tmp = session.account; var tmp = session.account;
sessionCookie.Expires = DateTime.Now.AddDays(3); sessionCookie.Expires = DateTime.Now.AddDays(3);
session.updateLastActivity(); session.updateLastActivity(this.httprequest.RequestType == "GET" ? this.httprequest.Path : null);
this.httpresponse.AppendCookie(sessionCookie); this.httpresponse.AppendCookie(sessionCookie);
this.session = session; this.session = session;
} catch(NotFoundInDBException) { } catch(NotFoundInDBException) {

@ -37,9 +37,14 @@ namespace FLocal.IISHandler.handlers.response {
} catch(NotFoundInDBException) { } catch(NotFoundInDBException) {
} }
} }
Session lastSession = null;
if(account != null && !account.isDetailedStatusHidden) {
lastSession = Session.GetLastSession(account);
}
return new XElement[] { return new XElement[] {
user.exportToXmlForViewing(context), user.exportToXmlForViewing(context),
(account == null) ? null : new XElement("accountId", account.id.ToString()), //for PM history, PM send etc (account == null) ? null : new XElement("accountId", account.id.ToString()), //for PM history, PM send etc
(lastSession == null) ? null : new XElement("lastActivity", lastSession.lastActivity.ToXml())
}; };
} }

@ -16,7 +16,7 @@ namespace FLocal.IISHandler.handlers.response {
override protected string templateName { override protected string templateName {
get { get {
return "UserList.xslt"; return "WhoIsOnline.xslt";
} }
} }
@ -25,16 +25,31 @@ namespace FLocal.IISHandler.handlers.response {
IEnumerable<Session> sessions = IEnumerable<Session> sessions =
from stringId in Config.instance.mainConnection.LoadIdsByConditions( from stringId in Config.instance.mainConnection.LoadIdsByConditions(
Session.TableSpec.instance, Session.TableSpec.instance,
new Core.DB.conditions.ComparisonCondition( new ComplexCondition(
Session.TableSpec.instance.getColumnSpec(Session.TableSpec.FIELD_LASTACTIVITY), ConditionsJoinType.AND,
Core.DB.conditions.ComparisonType.GREATEROREQUAL, new ComparisonCondition(
DateTime.Now.Subtract(Config.instance.ActivityThreshold).ToUTCString() Session.TableSpec.instance.getColumnSpec(Session.TableSpec.FIELD_LASTACTIVITY),
Core.DB.conditions.ComparisonType.GREATEROREQUAL,
DateTime.Now.Subtract(Config.instance.ActivityThreshold).ToUTCString()
),
new ComparisonCondition(
Session.TableSpec.instance.getColumnSpec(Session.TableSpec.FIELD_ISDELETED),
Core.DB.conditions.ComparisonType.EQUAL,
"0"
)
), ),
pageOuter pageOuter
) select Session.LoadByKey(stringId); ) select Session.LoadByKey(stringId);
return new XElement[] { return new XElement[] {
new XElement("users", new XElement("users",
from session in sessions select session.account.user.exportToXmlForViewing(context) from session in sessions
let account = session.account
where !account.isStatusHidden
select account.user.exportToXmlForViewing(
context,
new XElement("lastActivity", session.lastActivity.ToXml()),
!account.isDetailedStatusHidden ? new XElement("lastUrl", session.lastUrl) : null
)
) )
}; };
} }

@ -144,7 +144,7 @@
<xsl:text>Ïîñëåäíèé ðàç îíëàéí</xsl:text> <xsl:text>Ïîñëåäíèé ðàç îíëàéí</xsl:text>
</td> </td>
<td> <td>
<xsl:text>Not implemented</xsl:text> <xsl:apply-templates select="lastActivity" mode="dateTime"/>
</td> </td>
</tr> </tr>
<tr> <tr>

@ -0,0 +1,59 @@
<?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 class="tdheader">
<td align="left" width="15%" nowrap="nowrap">
<a>
<xsl:text>Ïîëüçîâàòåëü</xsl:text>
</a>
</td>
<td align="left" width="15%" nowrap="nowrap">
<a>
<xsl:text>Ïîñëåäíÿÿ àêòèâíîñòü</xsl:text>
</a>
</td>
<td align="left" width="70%" nowrap="nowrap">
<a>
<xsl:text>Ïîñëåäíÿÿ ïîñåù¸ííàÿ ñòðàíèöà</xsl:text>
</a>
</td>
</tr>
<xsl:apply-templates select="users/user"/>
</table>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="users/user">
<tr>
<xsl:choose>
<xsl:when test="position() mod 2 = 0">
<xsl:attribute name="class">lighttable</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="class">darktable</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
<td>
<xsl:apply-templates select="current()" mode="userLink"/>
</td>
<td>
<xsl:apply-templates select="lastActivity" mode="dateTime"/>
</td>
<td>
<a>
<xsl:attribute name="href"><xsl:value-of select="lastUrl"/></xsl:attribute>
<xsl:value-of select="lastUrl"/>
</a>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
Loading…
Cancel
Save