mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-25 19:55:26 +03:00
supports custom resource URIs for two upload endpoints
This commit is contained in:
parent
9713a838a9
commit
15fa57c2df
@ -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"
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -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({
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
28
server.js
28
server.js
@ -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,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user