diff --git a/SeafClient.Tests/ShareLinks.cs b/SeafClient.Tests/ShareLinks.cs new file mode 100644 index 0000000..2ec27f9 --- /dev/null +++ b/SeafClient.Tests/ShareLinks.cs @@ -0,0 +1,58 @@ +using System; +using System.Globalization; +using System.Net; +using System.Net.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SeafClient.Requests.Files; +using SeafClient.Types; + +namespace SeafClient.Tests +{ + [TestClass] + public class ShareLinks : SeafTestClassBase + { + [TestMethod] + public void Test_GetShareLink_Success() + { + var request = new CreateShareLinkRequest(FakeToken, FakeRepoId, "/"); + + var message = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(@"{ + ""username"": ""lian@lian.com"", + ""repo_id"": ""c474a093-19dc-4ddf-b0b0-72b33214ba33"", + ""ctime"": ""2017-04-01T02:35:57+00:00"", + ""expire_date"": """", + ""token"": ""6afa667ff2c248378b70"", + ""view_cnt"": 0, + ""link"": ""https://cloud.seafile.com/d/6afa667ff2c248378b70/"", + ""obj_name"": ""/"", + ""path"": ""/"", + ""is_dir"": true, + ""permissions"": { + ""can_edit"": false, + ""can_download"": true + }, + ""is_expired"": false, + ""repo_name"": ""seacloud.cc.124"" + }]") + }; + + Assert.IsTrue(request.WasSuccessful(message)); + var result = ExecuteSync(() => request.ParseResponseAsync(message)); + + Assert.AreEqual("/", result.Name); + + //Assert.AreEqual(FakeRepoId, result.LibraryId); + //Assert.AreEqual("/test/subfolder/foo.py", result.Path); + + Assert.AreEqual("6afa667ff2c248378b70", result.Id); + + Assert.AreEqual(true, result.IsDirectory); + //Assert.AreEqual(22, result.Size); + //// converted the timestamp 1398148877 using http://www.onlineconversion.com/unix_time.htm + //// note: comparison is done in local time + //Assert.AreEqual(DateTime.Parse("Tue, 22 Apr 2014 06:41:17 GMT", CultureInfo.InvariantCulture), result.Timestamp); + } + } +} diff --git a/SeafClient/Requests/ShareLinks/CreateShareLinkRequest.cs b/SeafClient/Requests/ShareLinks/CreateShareLinkRequest.cs new file mode 100644 index 0000000..70ab396 --- /dev/null +++ b/SeafClient/Requests/ShareLinks/CreateShareLinkRequest.cs @@ -0,0 +1,103 @@ +using Newtonsoft.Json; +using SeafClient.Requests; +using SeafClient.Types; +using System; +using System.Net; +using System.Net.Http; +using System.Text; + +namespace SeafClient +{ + + public class CreateShareLinkRequest : SessionRequest + { + public string LibraryId { get; set; } + + public string Path { get; set; } + + public string Password { get; set; } + + public int ExpiryDays { get; set; } + + public bool CanEdit { get; set; } + + public bool CanDownload { get; set; } + + + public override string CommandUri + { + get { return "api/v2.1/share-links/";} + } + + public override HttpAccessMethod HttpAccessMethod + { + get { return HttpAccessMethod.Custom; } + } + + public CreateShareLinkRequest( + string authToken, + string pLibraryId, + string pPath, + string pPassword="", + int pExpiryDays = 0, + bool pCanEdit = false, + bool pCanDownload = true + ) : base(authToken) + { + LibraryId = pLibraryId; + Path = pPath; + + if (!Path.StartsWith("/")) + Path = "/" + Path; + + Password = pPassword; + ExpiryDays = pExpiryDays; + CanEdit = pCanEdit; + CanDownload = pCanDownload; + } + + public override SeafError GetSeafError(HttpResponseMessage msg) + { + switch (msg.StatusCode) + { + case HttpStatusCode.BadRequest: + return new SeafError(msg.StatusCode, SeafErrorCode.PathDoesNotExist); + case HttpStatusCode.NotFound: + return new SeafError(msg.StatusCode, SeafErrorCode.FileNotFound); + default: + return base.GetSeafError(msg); + } + } + + public override HttpRequestMessage GetCustomizedRequest(Uri serverUri) + { + + Uri uri = new Uri(serverUri, CommandUri); + + HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, uri); + + message.Headers.Referrer = uri; + foreach (var hi in GetAdditionalHeaders()) + message.Headers.Add(hi.Key, hi.Value); + + var data = new SeafShareLinkRequest() + { + LibraryId = LibraryId, + Path = Path, + ExpireDays = ExpiryDays, + Permission = new SeafShareLinkPermissions() + { + CanDownload = CanDownload, + CanEdit = CanEdit + } + + }; + + message.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"); + return message; + } + + } + +} + diff --git a/SeafClient/Requests/ShareLinks/DeleteShareLinkRequest.cs b/SeafClient/Requests/ShareLinks/DeleteShareLinkRequest.cs new file mode 100644 index 0000000..e301a81 --- /dev/null +++ b/SeafClient/Requests/ShareLinks/DeleteShareLinkRequest.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace SeafClient.Requests.ShareLinks +{ + public class DeleteShareLinkRequest : SessionRequest + { + public string ShareLinkToken { get; set; } + + public override string CommandUri + { + get { return String.Format("api/v2.1/share-links/{0}/", ShareLinkToken); } + } + + public override HttpAccessMethod HttpAccessMethod + { + get { return HttpAccessMethod.Delete; } + } + + public DeleteShareLinkRequest(string authToken, string pShareLinkToken) + : base(authToken) + { + ShareLinkToken = pShareLinkToken; + } + + public override async Task ParseResponseAsync(System.Net.Http.HttpResponseMessage msg) + { + string content = await msg.Content.ReadAsStringAsync(); + return content == "\"success\""; + } + + + } +} diff --git a/SeafClient/Requests/ShareLinks/ListShareLinksRequest.cs b/SeafClient/Requests/ShareLinks/ListShareLinksRequest.cs new file mode 100644 index 0000000..955777a --- /dev/null +++ b/SeafClient/Requests/ShareLinks/ListShareLinksRequest.cs @@ -0,0 +1,52 @@ +using SeafClient.Types; +using SeafClient.Utils; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; + +namespace SeafClient.Requests.ShareLinks +{ + public class ListShareLinksRequest : SessionRequest> + { + public string LibraryId {get;set;} + public string Path { get; set; } + + public override string CommandUri + { + get + { + var tmp = new List(); + if (LibraryId!="") + { + tmp.Add("repo_id=" + LibraryId); + } + if (Path != "") + { + tmp.Add("path=" + WebUtility.UrlEncode(Path)); + } + + var add = ""; + if (tmp.Count > 0) + { + add = "?" + String.Join("&", tmp); + } + + return "api/v2.1/share-links/"+add; + } + } + + public ListShareLinksRequest(string authToken, string pLibraryId="", string pPath="") + : base(authToken) + { + ParamUtils.ThrowOnNull(pLibraryId, "pLibraryId"); + ParamUtils.ThrowOnNull(pPath, "pPath"); + + LibraryId = pLibraryId; + Path = pPath; + } + + + } +} + diff --git a/SeafClient/SeafClient.csproj b/SeafClient/SeafClient.csproj index f2b6450..08a274b 100644 --- a/SeafClient/SeafClient.csproj +++ b/SeafClient/SeafClient.csproj @@ -11,6 +11,10 @@ en + + + + diff --git a/SeafClient/SeafSession.cs b/SeafClient/SeafSession.cs index 0932ac7..b5d4ebf 100644 --- a/SeafClient/SeafSession.cs +++ b/SeafClient/SeafSession.cs @@ -8,6 +8,7 @@ using SeafClient.Requests.Files; using SeafClient.Requests.Groups; using SeafClient.Requests.Libraries; +using SeafClient.Requests.ShareLinks; using SeafClient.Requests.StarredFiles; using SeafClient.Requests.UserAccountInfo; using SeafClient.Types; @@ -1224,6 +1225,60 @@ public async Task RemoveGroupMember(int groupId, string userName) return await _webConnection.SendRequestAsync(ServerUri, request); } + + #region Share Links + + public async Task CreateShareLink(string pLibraryId, + string pPath, + string pPassword = "", + int pExpiryDays = 0, + bool pCanEdit = false, + bool pCanDownload = true) + { + var request = new CreateShareLinkRequest( + AuthToken, + pLibraryId, + pPath, + pPassword, + pExpiryDays, + pCanEdit, + pCanDownload + ); + var result = await _webConnection.SendRequestAsync(ServerUri, request); + return result; + } + + public async Task> ListSharedLinks(string pLibraryId = "", string pPath = "") + { + var request = new ListShareLinksRequest(AuthToken,pLibraryId,pPath); + return await _webConnection.SendRequestAsync(ServerUri, request); + } + + public async Task DeleteShareLink(string shareLinkToken) + { + var request = new DeleteShareLinkRequest(AuthToken, shareLinkToken); + return await _webConnection.SendRequestAsync(ServerUri, request); + } + + + + + #endregion + + + + + + + + + + + + + + + private void CheckRequestSupportedByServer(ISeafRequest request) { if (request.SupportedWithServerVersion(ServerVersion)) diff --git a/SeafClient/Types/SeafShareLink.cs b/SeafClient/Types/SeafShareLink.cs new file mode 100644 index 0000000..8e950d6 --- /dev/null +++ b/SeafClient/Types/SeafShareLink.cs @@ -0,0 +1,75 @@ +using System; +using Newtonsoft.Json; +using SeafClient.Converters; + +namespace SeafClient.Types +{ + public class SeafShareLinkPermissions + { + [JsonProperty("can_edit")] + public virtual bool CanEdit { get; set; } + + [JsonProperty("can_download")] + public virtual bool CanDownload { get; set; } + } + + public class SeafShareLinkRequest + { + [JsonProperty("repo_id")] + public virtual string LibraryId { get; set; } + + [JsonProperty("path")] + public virtual string Path { get; set; } + + [JsonProperty("permissions")] + public virtual SeafShareLinkPermissions Permission { get; set; } + + [JsonProperty("expire_days")] + public virtual int ExpireDays { get; set; } + } + + + public class SeafShareLink + { + [JsonProperty("repo_id")] + public virtual string LibraryId { get; set; } + + [JsonProperty("path")] + public virtual string Path { get; set; } + + + [JsonProperty("username")] + public virtual string UserName { get; set; } + + [JsonProperty("ctime")] + public virtual DateTime? CreationDate { get; set; } + + [JsonProperty("expire_date")] + public virtual DateTime? ExpiryDate { get; set; } + + [JsonProperty("token")] + public virtual string Id { get; set; } + + [JsonProperty("view_cnt")] + public virtual int ViewCounter { get; set; } + + [JsonProperty("link")] + public virtual string Link { get; set; } + + [JsonProperty("obj_name")] + public virtual string Name { get; set; } + + [JsonProperty("is_dir")] + public virtual bool IsDirectory { get; set; } + + [JsonProperty("is_expired")] + public virtual bool IsExpired { get; set; } + + [JsonProperty("repo_name")] + public virtual string LibraryName { get; set; } + + [JsonProperty("permissions")] + public virtual SeafShareLinkPermissions Permission { get; set; } + + } +} diff --git a/SeafClient/Utils/CredentialFormContent.cs b/SeafClient/Utils/CredentialFormContent.cs index ae96ac4..1ca1ef0 100644 --- a/SeafClient/Utils/CredentialFormContent.cs +++ b/SeafClient/Utils/CredentialFormContent.cs @@ -31,6 +31,8 @@ public CredentialFormContent(params KeyValuePair[] formData) } } + + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context) { try