diff --git a/README.md b/README.md index 0fedd2a..23f4710 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ This API contains 5 interactions: 3. Update File Info 4. Delete File 5. Get File +6. Create Bucket +7. Delete Bucket +8. Get Bucket The package is namespaced to `Waifuvault`, so to import it, simply: @@ -33,16 +36,17 @@ using Waifuvault; To Upload a file, use the `uploadFile` function. This function takes the following options as an object: -| Option | Type | Description | Required | Extra info | -|----------------|--------------|-------------------------------------------------------------|----------------|----------------------------------| -| `filename` | `string ` | The path to the file to upload | true if File | File path | -| `url` | `string` | The URL of the file to target | true if URL | Filename with extension | -| `buffer` | `byte array` | Byte array containing file to upload | true if buffer | Needs filename set also | -| `expires` | `string` | A string containing a number and a unit (1d = 1day) | false | Valid units are `m`, `h` and `d` | -| `hideFilename` | `boolean` | If true, then the uploaded filename won't appear in the URL | false | Defaults to `false` | -| `password` | `string` | If set, then the uploaded file will be encrypted | false | | -| `ct` | `canceltoken`| An optional cancellation token that can be passed in | false | Standard cancellation token | -| `oneTimeDownload` | `boolean` | if supplied, the file will be deleted as soon as it is accessed | false | | +| Option | Type | Description | Required | Extra info | +|-------------------|---------------|-----------------------------------------------------------------|----------------|----------------------------------| +| `filename` | `string ` | The path to the file to upload | true if File | File path | +| `url` | `string` | The URL of the file to target | true if URL | Filename with extension | +| `buffer` | `byte array` | Byte array containing file to upload | true if buffer | Needs filename set also | +| `bucketToken` | `string` | Token for a bucket to upload the file into | false | Create bucket gives token | +| `expires` | `string` | A string containing a number and a unit (1d = 1day) | false | Valid units are `m`, `h` and `d` | +| `hideFilename` | `boolean` | If true, then the uploaded filename won't appear in the URL | false | Defaults to `false` | +| `password` | `string` | If set, then the uploaded file will be encrypted | false | | +| `ct` | `canceltoken` | An optional cancellation token that can be passed in | false | Standard cancellation token | +| `oneTimeDownload` | `boolean` | if supplied, the file will be deleted as soon as it is accessed | false | | Using a URL: @@ -216,4 +220,59 @@ try { } catch(OperationCanceledException) { Console.WriteLine("Canceled download"); } +``` + +### Create Bucket + +Buckets are virtual collections that are linked to your IP and a token. When you create a bucket, you will receive a bucket token that you can use in Get Bucket to get all the files in that bucket + +> **NOTE:** Only one bucket is allowed per client IP address, if you call it more than once, it will return the same bucket token + +To create a bucket, use the `createBucket` function. This function does not take any arguments. + +```csharp +using Waifuvault; +var bucket = await Waifuvault.Api.createBucket(); +Console.WriteLine(bucket.token); +``` + +### Delete Bucket + +Deleting a bucket will delete the bucket and all the files it contains. + +> **IMPORTANT:** All contained files will be **DELETED** along with the Bucket! + +To delete a bucket, you must call the `deleteBucket` function with the following options as parameters: + +| Option | Type | Description | Required | Extra info | +|-------------|-----------|-----------------------------------|----------|-------------------| +| `token` | `string` | The token of the bucket to delete | true | | + +> **NOTE:** `deleteBucket` will only ever either return `true` or throw an exception if the token is invalid + +```csharp +using Waifuvault; +var resp = await Waifuvault.Api.deleteBucket("some-bucket-token"); +Console.WriteLine(resp); +``` + +### Get Bucket + +To get the list of files contained in a bucket, you use the `getBucket` functions and supply the token. +This function takes the following options as parameters: + +| Option | Type | Description | Required | Extra info | +|-------------|-----------|-------------------------|----------|-------------------| +| `token` | `string` | The token of the bucket | true | | + +This will respond with the bucket and all the files the bucket contains. + +```csharp +using Waifuvault; +var bucket = await Waifuvault.Api.getBucket("some-bucket-token"); +Console.WriteLine(bucket.token); +foreach(var file in bucket.files) +{ + Console.WriteLine(file.token); +} ``` \ No newline at end of file diff --git a/models.cs b/models.cs index 2a1eef5..eeee3d6 100644 --- a/models.cs +++ b/models.cs @@ -8,12 +8,13 @@ public class FileUpload public string? filename { get; set; } public string? url { get; set; } public byte[]? buffer { get; set; } + public string? bucketToken { get; set; } public string? expires { get; set; } public string? password { get; set; } public bool? hidefilename { get; set; } public bool? oneTimeDownload { get; set; } - public FileUpload(string target, string? expires = null, string? password = null, bool? hidefilename = null, bool? oneTimeDownload = null) { + public FileUpload(string target, string? bucket = null, string? expires = null, string? password = null, bool? hidefilename = null, bool? oneTimeDownload = null) { if(target.ToLower().StartsWith("http://") || target.ToLower().StartsWith("https://")) { this.url = target; @@ -23,15 +24,17 @@ public FileUpload(string target, string? expires = null, string? password = null this.filename = target; } this.buffer = null; + this.bucketToken = bucket; this.expires = expires; this.password = password; this.hidefilename = hidefilename; this.oneTimeDownload = oneTimeDownload; } - public FileUpload(byte[] buffer, string filename, string? expires = null, string? password = null, bool? hidefilename = null, bool? oneTimeDownload = null) { + public FileUpload(byte[] buffer, string filename, string? bucket = null, string? expires = null, string? password = null, bool? hidefilename = null, bool? oneTimeDownload = null) { this.buffer = buffer; this.filename = filename; + this.bucketToken = bucket; this.expires = expires; this.password = password; this.hidefilename = hidefilename; @@ -72,19 +75,33 @@ public class FileResponse { public string? token { get; set; } public string? url { get; set; } + public string? bucket { get; set; } [JsonConverter(typeof(StringConverter))] public string? retentionPeriod { get; set; } public FileOptions? options { get; set; } - public FileResponse(string? token = null, string? url = null, string? retentionPeriod = null, FileOptions? options = null) { + public FileResponse(string? token = null, string? url = null, string? bucket = null, string? retentionPeriod = null, FileOptions? options = null) { this.token = token; this.url = url; + this.bucket = bucket; this.retentionPeriod = retentionPeriod; this.options = options; } } +public class BucketResponse +{ + public string? token { get; set; } + public List files { get; set; } + + public BucketResponse(string? token = null) + { + this.token = token; + files = new List(); + } +} + public class ErrorResponse { public string name { get; set; } diff --git a/tests/waifuvaultTests.cs b/tests/waifuvaultTests.cs index cd83d2a..fa49456 100644 --- a/tests/waifuvaultTests.cs +++ b/tests/waifuvaultTests.cs @@ -12,6 +12,7 @@ public class waifuvaultTests public Mock deleteTrue = new Mock(MockBehavior.Strict); public Mock badRequest = new Mock(MockBehavior.Strict); public Mock fileReturn = new Mock(MockBehavior.Strict); + public Mock bucketReturn = new Mock(MockBehavior.Strict); public waifuvaultTests() { setupMocks(); @@ -26,7 +27,7 @@ private void setupMocks() { ) .ReturnsAsync(new HttpResponseMessage(){ StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"retentionPeriod\":100, \"options\":{\"protected\":false, \"hideFilename\":false, \"oneTimeDownload\":false}}") + Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"bucket\":\"test-bucket\", \"retentionPeriod\":100, \"options\":{\"protected\":false, \"hideFilename\":false, \"oneTimeDownload\":false}}") }) .Verifiable(); @@ -38,7 +39,7 @@ private void setupMocks() { ) .ReturnsAsync(new HttpResponseMessage(){ StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"retentionPeriod\":100, \"options\":{\"protected\":true, \"hideFilename\":false, \"oneTimeDownload\":false}}") + Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"bucket\":\"test-bucket\", \"retentionPeriod\":100, \"options\":{\"protected\":true, \"hideFilename\":false, \"oneTimeDownload\":false}}") }) .Verifiable(); @@ -50,7 +51,7 @@ private void setupMocks() { ) .ReturnsAsync(new HttpResponseMessage(){ StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"retentionPeriod\":\"10 minutes\", \"options\":{\"protected\":false, \"hideFilename\":false, \"oneTimeDownload\":false}}") + Content = new StringContent("{\"url\":\"https://waifuvault.moe/f/something\", \"token\":\"test-token\", \"bucket\":\"test-bucket\", \"retentionPeriod\":\"10 minutes\", \"options\":{\"protected\":false, \"hideFilename\":false, \"oneTimeDownload\":false}}") }) .Verifiable(); @@ -89,6 +90,18 @@ private void setupMocks() { Content = new ByteArrayContent(new byte[4] {0x00, 0x01, 0x01, 0x00}) }) .Verifiable(); + + bucketReturn.Protected() + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny() + ) + .ReturnsAsync(new HttpResponseMessage(){ + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StringContent("{\"token\":\"test-bucket\", \"files\":[]}") + }) + .Verifiable(); } [Fact] @@ -304,6 +317,57 @@ public async Task TestDownload() { ItExpr.IsAny()); Assert.True(response.GetType() == typeof(byte[])); } + + [Fact] + public async Task TestCreateBucket() { + // Given + bucketReturn.Invocations.Clear(); + Waifuvault.Api.customHttpClient = new HttpClient(bucketReturn.Object); + + // When + var response = await Waifuvault.Api.createBucket(); + + // Then + bucketReturn.Protected().Verify("SendAsync",Times.Once(), + ItExpr.Is(req => req.Method == HttpMethod.Get + && req.RequestUri.ToString().Contains("/bucket/create")), + ItExpr.IsAny()); + Assert.Equal("test-bucket",response.token); + } + + [Fact] + public async Task TestGetBucket() { + // Given + bucketReturn.Invocations.Clear(); + Waifuvault.Api.customHttpClient = new HttpClient(bucketReturn.Object); + + // When + var response = await Waifuvault.Api.getBucket("test-bucket"); + + // Then + bucketReturn.Protected().Verify("SendAsync",Times.Once(), + ItExpr.Is(req => req.Method == HttpMethod.Post + && req.RequestUri.ToString().Contains("/bucket/get")), + ItExpr.IsAny()); + Assert.Equal("test-bucket",response.token); + } + + [Fact] + public async Task TestDeleteBucket() { + // Given + deleteTrue.Invocations.Clear(); + Waifuvault.Api.customHttpClient = new HttpClient(deleteTrue.Object); + + // When + var response = await Waifuvault.Api.deleteBucket("test-bucket"); + + // Then + deleteTrue.Protected().Verify("SendAsync",Times.Once(), + ItExpr.Is(req => req.Method == HttpMethod.Delete + && req.RequestUri.ToString().Contains("/bucket/test-bucket")), + ItExpr.IsAny()); + Assert.True(response); + } [Fact] public void TestBuildArgs() { diff --git a/waifuVault-csharp-api.csproj b/waifuVault-csharp-api.csproj index e2ef010..c26c3f8 100644 --- a/waifuVault-csharp-api.csproj +++ b/waifuVault-csharp-api.csproj @@ -2,7 +2,7 @@ Waifuvault - 1.3.4 + 1.3.5 Walker Aldridge (walker@waifuvault.moe) waifuvault.moe waifuvault;temp file hosting;waifu;vault diff --git a/waifuvault.cs b/waifuvault.cs index b6ac5ef..da680cc 100644 --- a/waifuvault.cs +++ b/waifuvault.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Text; using System.Text.Json; namespace Waifuvault; @@ -8,9 +9,45 @@ public class Api public const string baseURL = "https://waifuvault.moe/rest"; public static HttpClient? customHttpClient; + public static async Task createBucket() + { + var client = customHttpClient ?? new HttpClient(); + var cts = new CancellationTokenSource(); + var url = $"{baseURL}/bucket/create"; + var createResponse = await client.GetAsync(url); + await checkError(createResponse,false); + var createResponseData = await createResponse.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(createResponseData) ?? new BucketResponse(); + } + + public static async Task deleteBucket(string token, CancellationToken? ct = null) + { + var client = customHttpClient ?? new HttpClient(); + var cts = new CancellationTokenSource(); + var url = $"{baseURL}/bucket/{token}"; + var urlResponse = await client.DeleteAsync(url,ct != null ? ct.Value : cts.Token); + await checkError(urlResponse,false); + var urlResponseData = await urlResponse.Content.ReadAsStringAsync(); + return urlResponseData == "true"; + } + + public static async Task getBucket(string token, CancellationToken? ct = null) + { + var client = customHttpClient ?? new HttpClient(); + var cts = new CancellationTokenSource(); + var url = $"{baseURL}/bucket/get"; + var data = new { bucket_token = token }; + var jsonData = JsonSerializer.Serialize(data); + var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + var getResponse = await client.PostAsync(url, content, ct != null ? ct.Value : cts.Token); + await checkError(getResponse,false); + var getResponseData = await getResponse.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(getResponseData) ?? new BucketResponse(); + } + public static async Task uploadFile(FileUpload fileObj, CancellationToken? ct = null) { var retval = new FileResponse(); - var targetUrl = fileObj.buildURL(baseURL); + var targetUrl = fileObj.buildURL(String.IsNullOrEmpty(fileObj.bucketToken) ? baseURL : baseURL + $"/{fileObj.bucketToken}"); if (!String.IsNullOrEmpty(fileObj.url)) { // URL Upload