Difference between revisions of "File Uploads"

From SocialStack
(Created page with "SocialStack has a mechanism for uploading public or private files. When a file is uploaded, the upload endpoint will return a file ref of the new file.")
 
Line 1: Line 1:
SocialStack has a mechanism for uploading public or private files. When a file is uploaded, the upload endpoint will return a [[file ref]] of the new file.
SocialStack has a mechanism for uploading public or private files. When a file is uploaded, the upload endpoint will return a [[File Refs|file ref]] for the new file, which is then typically the main way to refer to a particular file.
 
By default, when uploading an image file, it will automatically be resized into a collection of different sizes for convenience. This works on modern image formats like webp too.
 
If you need video to be handled as well, you can either install the Api/FFmpeg module and ffmpeg on the target servers (ffmpeg is installed by default on all SocialStack cloud servers), or perform remote transcoding with huddle servers. Transcoding video is a very heavy process but usually mandatory if a CDN is involved in your project due to the file size limits of a CDN, and also end users benefit by being able to skip through the video substantially faster.
 
= Displaying a file uploader =
 
Use type="file" for a file uploader. When the form is submitted, the value will be the [[File Refs|file ref]]:
 
<syntaxhighlight lang="javascript">
import Input from 'UI/Input';
 
...
 
<Input type="file" name="myFile" label="My File Uploader" />
</syntaxhighlight>
 
This defaults to storing files in the public file store. If you want them to be private, add the isPrivate prop:
 
<syntaxhighlight lang="javascript">
import Input from 'UI/Input';
 
...
 
<Input type="file" name="myFile" label="My File Uploader" isPrivate />
</syntaxhighlight>
 
= Making use of an uploaded file =
 
== On the frontend ==
 
An uploaded file is represented as a [[File Refs|file ref]] on the frontend - see the [[File Refs|file ref wiki article]] on how to work with those on the frontend.
 
== In the API ==
 
As an upload is a content type, you can subscribe to Upload related events to handle when a new file is uploaded. This is often not the easiest to work with though; more on that in a moment:
 
<syntaxhighlight lang="csharp">
 
Events.Upload.AfterCreate.AddEventListener(async (Context context, Upload upload) => {
   
    if(upload == null) {
        return upload;
    }
   
    // Do something with upload here.
   
    return upload;
 
});
 
// AfterUpdate, AfterDelete etc
 
</syntaxhighlight>
 
However, because this event runs whenever any file is uploaded, there's no context on why it was uploaded. This is fine if you're building something like a transcoder which just cares about file type, but not if you're making something that requires a specific file. Instead, it's recommended to make a custom endpoint which receives a ref for that situation.
 
For example, the frontend may have a form like this:
 
<syntaxhighlight lang="csharp">
<Form action="attendee/from-csv" submitLabel="Apply">
    <Input type="file" label="Attendee CSV" name="csvRef" isPrivate/>
</Form>
</syntaxhighlight>
 
When the file is uploaded and the form is submitted, a JSON payload containing field called csvRef will get posted to the endpoint, and the payload would look something like this:
 
<syntaxhighlight lang="json">
{
    "csvRef": "private:42.csv?s=..."
}
</syntaxhighlight>
 
From there, a C# asp.net controller method can capture the ref value:
 
<syntaxhighlight lang="json">
[HttpPost("from-csv")]
public async ValueTask FromCsv([FromBody] CsvRefPayload payload)
{
    var context = await Request.GetContext();
    var csvRef = payload.csvRef; // the string
 
    // Do something fun with the csvRef here! (there's more on handling refs in the API in the file ref wiki).
}
 
...
 
public class CsvRefPayload
{
    public string csvRef;
}
 
</syntaxhighlight>
 
For information on using a ref in the API, see the [[File Refs|file ref wiki page]].
 
= Upload metadata =
 
== On the frontend ==
 
File uploads are a content type (called Upload), meaning all the usual conveniences apply: you can list all uploads, use Loop on them and so on - provided the user has permission to do so.
 
<syntaxhighlight lang="javascript">
 
<Loop over='upload'>{anUpload => <>{anUpload.originalName}</>}</Loop>
 
// Or if you want an array of uploads:
 
webRequest('upload/list').then(response => {
    // response.json.results
})
 
</syntaxhighlight>
 
== In the API ==
 
As with other content types, either use injection or Services.Get to access the UploadService. From there, you can List/ Update and so on the upload you're interested in.

Revision as of 17:10, 17 January 2023

SocialStack has a mechanism for uploading public or private files. When a file is uploaded, the upload endpoint will return a file ref for the new file, which is then typically the main way to refer to a particular file.

By default, when uploading an image file, it will automatically be resized into a collection of different sizes for convenience. This works on modern image formats like webp too.

If you need video to be handled as well, you can either install the Api/FFmpeg module and ffmpeg on the target servers (ffmpeg is installed by default on all SocialStack cloud servers), or perform remote transcoding with huddle servers. Transcoding video is a very heavy process but usually mandatory if a CDN is involved in your project due to the file size limits of a CDN, and also end users benefit by being able to skip through the video substantially faster.

Displaying a file uploader

Use type="file" for a file uploader. When the form is submitted, the value will be the file ref:

import Input from 'UI/Input';

...

<Input type="file" name="myFile" label="My File Uploader" />

This defaults to storing files in the public file store. If you want them to be private, add the isPrivate prop:

import Input from 'UI/Input';

...

<Input type="file" name="myFile" label="My File Uploader" isPrivate />

Making use of an uploaded file

On the frontend

An uploaded file is represented as a file ref on the frontend - see the file ref wiki article on how to work with those on the frontend.

In the API

As an upload is a content type, you can subscribe to Upload related events to handle when a new file is uploaded. This is often not the easiest to work with though; more on that in a moment:

Events.Upload.AfterCreate.AddEventListener(async (Context context, Upload upload) => {
    
    if(upload == null) {
        return upload;
    }
    
    // Do something with upload here.
    
    return upload;

});

// AfterUpdate, AfterDelete etc

However, because this event runs whenever any file is uploaded, there's no context on why it was uploaded. This is fine if you're building something like a transcoder which just cares about file type, but not if you're making something that requires a specific file. Instead, it's recommended to make a custom endpoint which receives a ref for that situation.

For example, the frontend may have a form like this:

<Form action="attendee/from-csv" submitLabel="Apply">
    <Input type="file" label="Attendee CSV" name="csvRef" isPrivate/>
</Form>

When the file is uploaded and the form is submitted, a JSON payload containing field called csvRef will get posted to the endpoint, and the payload would look something like this:

{
    "csvRef": "private:42.csv?s=..."
}

From there, a C# asp.net controller method can capture the ref value:

[HttpPost("from-csv")]
public async ValueTask FromCsv([FromBody] CsvRefPayload payload)
{
    var context = await Request.GetContext();
    var csvRef = payload.csvRef; // the string

    // Do something fun with the csvRef here! (there's more on handling refs in the API in the file ref wiki).
}

...

public class CsvRefPayload
{
    public string csvRef;
}

For information on using a ref in the API, see the file ref wiki page.

Upload metadata

On the frontend

File uploads are a content type (called Upload), meaning all the usual conveniences apply: you can list all uploads, use Loop on them and so on - provided the user has permission to do so.

<Loop over='upload'>{anUpload => <>{anUpload.originalName}</>}</Loop>

// Or if you want an array of uploads:

webRequest('upload/list').then(response => {
    // response.json.results
})

In the API

As with other content types, either use injection or Services.Get to access the UploadService. From there, you can List/ Update and so on the upload you're interested in.