# OAT

## Useful links

### DEV
| Object  | Links | 
|---|---|
| Lambdas Sentry | [acknowledge](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795544) / [encoding-route](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795547) / [audio-validation](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795565) / [audio-waveform-generation](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795568) / [image-validation](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795549) / [image-encoding](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795560) / [general-status-notification](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795571) / [final-status-notification](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1795578) / [error-reporting](https://sentry.io/organizations/the-orchard/issues/?environment=dev&project=1796641))

### QA

| Object  | Links | 
|---|---|
| Lambdas Sentry | [acknowledge](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795544) / [encoding-route](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795547) / [audio-validation](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795565) / [audio-waveform-generation](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795568) / [image-validation](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795549) / [image-encoding](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795560) / [general-status-notification](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795571) / [final-status-notification](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1795578) / [error-reporting](https://sentry.io/organizations/the-orchard/issues/?environment=qa&project=1796641))


### PROD

| Object  | Links | 
|---|---|
| Lambdas Sentry | [acknowledge](https://sentry.io/organizations/the-orchard/issues/?project=1795545) / [encoding-route](https://sentry.io/organizations/the-orchard/issues/?project=1795546) / [audio-validation](https://sentry.io/organizations/the-orchard/issues/?project=1795566) / [audio-waveform-generation](https://sentry.io/organizations/the-orchard/issues/?project=1795569) / [image-validation](https://sentry.io/organizations/the-orchard/issues/?project=1795556) / [image-encoding](https://sentry.io/organizations/the-orchard/issues/?project=1795563) / [general-status-notification](https://sentry.io/organizations/the-orchard/issues/?project=1795575) / [final-status-notification](https://sentry.io/organizations/the-orchard/issues/?project=1795580) / [error-reporting](https://sentry.io/organizations/the-orchard/issues/?project=1796643))

## Usage
First step is from the frontend get a token from the upload_token endpoint, this can be done through graphql assetTranscoderUploadToken.

The frontend can then upload the file to s3 doing something like this...

```jsx
import AWS from 'aws-sdk/global';
import S3 from 'aws-sdk/clients/s3';

AWS.config.update({
    httpOptions: {
        timeout: 1200000
    }
});

export const createS3Client = ({
    awsAccessKeyId: accessKeyId,
    awsSecretAccessKey: secretAccessKey,
    token: sessionToken
}) =>
    new S3({
        accessKeyId,
        secretAccessKey,
        sessionToken,
        useAccelerateEndpoint: true,
        useDualstack: true
    });

export const uploadFileToS3 = (file, bucket, key, metadata, credentials) => {
    const s3Client = createS3Client(credentials);
    const params = {
        Body: file,
        Bucket: bucket,
        Key: key,
        ContentType: file.type,
        Metadata: {
            ...metadata
        }
    };

    return s3Client.upload(params, {});
};

export const pollAsset = (client, filename, setErrors, callback) => {
    const query = client.watchQuery({
        query: GET_UPLOAD_STATUS,
        variables: { filename },
        pollInterval: 1000,
    });

    const subscription = query.subscribe(({ data }) => {
        const status = get(data, 'assetTranscoderUploadStatus.status', '');
        if (status === 'encoding_completed') {
            subscription.unsubscribe();
            query.stopPolling();
            callback(data.assetTranscoderUploadStatus.assets);
        }
        if (status.endsWith('_error')) {
            subscription.unsubscribe();
            query.stopPolling();

            const errors = data.assetTranscoderUploadStatus.description.split('|');
            setErrors(errors);
        }
    });

    return () => {
        subscription.unsubscribe();
        query.stopPolling();
    };
};

const uploadFile = (file, credentials) => {
    const fileExtension = file.name.split('.').pop();
    const key = `${credentials.filename}.${fileExtension}`;

    const metadata = {
        asset_type: fileExtension.toUpperCase(),
        original_filename: encodeURI(file.name),
        object_type: objectType,
        object_id: objectId // this is optional
    };

    uploadRef.current = uploadFileToS3(
        file, credentials.bucket, key, metadata, credentials.credentials
    );

    uploadRef.current.on(
        'httpUploadProgress',
        (progress) => setUploadProgress(Math.round((progress.loaded / progress.total) * 100))
    );

    uploadRef.current.promise().then(
        () => pollAsset(client, credentials.filename, setErrors, (finals) => {
            const final = find(finals, { assetSubtype: 'large_cover' });
            setNewArtworkUrl(get(final, 'url', null));
        }),
        err => {
            if (err.message !== 'Request aborted by user')
                setErrors([err.message]);
        }
    );
};

const onStartUpload = async (files) => {
    const { data } = await client.query({
        query: GET_UPLOAD_TOKEN,
        fetchPolicy: 'network-only',
    });
    uploadFile(files[0], data.assetTranscoderUploadToken);
};

```

The metadata you attach to the s3 asset at this point is used by OAT to process the file.  The objectType and objectId are used to link this asset to the table it should be attached to.  You can choose to attach the asset immediately or at a later point (maybe when you hit a save button) by either passing object_id in the metadata at this point or leaving it off.

If you want to attach the asset to your object later, call the endpoint commit/<filename> where filename is credentials.filename.
