Avatars implemented; avatars importing implemented; ShallerConnector refactored

main
Inga 🏳‍🌈 15 years ago
parent e9d03cc18b
commit d6efb7e789
  1. 2
      Builder/IISMainHandler/build.txt
  2. 2
      Builder/IISUploadHandler/build.txt
  3. 2
      Common/actions/UpdateChange.cs
  4. 8
      Common/dataobjects/Upload.cs
  5. 21
      Common/dataobjects/User.cs
  6. 5
      ImportConsole/Program.cs
  7. 35
      ImportConsole/UsersImporter.cs
  8. 17
      Importer/FileInfo.cs
  9. 1
      Importer/Importer.csproj
  10. 48
      Importer/ShallerConnector.cs
  11. 24
      Importer/ShallerGateway.cs
  12. BIN
      static/images/noavatar.gif
  13. 11
      templates/Full/UserInfo.xslt
  14. 6
      templates/Full/elems/UserInfoBar.xslt

@ -5,7 +5,7 @@ using System.Text;
using FLocal.Core.DB; using FLocal.Core.DB;
namespace FLocal.Common.actions { namespace FLocal.Common.actions {
class UpdateChange : AbstractChange { public class UpdateChange : AbstractChange {
private readonly int id; private readonly int id;

@ -67,8 +67,8 @@ namespace FLocal.Common.dataobjects {
} }
} }
private int? _userId; private int _userId;
public int? userId { public int userId {
get { get {
this.LoadIfNotLoaded(); this.LoadIfNotLoaded();
return this._userId; return this._userId;
@ -76,7 +76,7 @@ namespace FLocal.Common.dataobjects {
} }
public User user { public User user {
get { get {
return User.LoadById(this.userId.Value); return User.LoadById(this.userId);
} }
} }
@ -86,7 +86,7 @@ namespace FLocal.Common.dataobjects {
this._size = int.Parse(data[TableSpec.FIELD_SIZE]); this._size = int.Parse(data[TableSpec.FIELD_SIZE]);
this._filename = data[TableSpec.FIELD_FILENAME]; this._filename = data[TableSpec.FIELD_FILENAME];
this._uploadDate = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_UPLOADDATE]).Value; this._uploadDate = Util.ParseDateTimeFromTimestamp(data[TableSpec.FIELD_UPLOADDATE]).Value;
this._userId = Util.ParseInt(data[TableSpec.FIELD_USERID]); this._userId = int.Parse(data[TableSpec.FIELD_USERID]);
} }
public XElement exportToXml(UserContext context) { public XElement exportToXml(UserContext context) {

@ -22,6 +22,7 @@ namespace FLocal.Common.dataobjects {
public const string FIELD_USERGROUPID = "UserGroupId"; public const string FIELD_USERGROUPID = "UserGroupId";
public const string FIELD_SHOWPOSTSTOUSERS = "ShowPostsToUsers"; public const string FIELD_SHOWPOSTSTOUSERS = "ShowPostsToUsers";
public const string FIELD_BIOGRAPHY = "Biography"; public const string FIELD_BIOGRAPHY = "Biography";
public const string FIELD_AVATARID = "AvatarId";
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; } }
@ -102,6 +103,19 @@ namespace FLocal.Common.dataobjects {
} }
} }
private int? _avatarId;
public int? avatarId {
get {
this.LoadIfNotLoaded();
return this._avatarId;
}
}
public Upload avatar {
get {
return Upload.LoadById(this.avatarId.Value);
}
}
private static Dictionary<string, int> id2user = new Dictionary<string,int>(); private static Dictionary<string, int> id2user = new Dictionary<string,int>();
public static User LoadByName(string name) { public static User LoadByName(string name) {
if(!id2user.ContainsKey(name)) { if(!id2user.ContainsKey(name)) {
@ -140,10 +154,11 @@ namespace FLocal.Common.dataobjects {
this._userGroupId = int.Parse(data[TableSpec.FIELD_USERGROUPID]); this._userGroupId = int.Parse(data[TableSpec.FIELD_USERGROUPID]);
this._showPostsToUsers = data[TableSpec.FIELD_SHOWPOSTSTOUSERS]; this._showPostsToUsers = data[TableSpec.FIELD_SHOWPOSTSTOUSERS];
this._biography = data[TableSpec.FIELD_BIOGRAPHY]; this._biography = data[TableSpec.FIELD_BIOGRAPHY];
this._avatarId = Util.ParseInt(data[TableSpec.FIELD_AVATARID]);
} }
public XElement exportToXmlForViewing(UserContext context) { public XElement exportToXmlForViewing(UserContext context) {
return new XElement("user", XElement result = new XElement("user",
new XElement("id", this.id), new XElement("id", this.id),
new XElement("regDate", this.regDate.ToXml()), new XElement("regDate", this.regDate.ToXml()),
new XElement("totalPosts", this.totalPosts), new XElement("totalPosts", this.totalPosts),
@ -154,6 +169,10 @@ namespace FLocal.Common.dataobjects {
new XElement("userGroupId", this.userGroupId), new XElement("userGroupId", this.userGroupId),
new XElement("showPostsToUsers", this.showPostsToUsers) new XElement("showPostsToUsers", this.showPostsToUsers)
); );
if(this.avatarId.HasValue) {
result.Add(new XElement("avatar", this.avatarId));
}
return result;
} }
public static IEnumerable<User> getUsers(Diapasone diapasone, UserContext context) { public static IEnumerable<User> getUsers(Diapasone diapasone, UserContext context) {

@ -22,7 +22,12 @@ namespace FLocal.ImportConsole {
[Action] [Action]
public static void ImportUsers() { public static void ImportUsers() {
try {
UsersImporter.ImportUsers(); UsersImporter.ImportUsers();
} catch(Exception e) {
Console.WriteLine(e.GetType().FullName + ": " + e.Message);
Console.WriteLine(e.StackTrace);
}
} }
[Action] [Action]

@ -4,6 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using FLocal.Core; using FLocal.Core;
using FLocal.Importer; using FLocal.Importer;
using FLocal.Common;
using FLocal.Common.dataobjects; using FLocal.Common.dataobjects;
using FLocal.Common.actions; using FLocal.Common.actions;
@ -15,11 +16,12 @@ namespace FLocal.ImportConsole {
for(int i=1; i<800; i++) { for(int i=1; i<800; i++) {
Console.Write("[" + i + "]"); Console.Write("[" + i + "]");
foreach(string userName in ShallerGateway.getUserNames(i)) { foreach(string userName in ShallerGateway.getUserNames(i)) {
Dictionary<string, string> userData = ShallerGateway.getUserInfo(userName);
User user;
try { try {
User.LoadByName(userName); user = User.LoadByName(userName);
Console.Write("-"); Console.Write("-");
} catch(NotFoundInDBException) { } catch(NotFoundInDBException) {
Dictionary<string, string> userData = ShallerGateway.getUserInfo(userName);
AbstractChange addUser = new InsertChange( AbstractChange addUser = new InsertChange(
User.TableSpec.instance, User.TableSpec.instance,
new Dictionary<string, AbstractFieldValue>() { new Dictionary<string, AbstractFieldValue>() {
@ -44,8 +46,37 @@ namespace FLocal.ImportConsole {
} }
); );
ChangeSetUtil.ApplyChanges(addUser, addAccount); ChangeSetUtil.ApplyChanges(addUser, addAccount);
user = User.LoadById(addUser.getId().Value);
Console.Write("."); Console.Write(".");
} }
if(!user.avatarId.HasValue && userData["avatar"] != null && userData["avatar"] != "") {
try {
Upload avatar;
string[] nameParts = userData["avatar"].Split('.');
if(nameParts.Length != 2) throw new FLocalException("wrong avatar filename '" + userData["avatar"] + "'");
int oldAvatarId = int.Parse(nameParts[0]);
FileInfo avatarInfo = ShallerGateway.getFileInfo("user/" + userData["avatar"]);
try {
avatar = UploadManager.UploadFile(avatarInfo.dataStream, avatarInfo.fileName, avatarInfo.lastModified, user, 900000 + oldAvatarId);
} catch(UploadManager.AlreadyUploadedException e) {
avatar = Upload.LoadById(e.uploadId);
}
ChangeSetUtil.ApplyChanges(
new UpdateChange(
User.TableSpec.instance,
new Dictionary<string,AbstractFieldValue> {
{ User.TableSpec.FIELD_AVATARID, new ScalarFieldValue(avatar.id.ToString()) }
},
user.id
)
);
Console.Write("a");
} catch(Exception e) {
Console.Write("!{" + user.id + "}{" + e.Message + "}!");
}
}
} }
} }
} }

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace FLocal.Importer {
public struct FileInfo {
public Stream dataStream;
public string filePath;
public string fileName;
public long fileSize;
public DateTime lastModified;
}
}

@ -50,6 +50,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ShallerConnector.cs" /> <Compile Include="ShallerConnector.cs" />
<Compile Include="ShallerGateway.cs" /> <Compile Include="ShallerGateway.cs" />
<Compile Include="FileInfo.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

@ -10,17 +10,17 @@ using System.IO;
namespace FLocal.Importer { namespace FLocal.Importer {
class ShallerConnector { class ShallerConnector {
public static Encoding encoding { public static readonly Encoding encoding = Encoding.GetEncoding(1251);
get { private const int BUFFER = 1024;
return Encoding.GetEncoding(1251);
}
}
public static string getPageContent(string requestUrl, Dictionary<string, string> postData, CookieContainer cookies) { public static FileInfo getPageInfo(string requestUrl, Dictionary<string, string> postData, CookieContainer cookies) {
string baseUrl = ConfigurationManager.AppSettings["Importer_BaseUrl"]; string baseUrl = ConfigurationManager.AppSettings["Importer_BaseUrl"];
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(baseUrl + requestUrl); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(baseUrl + requestUrl);
request.KeepAlive = true; request.KeepAlive = true;
request.CookieContainer = cookies; request.CookieContainer = cookies;
request.ReadWriteTimeout = 3*1000;
request.Timeout = 3*1000;
request.Accept = "*";
if(postData.Count < 1) { if(postData.Count < 1) {
request.Method = "GET"; request.Method = "GET";
} else { } else {
@ -42,10 +42,40 @@ namespace FLocal.Importer {
stream.Write(postBytes, 0, postBytes.Length); stream.Write(postBytes, 0, postBytes.Length);
stream.Close(); stream.Close();
} }
request.UserAgent = "ShallerConnector v0.1"; request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; FDM; .NET4.0C; .NET4.0E)";
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
cookies.Add(response.Cookies); cookies.Add(response.Cookies);
using(StreamReader reader = new StreamReader(response.GetResponseStream(), encoding)) {
byte[] content;
using(Stream responseStream = response.GetResponseStream()) {
using(MemoryStream memoryStream = new MemoryStream()) {
byte[] buffer = new byte[BUFFER];
int bytes;
while((bytes = responseStream.Read(buffer, 0, BUFFER)) > 0) {
memoryStream.Write(buffer, 0, bytes);
}
content = memoryStream.ToArray();
}
}
if(response.ContentLength > 0 && content.Length != response.ContentLength) {
throw new ApplicationException("incomplete file (expected " + response.ContentLength + ", got " + content.Length + ")");
}
FileInfo result = new FileInfo {
dataStream = new MemoryStream(content),
fileName = response.ResponseUri.Segments.Last(),
filePath = response.ResponseUri.AbsolutePath,
fileSize = response.ContentLength,
lastModified = response.LastModified,
};
response.Close();
return result;
}
}
public static string getPageContent(string requestUrl, Dictionary<string, string> postData, CookieContainer cookies) {
FileInfo info = getPageInfo(requestUrl, postData, cookies);
using(StreamReader reader = new StreamReader(info.dataStream, encoding)) {
return reader.ReadToEnd(); return reader.ReadToEnd();
} }
} }

@ -3,7 +3,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Net;
using System.Web; using System.Web;
using System.IO;
namespace FLocal.Importer { namespace FLocal.Importer {
public class ShallerGateway { public class ShallerGateway {
@ -25,6 +27,8 @@ namespace FLocal.Importer {
return regexInfoCache[caption]; return regexInfoCache[caption];
} }
private static Regex avatarRegex = new Regex("<img\\s+src=\"/user/(\\d+\\.\\w+)\"\\s+alt=\"Picture\"\\s+width=\"\\d+\"\\s+height=\"\\d+\"\\s*/>", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
private static Dictionary<string, string> userImportStructure { private static Dictionary<string, string> userImportStructure {
get { get {
return new Dictionary<string,string>() { return new Dictionary<string,string>() {
@ -39,10 +43,12 @@ namespace FLocal.Importer {
public static Dictionary<string, string> getUserInfo(string userName) { public static Dictionary<string, string> getUserInfo(string userName) {
string content = getUserInfoAsString(userName); string content = getUserInfoAsString(userName);
return userImportStructure.ToDictionary<KeyValuePair<string, string>, string, string>( Dictionary<string, string> result = userImportStructure.ToDictionary<KeyValuePair<string, string>, string, string>(
kvp => kvp.Key, kvp => kvp.Key,
kvp => HttpUtility.HtmlDecode(getInfoRegexByCaption(kvp.Value).Match(content).Groups[1].Value).Trim() kvp => HttpUtility.HtmlDecode(getInfoRegexByCaption(kvp.Value).Match(content).Groups[1].Value).Trim()
); );
result["avatar"] = avatarRegex.Match(content).Groups[1].Value;
return result;
} }
public static IEnumerable<string> getUserNames(int pageNum) { public static IEnumerable<string> getUserNames(int pageNum) {
@ -56,5 +62,21 @@ namespace FLocal.Importer {
return result; return result;
} }
private static FileInfo getFileInfo(string path, int attempt) {
try {
return ShallerConnector.getPageInfo(path, new Dictionary<string,string>(), new CookieContainer());
} catch(Exception) {
if(attempt > 3) {
throw;
} else {
return getFileInfo(path, attempt + 1);
}
}
}
public static FileInfo getFileInfo(string path) {
return getFileInfo(path, 1);
}
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

@ -30,7 +30,16 @@
<xsl:text>Not implemented</xsl:text> <xsl:text>Not implemented</xsl:text>
</td> </td>
<td align="right" valign="top" rowspan="11"> <td align="right" valign="top" rowspan="11">
<img src="/user/14291.png" alt="Picture" width="80" height="80" /> <img alt="Picture" width="80" height="80">
<xsl:choose>
<xsl:when test="user/avatar">
<xsl:attribute name="src">/Upload/Item/<xsl:value-of select="user/avatar"/>/</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="src">/static/images/noavatar.gif</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</img>
</td> </td>
</tr> </tr>
<tr> <tr>

@ -26,11 +26,15 @@
<i><font color="red"></font></i> <i><font color="red"></font></i>
</td> </td>
</tr> </tr>
<xsl:if test="avatar">
<tr> <tr>
<td class="small"> <td class="small">
<img src="/user/7901.jpg" alt="" width="80" height="80" /> <img alt="" width="80" height="80">
<xsl:attribute name="src">/Upload/Item/<xsl:value-of select="avatar"/>/</xsl:attribute>
</img>
</td> </td>
</tr> </tr>
</xsl:if>
<tr> <tr>
<td class="small"> <td class="small">
<xsl:text>Ðåã.: </xsl:text> <xsl:text>Ðåã.: </xsl:text>

Loading…
Cancel
Save