Skip to content

Commit f37e7b8

Browse files
Added support to upload files via a stream
Updated the RequestQuery custom filter
1 parent 875e256 commit f37e7b8

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

Scr/Sdk4me.GraphQL/Helpers/ExecutionQueryBuilder.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,7 @@ private static string SerializeObject(string? value)
451451
private static string[] SerializeObject(params string?[] values)
452452
{
453453
List<string> retval = new();
454-
if (values == null)
455-
values = Array.Empty<string>();
454+
values ??= Array.Empty<string>();
456455
foreach (string? value in values)
457456
retval.Add(SerializeObject(value));
458457
return retval.ToArray();

Scr/Sdk4me.GraphQL/Queries/RequestQuery.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ public RequestQuery SelectWorkflow(WorkflowQuery query)
347347
/// <exception cref="NullReferenceException"></exception>
348348
public RequestQuery CustomFilter(string name, FilterOperator filterOperator, params string?[] values)
349349
{
350-
return AddCustomFilter(name, filterOperator, values ?? new string?[] { null });
350+
return AddCustomFilter(name, filterOperator, values);
351351
}
352352
}
353353
}

Scr/Sdk4me.GraphQL/Sdk4meClient.cs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Newtonsoft.Json.Converters;
22
using System.Diagnostics;
33
using System.Net.Http.Headers;
4-
using System.Reflection;
54
using System.Text;
65
using System.Text.RegularExpressions;
76

@@ -312,29 +311,61 @@ public async Task<AttachmentUploadResponse> UploadAttachment(FileInfo file, stri
312311
if (!file.Exists)
313312
throw new FileNotFoundException(file.FullName);
314313

314+
using (FileStream stream = file.OpenRead())
315+
return await UploadAttachment(stream as Stream, file.Name, contentType);
316+
}
317+
318+
/// <summary>
319+
/// Upload a file to the 4me AWS S3 storage.
320+
/// </summary>
321+
/// <param name="stream">The content to upload. The stream needs to support seeking in order to determine the HTTP Content-Length header.</param>
322+
/// <param name="fileName">The file name.</param>
323+
/// <param name="contentType">The content type of the file.</param>
324+
/// <returns>A <see cref="AttachmentUploadResponse"/> containing the 4me AWS S3 file storage reference key and file size.</returns>
325+
/// <exception cref="FileNotFoundException"></exception>
326+
/// <exception cref="Sdk4meException"></exception>
327+
public async Task<AttachmentUploadResponse> UploadAttachment(StreamReader stream, string fileName, string contentType)
328+
{
329+
return await UploadAttachment(stream.BaseStream, fileName, contentType);
330+
}
331+
332+
/// <summary>
333+
/// Upload a file to the 4me AWS S3 storage.
334+
/// </summary>
335+
/// <param name="stream">The content to upload. The stream needs to support seeking in order to determine the HTTP Content-Length header.</param>
336+
/// <param name="fileName">The file name.</param>
337+
/// <param name="contentType">The content type of the file.</param>
338+
/// <returns>A <see cref="AttachmentUploadResponse"/> containing the 4me AWS S3 file storage reference key and file size.</returns>
339+
/// <exception cref="Sdk4meException"></exception>
340+
public async Task<AttachmentUploadResponse> UploadAttachment(Stream stream, string fileName, string contentType)
341+
{
342+
if (!stream.CanSeek)
343+
throw new Sdk4meException("The stream needs to support seeking in order to determine the HTTP Content-Length header.");
344+
315345
DataList<AttachmentStorage> attachmentStorages = await Get<AttachmentStorage>(Query.AttachmentStorage);
316346
if (attachmentStorages.FirstOrDefault() is AttachmentStorage attachmentStorage)
317347
{
318-
if (attachmentStorage.AllowedExtensions != null && attachmentStorage.AllowedExtensions.Contains(file.Extension.TrimStart('.')))
348+
string fileExtension = Path.GetExtension(fileName).TrimStart('.');
349+
if (attachmentStorage.AllowedExtensions != null && attachmentStorage.AllowedExtensions.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase))
319350
{
320-
if (file.Length >= attachmentStorage.SizeLimit)
351+
if (stream.Length >= attachmentStorage.SizeLimit)
321352
throw new Sdk4meException($"File size exceeded, the maximum size is {attachmentStorage.SizeLimit} byte");
322353

323354
Dictionary<string, string> storageFacility = attachmentStorage?.ProviderParameters?.ToObject<Dictionary<string, string>>() ?? throw new Sdk4meException("File upload failed, invalid AttachmentStorage.ProviderParameters value.");
324355
MultipartFormDataContent multipartContent = new()
325-
{
326-
{ new StringContent(contentType), "Content-Type" },
327-
{ new StringContent(storageFacility["acl"]), "acl" },
328-
{ new StringContent(storageFacility["key"]), "key" },
329-
{ new StringContent(storageFacility["policy"]), "policy" },
330-
{ new StringContent(storageFacility["success_action_status"]), "success_action_status" },
331-
{ new StringContent(storageFacility["x-amz-algorithm"]), "x-amz-algorithm" },
332-
{ new StringContent(storageFacility["x-amz-credential"]), "x-amz-credential" },
333-
{ new StringContent(storageFacility["x-amz-date"]), "x-amz-date" },
334-
{ new StringContent(storageFacility["x-amz-server-side-encryption"]), "x-amz-server-side-encryption" },
335-
{ new StringContent(storageFacility["x-amz-signature"]), "x-amz-signature" },
336-
{ new ByteArrayContent(File.ReadAllBytes(file.FullName)), "file", file.Name }
337-
};
356+
{
357+
{ new StringContent(contentType), "Content-Type" },
358+
{ new StringContent(storageFacility["acl"]), "acl" },
359+
{ new StringContent(storageFacility["key"]), "key" },
360+
{ new StringContent(storageFacility["policy"]), "policy" },
361+
{ new StringContent(storageFacility["success_action_status"]), "success_action_status" },
362+
{ new StringContent(storageFacility["x-amz-algorithm"]), "x-amz-algorithm" },
363+
{ new StringContent(storageFacility["x-amz-credential"]), "x-amz-credential" },
364+
{ new StringContent(storageFacility["x-amz-date"]), "x-amz-date" },
365+
{ new StringContent(storageFacility["x-amz-server-side-encryption"]), "x-amz-server-side-encryption" },
366+
{ new StringContent(storageFacility["x-amz-signature"]), "x-amz-signature" },
367+
{ new StreamContent(stream), "file", fileName }
368+
};
338369

339370
using (HttpRequestMessage requestMessage = new(HttpMethod.Post, attachmentStorage.UploadUri) { Content = multipartContent })
340371
{
@@ -351,7 +382,7 @@ public async Task<AttachmentUploadResponse> UploadAttachment(FileInfo file, stri
351382
return new()
352383
{
353384
Key = match.Value,
354-
Size = file.Length
385+
Size = stream.Length
355386
};
356387
}
357388
else
@@ -362,7 +393,10 @@ public async Task<AttachmentUploadResponse> UploadAttachment(FileInfo file, stri
362393
}
363394
}
364395
}
365-
throw new Sdk4meException($"The {file.Extension} extension is not allowed on this 4me instance.");
396+
if (fileExtension == string.Empty)
397+
throw new Sdk4meException($"A file name without extension is not allowed on this 4me instance.");
398+
else
399+
throw new Sdk4meException($"The '{fileExtension}' extension is not allowed on this 4me instance.");
366400
}
367401
throw new Sdk4meException("No AttachmentStorage object returned by the GraphQL API.");
368402
}

0 commit comments

Comments
 (0)