supports custom resource URIs for two upload endpoints

This commit is contained in:
@wwwjim 2020-10-23 03:34:31 -07:00
parent 9713a838a9
commit 15fa57c2df
10 changed files with 87 additions and 104 deletions

View File

@ -1,6 +1,7 @@
import * as Actions from "~/common/actions";
import * as Store from "~/common/store";
import * as Constants from "~/common/constants";
import * as Credentials from "~/common/credentials";
import { dispatchCustomEvent } from "~/common/custom-events";
import { encode } from "blurhash";
@ -31,7 +32,13 @@ const encodeImageToBlurhash = async (imageUrl) => {
return encode(imageData.data, imageData.width, imageData.height, 4, 4);
};
export const upload = async ({ file, context, bucketName }) => {
// NOTE(jim): We're speaking to a different server now.
const getCookie = (name) => {
var match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)"));
if (match) return match[2];
};
export const upload = async ({ file, context, bucketName, routes }) => {
let formData = new FormData();
const HEIC2ANY = require("heic2any");
@ -61,14 +68,13 @@ export const upload = async ({ file, context, bucketName }) => {
new Promise((resolve, reject) => {
const XHR = new XMLHttpRequest();
window.addEventListener(
`cancel-${file.lastModified}-${file.name}`,
() => {
XHR.abort();
}
);
window.addEventListener(`cancel-${file.lastModified}-${file.name}`, () => {
XHR.abort();
});
XHR.open("post", path, true);
XHR.setRequestHeader("authorization", getCookie(Credentials.session.key));
XHR.onerror = (event) => {
console.log(event);
XHR.abort();
@ -99,10 +105,7 @@ export const upload = async ({ file, context, bucketName }) => {
false
);
window.removeEventListener(
`cancel-${file.lastModified}-${file.name}`,
() => XHR.abort()
);
window.removeEventListener(`cancel-${file.lastModified}-${file.name}`, () => XHR.abort());
XHR.onloadend = (event) => {
console.log("FILE UPLOAD END", event);
@ -119,10 +122,15 @@ export const upload = async ({ file, context, bucketName }) => {
let res;
// TODO(jim): Make this smarter.
const storageDealRoute =
routes && routes.storageDealUpload ? routes.storageDealUpload : `/api/data/deal/`;
const generalRoute = routes && routes.upload ? routes.upload : "/api/data/";
if (bucketName && bucketName === STAGING_DEAL_BUCKET) {
res = await _privateUploadMethod(`/api/data/deal/${file.name}`, file);
res = await _privateUploadMethod(`${storageDealRoute}${file.name}`, file);
} else {
res = await _privateUploadMethod(`/api/data/${file.name}`, file);
res = await _privateUploadMethod(`${generalRoute}${file.name}`, file);
}
if (!res || res.error || !res.data) {
@ -176,8 +184,7 @@ export const uploadToSlate = async ({ responses, slate }) => {
name: "create-alert",
detail: {
alert: {
message:
"We're having trouble connecting right now. Please try again later",
message: "We're having trouble connecting right now. Please try again later",
},
},
});
@ -193,9 +200,7 @@ export const uploadToSlate = async ({ responses, slate }) => {
skipped = addResponse.skipped;
}
}
let message = `${added || 0} file${
added !== 1 ? "s" : ""
} uploaded to slate. `;
let message = `${added || 0} file${added !== 1 ? "s" : ""} uploaded to slate. `;
if (skipped) {
message += `${skipped || 0} duplicate / existing file${
added !== 1 ? "s were" : " was"

View File

@ -303,6 +303,7 @@ export default class ApplicationPage extends React.Component {
response = await FileUtilities.upload({
file: files[i],
context: this,
routes: this.props.resources,
});
} catch (e) {
console.log(e);
@ -817,6 +818,7 @@ export default class ApplicationPage extends React.Component {
onRehydrate: this.rehydrate,
sceneId: current.target.id,
mobile: this.state.mobile,
resources: this.props.resources,
});
let sidebarElement;
@ -837,6 +839,7 @@ export default class ApplicationPage extends React.Component {
onSidebarLoading: this._handleSidebarLoading,
onAction: this._handleAction,
onRehydrate: this.rehydrate,
resources: this.props.resources,
});
}

View File

@ -14,8 +14,7 @@ export const POSTGRES_ADMIN_USERNAME = process.env.POSTGRES_ADMIN_USERNAME;
export const POSTGRES_HOSTNAME = process.env.POSTGRES_HOSTNAME;
export const POSTGRES_DATABASE = process.env.POSTGRES_DATABASE;
export const JWT_SECRET = process.env.JWT_SECRET;
export const LOCAL_PASSWORD_ROUNDS_MANUAL =
process.env.LOCAL_PASSWORD_ROUNDS_MANUAL;
export const LOCAL_PASSWORD_ROUNDS_MANUAL = process.env.LOCAL_PASSWORD_ROUNDS_MANUAL;
export const LOCAL_PASSWORD_ROUNDS = process.env.LOCAL_PASSWORD_ROUNDS;
// TODO(jim):
@ -34,3 +33,7 @@ export const TEXTILE_HUB_STAGING_HOST = process.env.TEXTILE_HUB_STAGING_HOST;
export const SOCIAL_SLACK_WEBHOOK_KEY = process.env.SOCIAL_SLACK_WEBHOOK_KEY;
export const SUPPORT_SLACK_WEBHOOK_KEY = process.env.SUPPORT_SLACK_WEBHOOK_KEY;
export const TEXTILE_SLACK_WEBHOOK_KEY = process.env.TEXTILE_SLACK_WEBHOOK_KEY;
// NOTE(jim): customize resources
export const RESOURCE_URI_UPLOAD = process.env.RESOURCE_URI_UPLOAD;
export const RESOURCE_URI_STORAGE_UPLOAD = process.env.RESOURCE_URI_STORAGE_UPLOAD;

View File

@ -19,32 +19,20 @@ export const init = (middleware) => {
};
export const CORS = async (req, res, next) => {
/*
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, PUT, DELETE, OPTIONS"
);
res.header(
"Access-Control-Allow-Headers",
"Origin, Accept, Content-Type, Authorization"
);
res.header("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, Authorization");
if (req.method === "OPTIONS") {
return res.status(200).end();
}
*/
next();
};
export const RequireCookieAuthentication = async (req, res, next) => {
if (Strings.isEmpty(req.headers.cookie)) {
return res
.status(403)
.json({ decorator: "SERVER_AUTH_USER_NO_TOKEN", error: true });
return res.status(403).json({ decorator: "SERVER_AUTH_USER_NO_TOKEN", error: true });
}
const token = req.headers.cookie.replace(
@ -60,15 +48,11 @@ export const RequireCookieAuthentication = async (req, res, next) => {
});
if (!user || user.error) {
return res
.status(403)
.json({ decorator: "SERVER_AUTH_USER_NOT_FOUND", error: true });
return res.status(403).json({ decorator: "SERVER_AUTH_USER_NOT_FOUND", error: true });
}
} catch (err) {
console.log(err);
return res
.status(403)
.json({ decorator: "SERVER_AUTH_USER_ERROR", error: true });
return res.status(403).json({ decorator: "SERVER_AUTH_USER_ERROR", error: true });
}
next();

View File

@ -8,6 +8,7 @@ export const getServerSideProps = async ({ query }) => {
viewer: query.viewer,
analytics: query.analytics,
mobile: query.mobile,
resources: query.resources,
},
};
};
@ -19,6 +20,7 @@ export default class ApplicationPage extends React.Component {
viewer={this.props.viewer}
analytics={this.props.analytics}
mobile={this.props.mobile}
resources={this.props.resources}
/>
);
}

View File

@ -19,9 +19,7 @@ export default async (req, res) => {
});
if (!user || user.error) {
return res
.status(403)
.send({ decorator: "UPLOAD_NOT_ALLOWED", error: true });
return res.status(403).send({ decorator: "UPLOAD_NOT_ALLOWED", error: true });
}
let response = null;
@ -35,15 +33,11 @@ export default async (req, res) => {
}
if (!response) {
return res
.status(413)
.send({ decorator: "SERVER_UPLOAD_ERROR", error: true });
return res.status(413).send({ decorator: "SERVER_UPLOAD_ERROR", error: true });
}
if (response.error) {
return res
.status(413)
.send({ decorator: response.decorator, error: response.error });
return res.status(413).send({ decorator: response.decorator, error: response.error });
}
const { data, ipfs } = response;
@ -52,14 +46,11 @@ export default async (req, res) => {
ipfs,
});
const slateId = req.params ? req.params.b : null;
return res.status(200).send({
decorator: "SERVER_UPLOAD",
data: {
data: finalData,
owner_user_id: user.id,
slate_id: slateId,
},
});
};

View File

@ -22,9 +22,7 @@ export default async (req, res) => {
});
if (!user || user.error) {
return res
.status(403)
.send({ decorator: "UPLOAD_NOT_ALLOWED", error: true });
return res.status(403).send({ decorator: "UPLOAD_NOT_ALLOWED", error: true });
}
let response = null;
@ -39,15 +37,11 @@ export default async (req, res) => {
}
if (!response) {
return res
.status(413)
.send({ decorator: "SERVER_UPLOAD_ERROR", error: true });
return res.status(413).send({ decorator: "SERVER_UPLOAD_ERROR", error: true });
}
if (response.error) {
return res
.status(413)
.send({ decorator: response.decorator, error: response.error });
return res.status(413).send({ decorator: response.decorator, error: response.error });
}
return res.status(200).send({

View File

@ -38,12 +38,9 @@ export default class SceneEditAccount extends React.Component {
photo: this.props.viewer.data.photo,
name: this.props.viewer.data.name,
deleting: false,
allow_filecoin_directory_listing: this.props.viewer
.allow_filecoin_directory_listing,
allow_automatic_data_storage: this.props.viewer
.allow_automatic_data_storage,
allow_encrypted_data_storage: this.props.viewer
.allow_encrypted_data_storage,
allow_filecoin_directory_listing: this.props.viewer.allow_filecoin_directory_listing,
allow_automatic_data_storage: this.props.viewer.allow_automatic_data_storage,
allow_encrypted_data_storage: this.props.viewer.allow_encrypted_data_storage,
changingPassword: false,
changingUsername: false,
changingAvatar: false,
@ -78,7 +75,7 @@ export default class SceneEditAccount extends React.Component {
return;
}
const response = await FileUtilities.upload({ file });
const response = await FileUtilities.upload({ file, routes: this.props.resources });
if (!response) {
dispatchCustomEvent({
@ -140,8 +137,7 @@ export default class SceneEditAccount extends React.Component {
photo: this.state.photo,
body: this.state.body,
name: this.state.name,
allow_filecoin_directory_listing: this.state
.allow_filecoin_directory_listing,
allow_filecoin_directory_listing: this.state.allow_filecoin_directory_listing,
allow_automatic_data_storage: this.state.allow_automatic_data_storage,
allow_encrypted_data_storage: this.state.allow_encrypted_data_storage,
},
@ -247,19 +243,10 @@ export default class SceneEditAccount extends React.Component {
description="This image will appear in various lists."
/>
<Avatar
style={{ marginTop: 24 }}
size={256}
url={this.props.viewer.data.photo}
/>
<Avatar style={{ marginTop: 24 }} size={256} url={this.props.viewer.data.photo} />
<div style={{ marginTop: 24 }}>
<input
css={STYLES_FILE_HIDDEN}
type="file"
id="file"
onChange={this._handleUpload}
/>
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
<System.ButtonPrimary
style={{ margin: "0 16px 16px 0" }}
type="label"
@ -282,8 +269,7 @@ export default class SceneEditAccount extends React.Component {
value={this.state.allow_filecoin_directory_listing}
onChange={this._handleCheckboxChange}
>
Show your successful deals on a directory page where others can
retrieve them.
Show your successful deals on a directory page where others can retrieve them.
</System.CheckBox>
<System.CheckBox
@ -292,8 +278,8 @@ export default class SceneEditAccount extends React.Component {
value={this.state.allow_automatic_data_storage}
onChange={this._handleCheckboxChange}
>
Allow Slate to make archive storage deals on your behalf to the
Filecoin Network. You will get a receipt in the Filecoin section.
Allow Slate to make archive storage deals on your behalf to the Filecoin Network. You will
get a receipt in the Filecoin section.
</System.CheckBox>
<System.CheckBox
@ -302,8 +288,8 @@ export default class SceneEditAccount extends React.Component {
value={this.state.allow_encrypted_data_storage}
onChange={this._handleCheckboxChange}
>
Force encryption on archive storage deals (only you can see retrieved
data from the Filecoin network).
Force encryption on archive storage deals (only you can see retrieved data from the
Filecoin network).
</System.CheckBox>
<div style={{ marginTop: 24 }}>
@ -320,8 +306,7 @@ export default class SceneEditAccount extends React.Component {
label="Username"
description={
<React.Fragment>
This is your username on Slate. Your username is unique and used
for your profile URL{" "}
This is your username on Slate. Your username is unique and used for your profile URL{" "}
<a href={profileURL} target="_blank">
{profileURL}
</a>
@ -334,10 +319,7 @@ export default class SceneEditAccount extends React.Component {
/>
<div style={{ marginTop: 24 }}>
<System.ButtonPrimary
onClick={this._handleSave}
loading={this.state.changingUsername}
>
<System.ButtonPrimary onClick={this._handleSave} loading={this.state.changingUsername}>
Change username
</System.ButtonPrimary>
</div>
@ -363,10 +345,7 @@ export default class SceneEditAccount extends React.Component {
/>
<div style={{ marginTop: 24 }}>
<System.ButtonPrimary
onClick={this._handleSaveBio}
loading={this.state.changingBio}
>
<System.ButtonPrimary onClick={this._handleSaveBio} loading={this.state.changingBio}>
Update information
</System.ButtonPrimary>
</div>
@ -413,10 +392,7 @@ export default class SceneEditAccount extends React.Component {
/>
<div style={{ marginTop: 24 }}>
<System.ButtonPrimary
onClick={this._handleDelete}
loading={this.state.deleting}
>
<System.ButtonPrimary onClick={this._handleDelete} loading={this.state.deleting}>
Delete my account
</System.ButtonPrimary>
</div>

View File

@ -102,6 +102,7 @@ export default class SceneMakeFilecoinDeal extends React.Component {
const response = await FileUtilities.upload({
bucketName: STAGING_DEAL_BUCKET,
routes: this.props.resources,
file,
});
}

View File

@ -93,6 +93,10 @@ app.prepare().then(async () => {
viewer,
analytics,
mobile,
resources: {
storageDealUpload: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Environment.RESOURCE_URI_UPLOAD,
},
});
});
@ -119,7 +123,13 @@ app.prepare().then(async () => {
// TODO(jim): Temporary workaround
if (!Validations.userRoute(req.params.username)) {
return handler(req, res, req.url, { mobile });
return handler(req, res, req.url, {
mobile,
resources: {
storageDealUpload: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Environment.RESOURCE_URI_UPLOAD,
},
});
}
const id = Utilities.getIdFromCookie(req);
@ -152,6 +162,10 @@ app.prepare().then(async () => {
viewer,
creator: Serializers.user({ ...creator, slates }),
mobile,
resources: {
storageDealUpload: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Environment.RESOURCE_URI_UPLOAD,
},
});
});
@ -160,7 +174,13 @@ app.prepare().then(async () => {
// TODO(jim): Temporary workaround
if (!Validations.userRoute(req.params.username)) {
return handler(req, res, req.url, { mobile });
return handler(req, res, req.url, {
mobile,
resources: {
storageDealUpload: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Environment.RESOURCE_URI_UPLOAD,
},
});
}
const slate = await Data.getSlateByName({
@ -208,6 +228,10 @@ app.prepare().then(async () => {
creator: Serializers.user(creator),
slate,
mobile,
resources: {
storageDealUpload: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Environment.RESOURCE_URI_UPLOAD,
},
});
});