Skip to content

Feature - issue 21 #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
49 changes: 49 additions & 0 deletions Storage/FileObjectV2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Supabase.Storage
{
public class FileObjectV2
{

[JsonProperty("id")]
public string Id { get; set; }

Check warning on line 11 in Storage/FileObjectV2.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Id' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 11 in Storage/FileObjectV2.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Id' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonProperty("version")]
public string Version { get; set; }

Check warning on line 14 in Storage/FileObjectV2.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Version' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 14 in Storage/FileObjectV2.cs

View workflow job for this annotation

GitHub Actions / build-and-test

Non-nullable property 'Version' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

[JsonProperty("name")]
public string? Name { get; set; }

[JsonProperty("bucket_id")]
public string? BucketId { get; set; }

[JsonProperty("updated_at")]
public DateTime? UpdatedAt { get; set; }

[JsonProperty("created_at")]
public DateTime? CreatedAt { get; set; }

[JsonProperty("last_accessed_at")]
public DateTime? LastAccessedAt { get; set; }

[JsonProperty("size")]
public int? Size { get; set; }

[JsonProperty("cache_control")]
public string? CacheControl { get; set; }

[JsonProperty("content_type")]
public string? ContentType { get; set; }

[JsonProperty("etag")]
public string? Etag { get; set; }

[JsonProperty("last_modified")]
public DateTime? LastModified { get; set; }

[JsonProperty("metadata")]
public Dictionary<string, string>? Metadata { get; set; }
}
}
12 changes: 11 additions & 1 deletion Storage/FileOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Supabase.Storage
{
Expand All @@ -12,5 +13,14 @@ public class FileOptions

[JsonProperty("upsert")]
public bool Upsert { get; set; }

[JsonProperty("duplex")]
public string? Duplex { get; set; }

[JsonProperty("metadata")]
public Dictionary<string, string>? Metadata { get; set; }

[JsonProperty("headers")]
public Dictionary<string, string>? Headers { get; set; }
}
}
1 change: 1 addition & 0 deletions Storage/Interfaces/IStorageFileApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public interface IStorageFileApi<TFileObject>
Task<string> DownloadPublicFile(string supabasePath, string localPath, TransformOptions? transformOptions = null, EventHandler<float>? onProgress = null);
string GetPublicUrl(string path, TransformOptions? transformOptions = null);
Task<List<TFileObject>?> List(string path = "", SearchOptions? options = null);
Task<FileObjectV2?> Info(string path);
Task<bool> Move(string fromPath, string toPath, DestinationOptions? options = null);
Task<bool> Copy(string fromPath, string toPath, DestinationOptions? options = null);
Task<TFileObject?> Remove(string path);
Expand Down
37 changes: 37 additions & 0 deletions Storage/StorageFileApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,19 @@ await Helpers.MakeRequest<List<FileObject>>(HttpMethod.Post, $"{Url}/object/list

return response;
}

/// <summary>
/// Retrieves the details of an existing file.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task<FileObjectV2?> Info(string path)
{
var response =
await Helpers.MakeRequest<FileObjectV2>(HttpMethod.Get, $"{Url}/object/info/{BucketId}/{path}", null, Headers);

return response;
}

/// <summary>
/// Uploads a file to an existing bucket.
Expand Down Expand Up @@ -464,6 +477,14 @@ private async Task<string> UploadOrUpdate(string localPath, string supabasePath,
if (options.Upsert)
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

if (onProgress != null)
Expand All @@ -474,6 +495,14 @@ private async Task<string> UploadOrUpdate(string localPath, string supabasePath,
return GetFinalPath(supabasePath);
}

private static string ParseMetadata(Dictionary<string, string> metadata)
{
var json = JsonConvert.SerializeObject(metadata);
var base64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(json));

return base64;
}

private async Task<string> UploadOrUpdate(byte[] data, string supabasePath, FileOptions options,
EventHandler<float>? onProgress = null)
{
Expand All @@ -488,6 +517,14 @@ private async Task<string> UploadOrUpdate(byte[] data, string supabasePath, File
if (options.Upsert)
headers.Add("x-upsert", options.Upsert.ToString().ToLower());

if (options.Metadata != null)
headers.Add("x-metadata", ParseMetadata(options.Metadata));

options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));

if (options.Duplex != null)
headers.Add("x-duplex", options.Duplex.ToLower());

var progress = new Progress<float>();

if (onProgress != null)
Expand Down
48 changes: 47 additions & 1 deletion StorageTests/StorageFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Supabase.Storage;
using Supabase.Storage.Interfaces;
using FileOptions = Supabase.Storage.FileOptions;

namespace StorageTests;

Expand Down Expand Up @@ -75,6 +76,51 @@ public async Task UploadFile()

await _bucket.Remove(new List<string> { name });
}

[TestMethod("File: Upload File With FileOptions")]
public async Task UploadFileWithFileOptions()
{
var didTriggerProgress = new TaskCompletionSource<bool>();

var asset = "supabase-csharp.png";
var name = $"{Guid.NewGuid()}.png";
var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)?.Replace("file:", "");

Assert.IsNotNull(basePath);

var imagePath = Path.Combine(basePath, "Assets", asset);

var metadata = new Dictionary<string, string>
{
["custom"] = "metadata",
["local_file"] = "local_file"
};

var headers = new Dictionary<string, string>
{
["x-version"] = "123"
};

var options = new FileOptions
{
Duplex = "duplex",
Metadata = metadata,
Headers = headers,
};
await _bucket.Upload(imagePath, name, options, (_, _) => { didTriggerProgress.TrySetResult(true); });

var item = await _bucket.Info(name);

Assert.IsNotNull(item);
Assert.IsNotNull(item.Metadata);
Assert.AreEqual(metadata["custom"], item.Metadata["custom"]);
Assert.AreEqual(metadata["local_file"], item.Metadata["local_file"]);

var sentProgressEvent = await didTriggerProgress.Task;
Assert.IsTrue(sentProgressEvent);

await _bucket.Remove([name]);
}

[TestMethod("File: Upload Arbitrary Byte Array")]
public async Task UploadArbitraryByteArray()
Expand Down Expand Up @@ -192,7 +238,7 @@ public async Task CopyToAnotherBucket()
foreach (var file in copied)
{
if (file.Name is not null)
await localBucket.Remove(new List<string> { file.Name });
await localBucket.Remove([file.Name]);
}

await Storage.DeleteBucket("copyfile");
Expand Down
Loading