Added json serialization of Pithos version timestamp dates in PithosDateTimeConverter.cs
Replaced redundant ObjectInfo properties with Json named attributes
Build intentionally left broken, moving code to another machine.
Next step, create the File Properties window
// </copyright>
// -----------------------------------------------------------------------
+using System.Collections.Concurrent;
+using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using Caliburn.Micro;
+using Pithos.Interfaces;
namespace Pithos.Client.WPF
{
[Export(typeof(FilePropertiesViewModel))]
public class FilePropertiesViewModel : Screen, IShell
{
- public FilePropertiesViewModel()
+
+ public FilePropertiesViewModel(ShellViewModel shell,ObjectInfo pithosFile)
+ {
+ Shell = shell;
+ PithosFile = pithosFile;
+ }
+
+ protected ShellViewModel Shell { get; set; }
+
+ private ObjectInfo _pithosFile;
+ public ObjectInfo PithosFile
+ {
+ get { return _pithosFile; }
+ set
+ {
+ _pithosFile = value;
+
+ NotifyOfPropertyChange(()=>PithosFile);
+ }
+ }
+
+ private ObservableConcurrentDictionary<string, string> _permissions;
+ public ObservableConcurrentDictionary<string, string> Permissions
+ {
+ get { return _permissions; }
+ set
+ {
+ _permissions = value;
+ }
+ }
+
+
+ public void Refresh()
+ {
+ PithosFile=Shell.RetrieveObjectInfo(PithosFile);
+ }
+
+ public override void CanClose(Action<bool> callback)
+ {
+ base.CanClose(callback);
+ }
+
+ public void SaveChanges()
+ {
+ DoSave();
+ TryClose(true);
+ }
+
+ public void RejectChanges()
+ {
+ TryClose(false);
+ }
+
+ public void ApplyChanges()
+ {
+ DoSave();
+ }
+
+ private void DoSave()
{
}
+
}
}
<Reference Include="NHibernate.Search, Version=0.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\Libraries\NHibernate.Search.dll</HintPath>
</Reference>
+ <Reference Include="ServiceStack.Text">
+ <HintPath>..\packages\ServiceStack.Text.2.27\lib\net35\ServiceStack.Text.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Compile Include="WorkflowState.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\Libraries\Json40r2\Source\Src\Newtonsoft.Json\Newtonsoft.Json.csproj">
- <Project>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</Project>
- <Name>Newtonsoft.Json</Name>
- </ProjectReference>
<ProjectReference Include="..\Libraries\ParallelExtensionsExtras\ParallelExtensionsExtras.csproj">
<Project>{C45218F8-09E7-4F57-85BC-5D8D2AC736A3}</Project>
<Name>ParallelExtensionsExtras</Name>
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Windows7APICodePack" version="1.0.0.0" />
- <package id="Castle.Core" version="2.5.2" />
- <package id="Castle.Components.Validator" version="2.5.0" />
<package id="Castle.Activerecord" version="3.0.0.1" />
+ <package id="Castle.Components.Validator" version="2.5.0" />
+ <package id="Castle.Core" version="2.5.2" />
<package id="Iesi.Collections" version="3.1.0.4000" />
<package id="NHibernate" version="3.1.0.4000" />
<package id="NHibernate.Castle" version="3.1.0.4000" />
+ <package id="ServiceStack.Text" version="2.27" />
+ <package id="Windows7APICodePack" version="1.0.0.0" />
</packages>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+using System.Dynamic;
using System.Globalization;
using System.IO;
+using System.Text.RegularExpressions;
+using Newtonsoft.Json;
namespace Pithos.Interfaces
{
- public class ObjectInfo
+ public class ObjectInfo:DynamicObject
{
- private List<string> _knownContainers= new List<string>{"trash"};
+ private readonly List<string> _knownContainers= new List<string>{"trash"};
public string Name { get; set; }
public string Hash { get; set; }
public long Bytes { get; set; }
ExtractKnownExtensions();
}
}
-
- private long? _version;
- public long? Version
- {
- get { return _version; }
- set { _version = value; }
- }
- //Alias for version, for Json deserialization purposes
- public long? X_Object_Version
+
+ private Dictionary<string, string> _permissions=new Dictionary<string, string>();
+ [JsonProperty("x_object_sharing")]
+ [JsonConverter(typeof(PermissionConverter))]
+ public Dictionary<string, string> Permissions
{
- get { return _version; }
- set { _version = value; }
+ get { return _permissions; }
+ set
+ {
+ _permissions = value;
+ }
}
- private string _allowedTo;
- public string AllowedTo
- {
- get { return _allowedTo; }
- set { _allowedTo = value; }
- }
+ /// <summary>
+ /// Version number
+ /// </summary>
+ [JsonProperty("x_object_version")]
+ public long? Version { get; set; }
- //Object permissions for Json deserialization, can be Read or Write
-
- public string x_object_allowed_to
- {
- get { return _allowedTo; }
- set { _allowedTo = value; }
- }
- //Object permissions for HEAD deserialization, can be Read or Write
- public string X_Object_Allowed_To
- {
- get { return _allowedTo; }
- set { _allowedTo = value; }
- }
+ /// <summary>
+ /// Shared object permissions can be Read or Write
+ /// </summary>
+ [JsonProperty("x_object_allowed_to")]
+ public string AllowedTo { get; set; }
- //Alias for VersionTimestamp, for Json deserialization purposes
- //The x_object_version_timestamp is a unix timestamp.
- public double? X_Object_Version_Timestamp
- {
- get
- {
- if (_versionTimestamp.HasValue)
- return (_versionTimestamp.Value-_epoch).TotalSeconds;
- return null;
- }
- set
- {
- if (value.HasValue)
- {
- _versionTimestamp = _epoch.AddSeconds(value.Value);
- }
- else
- {
- _versionTimestamp = null;
- }
- }
- }
- private DateTime? _versionTimestamp;
- public DateTime? VersionTimestamp
- {
- get { return _versionTimestamp; }
- set { _versionTimestamp = value; }
- }
+ /// <summary>
+ /// Version timestamp
+ /// </summary>
+ [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
+ public DateTime? VersionTimestamp { get; set; }
- public string ModifiedBy
- {
- get{ return _modifiedBy; }
- set{ _modifiedBy = value; }
- }
+ [JsonProperty("X_Object_Modified_By")]
+ public string ModifiedBy { get; set; }
- //Alias for ModifiedBy, for Json deserialization purposes
- public string X_Object_Modified_By
- {
- get{ return _modifiedBy; }
- set{ _modifiedBy = value; }
- }
public Stream Stream { get; set; }
Last_Modified = DateTime.MinValue
};
- private string _modifiedBy;
- private DateTime _epoch = new DateTime(1970, 1, 1);
-
-
-
public string RelativeUrlToFilePath(string currentAccount)
{
- if (this.Name==null)
+ if (Name==null)
throw new InvalidOperationException("Name can't be null");
if (String.IsNullOrWhiteSpace(currentAccount))
throw new ArgumentNullException("currentAccount");
if (this == Empty)
return String.Empty;
- var unescaped = Uri.UnescapeDataString(this.Name);
+ var unescaped = Uri.UnescapeDataString(Name);
var path = unescaped.Replace("/", "\\");
var pathParts=new Stack<string>();
pathParts.Push(path);
return finalPath;
}
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ if (binder.Name.StartsWith("x_object_meta"))
+ {
+ Tags[binder.Name] = value.ToString();
+ }
+ return false;
+ }
+
}
}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Pithos.Interfaces
+{
+ public class PermissionConverter:JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ var dict = (Dictionary<string, string>) value;
+ var pairs = from pair in dict
+ group pair by pair.Value into g
+ select new {Permission=g.Key,Names=String.Join(",", g.SelectMany(p=>p.Key))};
+
+ var result=pairs.Aggregate(new StringBuilder(),
+ (builder, perm) =>
+ builder.AppendFormat("{0}={1};", perm.Permission, perm.Names));
+
+ var finalValue = result.ToString();
+ writer.WriteValue(finalValue);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+
+ var permissionString= (string) reader.Value;
+
+ var permissions = (from permisson in permissionString.Split(';')
+ let parsed = permisson.Split('=')
+ from account in parsed[1].Split(',')
+ select new { account, Permission = parsed[0] })
+ .ToDictionary(perm=>perm.account,perm=>perm.Permission);
+
+ return permissions;
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return (objectType==typeof(Dictionary<string,string>));
+ }
+ }
+}
\ No newline at end of file
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
+ <Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Compile Include="AccountSettings.cs" />
<Compile Include="IPithosSettings.cs" />
<Compile Include="IStatusChecker.cs" />
+ <Compile Include="PermissionConverter.cs" />
+ <Compile Include="PithosDateTimeConverter.cs">
+ <SubType>Code</SubType>
+ </Compile>
<Compile Include="KnownExtensions.cs" />
<Compile Include="ObjectInfo.cs" />
<Compile Include="PithosSettingsData.cs" />
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Libraries\Json40r2\Source\Src\Newtonsoft.Json\Newtonsoft.Json.csproj">
+ <Project>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</Project>
+ <Name>Newtonsoft.Json</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
--- /dev/null
+using System;
+using System.Globalization;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json.Utilities;
+
+namespace Pithos.Interfaces
+{
+ /// <summary>
+ /// Converts a <see cref="DateTime"/> to and from a JavaScript date constructor (e.g. new Date(52231943)).
+ /// </summary>
+ public class PithosDateTimeConverter : DateTimeConverterBase
+ {
+ private DateTime _epoch = new DateTime(1970, 1, 1,0,0,0,DateTimeKind.Utc);
+
+ /// <summary>
+ /// Writes the JSON representation of the object.
+ /// </summary>
+ /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
+ /// <param name="value">The value.</param>
+ /// <param name="serializer">The calling serializer.</param>
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ double seconds;
+
+ if (value is DateTime)
+ {
+ DateTime dateTime = (DateTime)value;
+ DateTime utcDateTime = dateTime.ToUniversalTime();
+ seconds = (utcDateTime - _epoch).TotalSeconds; ;
+ }
+#if !PocketPC && !NET20
+ else if (value is DateTimeOffset)
+ {
+ DateTimeOffset dateTimeOffset = (DateTimeOffset)value;
+ DateTimeOffset utcDateTimeOffset = dateTimeOffset.ToUniversalTime();
+ seconds= (utcDateTimeOffset.UtcDateTime - _epoch).TotalSeconds;
+ }
+#endif
+ else
+ {
+ throw new Exception("Expected date object value.");
+ }
+
+ writer.WriteValue(seconds);
+ }
+
+ /// <summary>
+ /// Reads the JSON representation of the object.
+ /// </summary>
+ /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
+ /// <param name="objectType">Type of the object.</param>
+ /// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
+ /// <param name="serializer">The calling serializer.</param>
+ /// <returns>The object value.</returns>
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ Type t = (IsNullableType(objectType))
+ ? Nullable.GetUnderlyingType(objectType)
+ : objectType;
+
+ if (reader.TokenType == JsonToken.Null)
+ {
+ if (!IsNullableType(objectType))
+ throw new Exception(String.Format("Cannot convert null value to {0}.",objectType));
+
+ return null;
+ }
+
+ var seconds = double.Parse((string)reader.Value,CultureInfo.InvariantCulture);
+
+ DateTime d = _epoch.AddSeconds(seconds);
+
+
+#if !PocketPC && !NET20
+ if (t == typeof(DateTimeOffset))
+ return new DateTimeOffset(d);
+#endif
+
+ return d;
+ }
+
+ public static bool IsNullableType(Type t)
+ {
+ if (t== null)
+ throw new ArgumentNullException("t");
+
+ return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
+ }
+ }
+}
\ No newline at end of file
using System.Linq;
using System.Text;
using NUnit.Framework;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using Pithos.Interfaces;
namespace Pithos.Network.Test
Assert.AreEqual(@"somefolder\file1.txt", path1);
}
+
+
+ [Test]
+ public void TestDeserialization()
+ {
+ var content="[{\"x_object_meta_smoe\": \"true\", \"hash\": \"0f5fbd63a50cb19c13eb111d3c3a7e40\", \"name\": \"wlsetup-web.exe\", \"x_object_meta_moe\": \"true\", \"x_object_meta_joe\": \"true\", \"x_object_sharing\": \"read=lumumba;write=pkanavos,fufutos\", \"x_object_version_timestamp\": \"1319572542.348810\", \"bytes\": 1286504, \"last_modified\": \"2011-10-25T19:55:42.348810+00:00\", \"content_type\": \"application/octet-stream\", \"x_object_version\": 22075, \"x_object_modified_by\": \"890329@vho.grnet.gr\"}]";
+ var infos=JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+ var info = infos[0];
+
+ Assert.IsNotEmpty(info.Tags);
+ Assert.IsNotEmpty(info.Permissions);
+ Assert.AreEqual(3,info.Permissions.Count);
+ Assert.IsTrue(info.Permissions["pkanavos"]=="write");
+ Assert.IsTrue(info.Permissions["lumumba"] == "read");
+ Assert.IsTrue(info.Permissions["fufutos"] == "write");
+ Assert.IsTrue(info.Tags.ContainsKey("x_object_meta_smoe"));
+ }
+
+ [Test]
+ public void ParseInfo()
+ {
+
+ var account = "890329@vho.grnet.gr";
+ var apiKey = "pvCJNuf28+K2UjWnSTlfVQ==";
+
+ var client = new CloudFilesClient(account, apiKey)
+ {
+ AuthenticationUrl = @"https://pithos.dev.grnet.gr",
+ UsePithos = true
+ };
+ client.Authenticate();
+ var fileName = @"wlsetup-web.exe";
+
+ var infos=client.ListObjects(account, "pithos");
+ var info = infos.First(i=> i.Name == fileName);
+ Assert.IsNotEmpty(info.Tags);
+
+ }
}
}
using System.IO;
using System.Text;
using System.Threading.Tasks;
-using Newtonsoft.Json;
+
using System.Linq;
+using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Pithos.Network