Session implemented; login and logout implemented

main
Inga 🏳‍🌈 15 years ago
parent 3e6a58dcbc
commit 1eee4ddff5
  1. 2
      Builder/IISMainHandler/build.txt
  2. 2
      Common/Common.csproj
  3. 7
      Common/Config.cs
  4. 27
      Common/SqlObject.cs
  5. 3
      Common/actions/ChangeSet.cs
  6. 35
      Common/actions/ChangeSetUtil.cs
  7. 2
      Common/actions/InsertChange.cs
  8. 52
      Common/dataobjects/Account.cs
  9. 151
      Common/dataobjects/Session.cs
  10. 12
      Common/dataobjects/Thread.cs
  11. 4
      Core/DataObject.cs
  12. 9
      Core/Util.cs
  13. 4
      Core/extensions/Extensions.cs
  14. 4
      IISMainHandler/HandlersFactory.cs
  15. 2
      IISMainHandler/IISMainHandler.csproj
  16. 36
      IISMainHandler/WebContext.cs
  17. 1
      IISMainHandler/handlers/AbstractGetHandler.cs
  18. 18
      IISMainHandler/handlers/request/AbstractPostHandler.cs
  19. 45
      IISMainHandler/handlers/request/LoginHandler.cs
  20. 39
      IISMainHandler/handlers/request/LogoutHandler.cs
  21. 8
      IISMainHandler/handlers/request/MigrateAccountHandler.cs
  22. 3
      IISMainHandler/handlers/response/MigrateAccountHandler.cs
  23. 20
      MySQLConnector/Connection.cs
  24. 9
      templates/Full/Boards.xslt
  25. 2
      templates/Full/Login.xslt
  26. 9
      templates/Full/Root.xslt
  27. 17
      templates/Full/elems/Header.xslt
  28. 25
      templates/Full/result/Login.xslt
  29. 25
      templates/Full/result/Logout.xslt

@ -54,6 +54,7 @@
<Compile Include="actions\ReferenceFieldValue.cs" />
<Compile Include="actions\ScalarFieldValue.cs" />
<Compile Include="actions\UpdateChange.cs" />
<Compile Include="actions\ChangeSetUtil.cs" />
<Compile Include="Config.cs" />
<Compile Include="dataobjects\Account.cs" />
<Compile Include="dataobjects\Board.cs" />
@ -61,6 +62,7 @@
<Compile Include="dataobjects\IUserSettings.cs" />
<Compile Include="dataobjects\AnonymousUserSettings.cs" />
<Compile Include="dataobjects\Post.cs" />
<Compile Include="dataobjects\Session.cs" />
<Compile Include="dataobjects\Thread.cs" />
<Compile Include="dataobjects\User.cs" />
<Compile Include="IOutputParams.cs" />

@ -42,6 +42,13 @@ namespace FLocal.Common {
base.Dispose();
}
public static void Transactional(Action<Core.DB.Transaction> action) {
using(Core.DB.Transaction transaction = Core.DB.IDBConnectionExtensions.beginTransaction(instance.mainConnection)) {
action(transaction);
transaction.Commit();
}
}
}
}

@ -6,7 +6,9 @@ using FLocal.Core;
using FLocal.Core.DB;
namespace FLocal.Common {
abstract public class SqlObject<T> : Core.DataObject<int, T> where T : SqlObject<T>, new() {
abstract public class SqlObject<TKey, T> : Core.DataObject<TKey, T>
where T : SqlObject<TKey, T>, new()
where TKey : struct {
protected SqlObject() : base() {
}
@ -15,7 +17,15 @@ namespace FLocal.Common {
get;
}
private bool isLoaded = false;
private bool _isLoaded = false;
protected bool isLoaded {
get {
return this._isLoaded;
}
private set {
this._isLoaded = value;
}
}
private object lockFiller = new object();
private object lockInitializer = new object();
@ -82,6 +92,15 @@ namespace FLocal.Common {
if(!forLoadingFromHash) this.Load();
}
protected static void Refresh(TKey id) {
Dictionary<TKey, T> objects = LoadByIdsForLoadingFromHash(new List<TKey>() { id });
objects[id].ReLoad();
}
}
abstract public class SqlObject<T> : SqlObject<int, T> where T : SqlObject<T>, new() {
public static List<T> LoadByIds(IEnumerable<int> ids) {
Dictionary<int, T> rawRes = LoadByIdsForLoadingFromHash(ids);
@ -116,10 +135,6 @@ namespace FLocal.Common {
return res;
}
protected static void Refresh(int id) {
Dictionary<int, T> objects = LoadByIdsForLoadingFromHash(new List<int>() { id });
objects[id].ReLoad();
}
}
}

@ -11,7 +11,7 @@ namespace FLocal.Common.actions {
/// Note that you should create ChangeSet instances outside of transactions they're using!
/// Otherwise, there will be a 100% DB deadlock in Dispose (or data in registry won't update)
/// </summary>
class ChangeSet : IDisposable {
internal class ChangeSet : IDisposable {
private static readonly object tablesLockOrder_locker = new object();
private static IEnumerable<string> tablesLockOrder {
@ -23,6 +23,7 @@ namespace FLocal.Common.actions {
"Boards",
"Threads",
"Posts",
"Sessions",
}
);
}

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FLocal.Core.DB;
namespace FLocal.Common.actions {
class ChangeSetUtil {
public static void WithChangeSet(Action<ChangeSet, Transaction> action) {
using(ChangeSet changeSet = new ChangeSet()) {
Config.Transactional(transaction => {
action(changeSet, transaction);
changeSet.Apply(transaction);
});
}
}
public static void WithChangeSet(Action<ChangeSet> action) {
WithChangeSet((changeset, transaction) => action(changeset));
}
public static void ApplyChanges(IEnumerable<AbstractChange> changes) {
using(ChangeSet changeSet = new ChangeSet()) {
foreach(AbstractChange change in changes) {
changeSet.Add(change);
}
Config.Transactional(transaction => {
changeSet.Apply(transaction);
});
}
}
}
}

@ -9,7 +9,7 @@ namespace FLocal.Common.actions {
private int? id;
public InsertChange(ISqlObjectTableSpec tableSpec, Dictionary<string, AbstractFieldValue> data, int id)
public InsertChange(ISqlObjectTableSpec tableSpec, Dictionary<string, AbstractFieldValue> data)
: base(tableSpec, data) {
this.id = null;
}

@ -15,8 +15,9 @@ namespace FLocal.Common.dataobjects {
public const string TABLE = "Accounts";
public const string FIELD_ID = "Id";
public const string FIELD_USERID = "UserId";
public const string FIELD_PASSWORD = "Password";
public const string FIELD_PASSWORDHASH = "Password";
public const string FIELD_NEEDSMIGRATION = "NeedsMigration";
public const string FIELD_NAME = "Name";
public static readonly TableSpec instance = new TableSpec();
public string name { get { return TABLE; } }
public string idName { get { return FIELD_ID; } }
@ -38,11 +39,11 @@ namespace FLocal.Common.dataobjects {
}
}
private string _password;
private string password {
private string _passwordHash;
private string passwordHash {
get {
this.LoadIfNotLoaded();
return this._password;
return this._passwordHash;
}
}
@ -56,21 +57,22 @@ namespace FLocal.Common.dataobjects {
protected override void doFromHash(Dictionary<string, string> data) {
this._userId = int.Parse(data[TableSpec.FIELD_USERID]);
this._password = data[TableSpec.FIELD_PASSWORD];
this._passwordHash = data[TableSpec.FIELD_PASSWORDHASH];
this._needsMigration = Util.string2bool(data[TableSpec.FIELD_NEEDSMIGRATION]);
}
private static Dictionary<int, int> userid2id = new Dictionary<int, int>();
public static Account LoadByUser(User user) {
if(!userid2id.ContainsKey(user.id)) {
lock(userid2id) {
if(!userid2id.ContainsKey(user.id)) {
private static Dictionary<string, int> name2id = new Dictionary<string, int>();
public static Account LoadByName(string _name) {
string name = _name.ToLower();
if(!name2id.ContainsKey(name)) {
lock(name2id) {
if(!name2id.ContainsKey(name)) {
List<string> ids = Config.instance.mainConnection.LoadIdsByConditions(
TableSpec.instance,
new ComparisonCondition(
TableSpec.instance.getColumnSpec(TableSpec.FIELD_USERID),
TableSpec.instance.getColumnSpec(TableSpec.FIELD_NAME),
ComparisonType.EQUAL,
user.id.ToString()
name
),
Diapasone.unlimited,
new JoinSpec[0]
@ -78,25 +80,28 @@ namespace FLocal.Common.dataobjects {
if(ids.Count > 1) {
throw new CriticalException("not unique");
} else if(ids.Count == 1) {
userid2id[user.id] = int.Parse(ids[0]);
name2id[name] = int.Parse(ids[0]);
} else {
throw new NotFoundInDBException();
}
}
}
}
return Account.LoadById(userid2id[user.id]);
return Account.LoadById(name2id[name]);
}
private string hashPassword(string password) {
return Util.md5(password + " " + Config.instance.SaltMigration + " " + this.id);
}
public void updatePassword(string newPassword) {
using(ChangeSet changeSet = new ChangeSet()) {
changeSet.Add(
ChangeSetUtil.ApplyChanges(new AbstractChange[] {
new UpdateChange(
TableSpec.instance,
new Dictionary<string, AbstractFieldValue>() {
{
TableSpec.FIELD_PASSWORD,
new ScalarFieldValue(Util.md5(newPassword + " " + Config.instance.SaltMigration + " " + this.id))
TableSpec.FIELD_PASSWORDHASH,
new ScalarFieldValue(this.hashPassword(newPassword))
},
{
TableSpec.FIELD_NEEDSMIGRATION,
@ -105,12 +110,13 @@ namespace FLocal.Common.dataobjects {
},
this.id
)
);
using(Transaction transaction = Config.instance.mainConnection.beginTransaction()) {
changeSet.Apply(transaction);
transaction.Commit();
}
});
}
public static Account tryAuthorize(string name, string password) {
Account account = LoadByName(name);
if(account.passwordHash != account.hashPassword(password)) throw new NotFoundInDBException();
return account;
}
}

@ -0,0 +1,151 @@
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 Session : SqlObject<Session.SessionKey, Session> {
public struct SessionKey : IEquatable<SessionKey> {
private string key;
public static SessionKey Parse(string _key) {
return new SessionKey { key = _key };
}
bool IEquatable<SessionKey>.Equals(SessionKey _key) {
return this.key.Equals(_key.key);
}
public override bool Equals(object obj) {
if(obj == null) return base.Equals(obj);
if(!(obj is SessionKey)) throw new InvalidCastException();
return ((IEquatable<SessionKey>)this).Equals((SessionKey)obj);
}
public override int GetHashCode() {
return this.key.GetHashCode();
}
public override string ToString() {
return this.key;
}
}
public class TableSpec : ISqlObjectTableSpec {
public const string TABLE = "Sessions";
public const string FIELD_ID = FIELD_SESSIONKEY;
public const string FIELD_SESSIONKEY = "SessionKey";
public const string FIELD_ACCOUNTID = "AccountId";
public const string FIELD_LASTACTIVITY = "LastActivity";
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) { throw new NotImplementedException(); }
}
protected override ISqlObjectTableSpec table { get { return TableSpec.instance; } }
private string _sessionKey;
public string sessionKey {
get {
this.LoadIfNotLoaded();
return this._sessionKey;
}
}
private int _accountId;
public int accountId {
get {
this.LoadIfNotLoaded();
return this._accountId;
}
}
public Account account {
get {
return Account.LoadById(this.accountId);
}
}
private DateTime _lastActivity;
public DateTime lastActivity {
get {
this.LoadIfNotLoaded();
return this._lastActivity;
}
}
protected override void doFromHash(Dictionary<string, string> data) {
this._sessionKey = data[TableSpec.FIELD_SESSIONKEY];
this._lastActivity = new DateTime(long.Parse(data[TableSpec.FIELD_LASTACTIVITY]));
this._accountId = int.Parse(data[TableSpec.FIELD_ACCOUNTID]);
}
public void updateLastActivity() {
try {
Config.Transactional(transaction => {
Config.instance.mainConnection.update(
transaction,
TableSpec.instance,
this.id.ToString(),
new Dictionary<string,string>() {
{ TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() }
}
);
});
} finally {
this.ReLoad();
}
}
public static Session create(Account account) {
string key=null;
Config.Transactional(transaction => {
Config.instance.mainConnection.lockTable(transaction, TableSpec.instance);
do {
key = Util.RandomString(32, Util.RandomSource.LETTERS_DIGITS);
} while(Config.instance.mainConnection.LoadByIds(transaction, TableSpec.instance, new List<string>() { key }).Count > 0);
Config.instance.mainConnection.insert(
transaction,
TableSpec.instance,
new Dictionary<string,string>() {
{ TableSpec.FIELD_SESSIONKEY, key },
{ TableSpec.FIELD_ACCOUNTID, account.id.ToString() },
{ TableSpec.FIELD_LASTACTIVITY, DateTime.Now.ToUTCString() },
}
);
});
return Session.LoadById(SessionKey.Parse(key));
}
public void delete() {
Config.Transactional(transaction => Config.instance.mainConnection.delete(transaction, TableSpec.instance, this.id.ToString()));
this.deleteFromRegistry();
}
public XElement exportToXml(UserContext context) {
return new XElement("session",
new XElement("lastActivity", this.lastActivity.ToXml()),
new XElement("sessionKey", this.sessionKey),
this.account.user.exportToXmlForViewing(context)
);
}
public static Session LoadByKey(string sessionKey) {
return LoadById(SessionKey.Parse(sessionKey));
}
}
}

@ -196,8 +196,8 @@ namespace FLocal.Common.dataobjects {
}
public void incrementViewsCounter() {
using(ChangeSet changeSet = new ChangeSet()) {
changeSet.Add(new UpdateChange(
ChangeSetUtil.ApplyChanges(new AbstractChange[] {
new UpdateChange(
TableSpec.instance,
new Dictionary<string,AbstractFieldValue>() {
{
@ -206,12 +206,8 @@ namespace FLocal.Common.dataobjects {
}
},
this.id
));
using(Transaction transaction = Config.instance.mainConnection.beginTransaction()) {
changeSet.Apply(transaction);
transaction.Commit();
}
}
)
});
}
}

@ -65,6 +65,10 @@ namespace FLocal.Core {
}
}
protected void deleteFromRegistry() {
registry.Delete(new TKey[] { this.id });
}
}
}

@ -165,6 +165,15 @@ namespace FLocal.Core {
return sBuilder.ToString();
}
public static bool throws<TException>(Action action) where TException : Exception {
try {
action();
return false;
} catch(TException) {
return true;
}
}
}
}

@ -226,5 +226,9 @@ namespace FLocal.Core {
return decimal.ToInt64(number);
}
public static string ToUTCString(this DateTime date) {
return date.ToUniversalTime().ToString("u");
}
}
}

@ -36,6 +36,10 @@ namespace FLocal.IISHandler {
return new handlers.WrongUrlHandler();
} else {
switch(context.requestParts[1].ToLower()) {
case "login":
return new handlers.request.LoginHandler();
case "logout":
return new handlers.request.LogoutHandler();
case "migrateaccount":
return new handlers.request.MigrateAccountHandler();
default:

@ -58,6 +58,8 @@
<Compile Include="handlers\DebugHandler.cs" />
<Compile Include="handlers\PostHandler.cs" />
<Compile Include="handlers\request\AbstractPostHandler.cs" />
<Compile Include="handlers\request\LoginHandler.cs" />
<Compile Include="handlers\request\LogoutHandler.cs" />
<Compile Include="handlers\request\MigrateAccountHandler.cs" />
<Compile Include="handlers\response\BoardAsThread.cs" />
<Compile Include="handlers\response\LoginHandler.cs" />

@ -4,6 +4,8 @@ using System.Linq;
using System.Text;
using System.Web;
using FLocal.Core;
using FLocal.Common.dataobjects;
using System.Xml.Linq;
namespace FLocal.IISHandler {
class WebContext : Common.UserContext {
@ -57,9 +59,24 @@ namespace FLocal.IISHandler {
public DateTime requestTime;
public Session session;
public WebContext(HttpContext httpcontext) {
this.httpcontext = httpcontext;
this.requestTime = DateTime.Now;
HttpCookie sessionCookie = this.httprequest.Cookies["session"];
if(sessionCookie != null && sessionCookie.Value != null && sessionCookie.Value != "") {
try {
this.session = Session.LoadByKey(sessionCookie.Value);
sessionCookie.Expires = DateTime.Now.AddDays(3);
this.httpresponse.AppendCookie(sessionCookie);
} catch(NotFoundInDBException) {
sessionCookie.Value = "";
sessionCookie.Expires = DateTime.Now.AddDays(-1);
this.httpresponse.AppendCookie(sessionCookie);
//throw; //TODO: remove me!
}
}
}
public string Transform(string templateName, System.Xml.Linq.XDocument data) {
@ -67,5 +84,24 @@ namespace FLocal.IISHandler {
return TemplateEngine.Compile(this.design.fsname + this.config.DirSeparator + templateName, data);
}
public XElement exportSession() {
if(this.session != null) {
return session.exportToXml(this);
} else {
return new XElement("session",
new XElement("notLoggedIn", true)
);
}
}
public HttpCookie createCookie(string name) {
HttpCookie result = new HttpCookie(name);
result.HttpOnly = true;
result.Secure = true;
result.Domain = "." + String.Join(".", this.httprequest.Url.Host.Split(".", StringSplitOptions.RemoveEmptyEntries).Slice(1).ToArray());
result.Path = "/";
return result;
}
}
}

@ -18,6 +18,7 @@ namespace FLocal.IISHandler.handlers {
return new XDocument(
new XElement("root",
new XElement("title", Config.instance.AppInfo),
context.exportSession(),
this.getSpecificData(context)
)
);

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using FLocal.Core;
using FLocal.Common;
namespace FLocal.IISHandler.handlers.request {
@ -12,18 +13,33 @@ namespace FLocal.IISHandler.handlers.request {
get;
}
virtual protected bool shouldBeLoggedIn {
get {
return true;
}
}
virtual protected bool shouldBeGuest {
get {
return false;
}
}
abstract protected XElement[] Do(WebContext context);
private XDocument getData(WebContext context) {
return new XDocument(
new XElement("root",
new XElement("title", Config.instance.AppInfo),
this.Do(context)
this.Do(context),
context.exportSession()
)
);
}
public void Handle(WebContext context) {
if(this.shouldBeGuest && context.session != null) throw new FLocalException("Should be guest");
if(this.shouldBeLoggedIn && context.session == null) throw new FLocalException("Should be anonymous");
context.httpresponse.Write(context.Transform(this.templateName, this.getData(context)));
}

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using FLocal.Common.dataobjects;
using FLocal.Importer;
using System.Text.RegularExpressions;
using FLocal.Core;
using FLocal.Common;
using FLocal.Common.actions;
using System.Web;
namespace FLocal.IISHandler.handlers.request {
class LoginHandler : AbstractPostHandler {
protected override string templateName {
get {
return "result/Login.xslt";
}
}
protected override bool shouldBeLoggedIn {
get { return false; }
}
protected override bool shouldBeGuest {
get { return true; }
}
protected override XElement[] Do(WebContext context) {
Account account = Account.tryAuthorize(context.httprequest.Form["name"], context.httprequest.Form["password"]);
Session session = Session.create(account);
HttpCookie sessionCookie = context.createCookie("session");
sessionCookie.Value = session.sessionKey;
sessionCookie.Expires = DateTime.Now.AddDays(3);
context.httpresponse.AppendCookie(sessionCookie);
context.session = session;
return new XElement[0];
}
}
}

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using FLocal.Common.dataobjects;
using FLocal.Importer;
using System.Text.RegularExpressions;
using FLocal.Core;
using FLocal.Common;
using FLocal.Common.actions;
using System.Web;
namespace FLocal.IISHandler.handlers.request {
class LogoutHandler : AbstractPostHandler {
protected override string templateName {
get {
return "result/Logout.xslt";
}
}
protected override XElement[] Do(WebContext context) {
if(context.session.id.ToString().ToLower() != context.httprequest.QueryString["sessionKey"].ToLower()) {
throw new FLocalException("Wrong session id");
}
context.session.delete();
HttpCookie sessionCookie = context.createCookie("session");
sessionCookie.Value = "";
sessionCookie.Expires = DateTime.Now.AddDays(-1);
context.httpresponse.AppendCookie(sessionCookie);
context.session = null;
return new XElement[0];
}
}
}

@ -19,6 +19,14 @@ namespace FLocal.IISHandler.handlers.request {
}
}
protected override bool shouldBeLoggedIn {
get { return false; }
}
protected override bool shouldBeGuest {
get { return true; }
}
protected override XElement[] Do(WebContext context) {
Account account = Account.LoadById(int.Parse(context.httprequest.Form["accountId"]));
if(!account.needsMigration) throw new FLocalException("Already migrated");

@ -26,8 +26,7 @@ namespace FLocal.IISHandler.handlers.response {
}
username = context.requestParts[1];
}
User user = User.LoadByName(username);
Account account = Account.LoadByUser(user);
Account account = Account.LoadByName(username);
if(!account.needsMigration) throw new FLocalException("Already migrated");
string key = Util.RandomString(8, Util.RandomSource.LETTERS_DIGITS);
return new XElement[] {

@ -251,25 +251,37 @@ namespace FLocal.MySQLConnector {
lock(transaction) {
using(DbCommand command = transaction.sqlconnection.CreateCommand()) {
List<string> updates = new List<string>();
List<string> updatesPlaceholders = new List<string>();
ParamsHolder paramsholder = new ParamsHolder();
foreach(KeyValuePair<string, string> kvp in data) {
updates.Add(this.traits.escapeIdentifier(kvp.Key) + " = " + this.traits.markParam(paramsholder.Add(kvp.Value)));
updates.Add(this.traits.escapeIdentifier(kvp.Key));
updatesPlaceholders.Add(this.traits.markParam(paramsholder.Add(kvp.Value)));
}
command.Transaction = transaction.sqltransaction;
command.CommandType = System.Data.CommandType.Text;
command.CommandText = "INSERT INTO " + table.compile(this.traits) + " SET " + String.Join(", ", updates.ToArray());
command.CommandText = "INSERT INTO " + table.compile(this.traits) + " (" + String.Join(", ", updates.ToArray()) + ") VALUES (" + String.Join(", ", updatesPlaceholders.ToArray()) + ")";
foreach(KeyValuePair<string, string> kvp in paramsholder.data) {
command.AddParameter(kvp.Key, kvp.Value);
}
command.ExecuteNonQuery();
if(data.ContainsKey(table.idName)) return data[table.idName];
return this.traits.LastInsertId(command, table).ToString();
}
}
}
public void delete(FLocal.Core.DB.Transaction transaction, ITableSpec table, string id) {
throw new NotImplementedException();
public void delete(FLocal.Core.DB.Transaction _transaction, ITableSpec table, string id) {
Transaction transaction = (Transaction)_transaction;
lock(transaction) {
using(DbCommand command = transaction.sqlconnection.CreateCommand()) {
command.Transaction = transaction.sqltransaction;
command.CommandType = System.Data.CommandType.Text;
command.CommandText = "DELETE FROM " + table.compile(traits) + " where " + table.getIdSpec().compile(this.traits) + " = " + this.traits.markParam("id");
command.AddParameter("id", id);
command.ExecuteNonQuery();
}
}
}
public void Dispose() {

@ -22,7 +22,14 @@
</tr>
<tr class="lighttable">
<td width="45%" class="small" valign="top">
<xsl:text>Вы вошли в форум как summersun</xsl:text>
<xsl:choose>
<xsl:when test="session/user">
<xsl:text>Âû âîøëè â ôîðóì êàê </xsl:text><xsl:value-of select="session/user/name"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>Âû íå âîøëè â ôîðóì</xsl:text>
</xsl:otherwise>
</xsl:choose>
<br />
<xsl:text>18983 Зарегистрированных пользователей.</xsl:text>
<br />

@ -21,7 +21,7 @@
<td class="lighttable">
<form method="post" action="/do/Login/">
<xsl:text>Ëîãèí</xsl:text><br />
<input type="text" name="username" class="formboxes" /><br/>
<input type="text" name="name" class="formboxes" /><br/>
<xsl:text>Ïàðîëü</xsl:text><br/>
<input type="password" name="password" class="formboxes" /><br/>
<input type="submit" name="buttlogin" value="Âîéòè!" class="buttons" />

@ -37,7 +37,14 @@
<table width="95%" align="center" cellpadding="1" cellspacing="1" class="tablesurround">
<tr>
<td>
Hello, summersun (External IP).
<xsl:choose>
<xsl:when test="session/user">
<xsl:text>Hello, </xsl:text><xsl:value-of select="session/user/name"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>Hello, Guest</xsl:text>
</xsl:otherwise>
</xsl:choose>
<table cellpadding="1" cellspacing="0" width="100%" class="tableborders" height="100%">
<tr class="menubar">
<td align="left" width="50%" id="decor">

@ -38,14 +38,25 @@
<xsl:text> | </xsl:text>
<a target="_top">Ďîčńę</a>
<xsl:text> | </xsl:text>
<!--a target="_top">My Home</a-->
<a href="/Login/" target="_top">Âõîä</a>
<a target="_top">My Home</a>
<xsl:text> | </xsl:text>
<a target="_top">
<xsl:if test="session/notLoggedIn">
<xsl:attribute name="href">/Login/</xsl:attribute>
</xsl:if>
<xsl:text>Âõîä</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a target="_top">Ęňî â îíëŕéíĺ</a>
<xsl:text> | </xsl:text>
<a target="_top">FAQ</a>
<xsl:text> | </xsl:text>
<a target="_top">Âûõîä</a>
<a target="_top">
<xsl:if test="session/sessionKey">
<xsl:attribute name="href">/do/Logout/?sessionKey=<xsl:value-of select="session/sessionKey"/></xsl:attribute>
</xsl:if>
<xsl:text>Âûõîä</xsl:text>
</a>
<xsl:text> | </xsl:text>
<a target="_top">Ďîëüçîâŕňĺëč</a>
</td>

@ -0,0 +1,25 @@
<?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="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>
<tr>
<td class="lighttable">
<xsl:text>Àâòîðèçàöèÿ ïðîøëà óñïåøíî</xsl:text>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>

@ -0,0 +1,25 @@
<?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="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>
<tr>
<td class="lighttable">
<xsl:text>Ñåññèÿ óäàëåíà</xsl:text>
</td>
</tr>
</table>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
Loading…
Cancel
Save