mirror of
https://github.com/filecoin-project/slate.git
synced 2025-01-08 18:37:24 +03:00
api: lands get slate and add data to slate by id
This commit is contained in:
parent
9bb6ac2eda
commit
d1048382d7
@ -21,6 +21,14 @@ export const copyText = (str) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export const getKey = (text) => {
|
||||
if (isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return text.replace("Basic ", "");
|
||||
};
|
||||
|
||||
export const createSlug = (text) => {
|
||||
if (isEmpty(text)) {
|
||||
return "untitled";
|
||||
|
@ -271,7 +271,7 @@ export const injectCodeBlockStyles = () => css`
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #444;
|
||||
color: #FF00FF;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
|
@ -67,7 +67,11 @@ class CodeBlock extends React.Component {
|
||||
const textMap = codeBlockToken;
|
||||
|
||||
return (
|
||||
<div css={STYLES_CODE_BLOCK} className="language-javascript">
|
||||
<div
|
||||
css={STYLES_CODE_BLOCK}
|
||||
className="language-javascript"
|
||||
style={this.props.style}
|
||||
>
|
||||
{textMap.map((element, index) => {
|
||||
return (
|
||||
<div css={STYLES_LINE} key={`${element}-${index}`}>
|
||||
|
@ -14,6 +14,7 @@ import createAPIKeyForUserId from "~/node_common/data/methods/create-api-key-for
|
||||
import deleteAPIKeyById from "~/node_common/data/methods/delete-api-key-by-id";
|
||||
import deleteAPIKeysForUserId from "~/node_common/data/methods/delete-api-keys-for-user-id";
|
||||
import getAPIKey from "~/node_common/data/methods/get-api-key";
|
||||
import getAPIKeyByKey from "~/node_common/data/methods/get-api-key-by-key";
|
||||
import getAPIKeysByUserId from "~/node_common/data/methods/get-api-keys-by-user-id";
|
||||
|
||||
export {
|
||||
@ -34,5 +35,6 @@ export {
|
||||
deleteAPIKeyById,
|
||||
deleteAPIKeysForUserId,
|
||||
getAPIKey,
|
||||
getAPIKeyByKey,
|
||||
getAPIKeysByUserId,
|
||||
};
|
||||
|
31
node_common/data/methods/get-api-key-by-key.js
Normal file
31
node_common/data/methods/get-api-key-by-key.js
Normal file
@ -0,0 +1,31 @@
|
||||
import { runQuery } from "~/node_common/data/utilities";
|
||||
|
||||
export default async ({ key }) => {
|
||||
return await runQuery({
|
||||
label: "GET_API_KEY_BY_KEY",
|
||||
queryFn: async (DB) => {
|
||||
const query = await DB.select("*")
|
||||
.from("keys")
|
||||
.where({ key })
|
||||
.first();
|
||||
|
||||
console.log(query);
|
||||
|
||||
if (!query || query.error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (query.id) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
return {
|
||||
error: "GET_API_KEY_BY_KEY",
|
||||
source: e,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
@ -20,7 +20,7 @@ export default async ({ id, slatename, updated_at, data }) => {
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
return {
|
||||
error: "UPDATE_SLATE",
|
||||
error: "UPDATE_SLATE_BY_ID",
|
||||
source: e,
|
||||
};
|
||||
},
|
||||
|
@ -32,7 +32,7 @@ export default async ({ id, data, username, salt, password }) => {
|
||||
},
|
||||
errorFn: async (e) => {
|
||||
return {
|
||||
error: "UPDATE_USER",
|
||||
error: "UPDATE_USER_BY_ID",
|
||||
source: e,
|
||||
};
|
||||
},
|
||||
|
@ -1,7 +1,39 @@
|
||||
import * as React from "react";
|
||||
import * as System from "../dist";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
|
||||
const STYLES_FILE_HIDDEN = css`
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
position: fixed;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
`;
|
||||
|
||||
export default class SlateReactSystemPage extends React.Component {
|
||||
_handleUpload = async (e) => {
|
||||
e.persist();
|
||||
|
||||
const url = "/api/v1/upload-data/--";
|
||||
let file = e.target.files[0];
|
||||
let data = new FormData();
|
||||
|
||||
data.append("image", file);
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: "Basic --",
|
||||
},
|
||||
body: data,
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
console.log(json);
|
||||
};
|
||||
|
||||
render() {
|
||||
console.log(System.Constants);
|
||||
|
||||
@ -15,9 +47,21 @@ export default class SlateReactSystemPage extends React.Component {
|
||||
correctly.
|
||||
<br />
|
||||
<br />
|
||||
<System.ButtonPrimary>Primary</System.ButtonPrimary>
|
||||
<System.ButtonSecondary>Secondary</System.ButtonSecondary>
|
||||
<System.ButtonDisabled>Disabled</System.ButtonDisabled>
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<input
|
||||
css={STYLES_FILE_HIDDEN}
|
||||
type="file"
|
||||
id="file"
|
||||
onChange={this._handleUpload}
|
||||
/>
|
||||
<System.ButtonPrimary
|
||||
style={{ margin: "0 16px 16px 0" }}
|
||||
type="label"
|
||||
htmlFor="file"
|
||||
>
|
||||
Pick avatar
|
||||
</System.ButtonPrimary>
|
||||
</div>
|
||||
</System.P>
|
||||
</div>
|
||||
);
|
||||
|
94
pages/api/v1/get-slate.js
Normal file
94
pages/api/v1/get-slate.js
Normal file
@ -0,0 +1,94 @@
|
||||
import * as MW from "~/node_common/middleware";
|
||||
import * as Utilities from "~/node_common/utilities";
|
||||
import * as Data from "~/node_common/data";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Powergate from "~/node_common/powergate";
|
||||
|
||||
const initCORS = MW.init(MW.CORS);
|
||||
|
||||
export default async (req, res) => {
|
||||
initCORS(req, res);
|
||||
|
||||
if (Strings.isEmpty(req.headers.authorization)) {
|
||||
return res.status(404).send({
|
||||
decorator: "SERVER_API_KEY_MISSING",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
const parsed = Strings.getKey(req.headers.authorization);
|
||||
|
||||
const key = await Data.getAPIKeyByKey({
|
||||
key: parsed,
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
return res.status(403).send({
|
||||
decorator: "V1_GET_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (key.error) {
|
||||
return res.status(500).send({
|
||||
decorator: "V1_GET_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
const user = await Data.getUserById({
|
||||
id: key.owner_id,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ decorator: "V1_GET_SLATE_USER_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
if (user.error) {
|
||||
return res
|
||||
.status(500)
|
||||
.json({ decorator: "V1_GET_SLATE_USER_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
let slateId = req.body.data ? req.body.data.id : null;
|
||||
let slate;
|
||||
|
||||
if (Strings.isEmpty(slateId)) {
|
||||
const slates = await Data.getSlatesByUserId({ userId: user.id });
|
||||
if (!slates) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ decorator: "V1_GET_SLATE_SLATE_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
if (slates.error || !slates.length) {
|
||||
return res
|
||||
.status(500)
|
||||
.json({ decorator: "V1_GET_SLATE_SLATE_NOT_FOUND", error: true });
|
||||
}
|
||||
|
||||
return res
|
||||
.status(200)
|
||||
.json({ decorator: "V1_GET_SLATE_MOST_RECENT", slate: slates[0] });
|
||||
}
|
||||
|
||||
slate = await Data.getSlateById({ id: slateId });
|
||||
|
||||
if (!slate) {
|
||||
return res.status(404).json({
|
||||
decorator: "V1_GET_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (slate.error) {
|
||||
return res.status(500).json({
|
||||
decorator: "V1_GET_SLATE_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({ decorator: "V1_GET_SLATE", slate });
|
||||
};
|
181
pages/api/v1/upload-data/[id].js
Normal file
181
pages/api/v1/upload-data/[id].js
Normal file
@ -0,0 +1,181 @@
|
||||
import * as MW from "~/node_common/middleware";
|
||||
import * as Constants from "~/node_common/constants";
|
||||
import * as Data from "~/node_common/data";
|
||||
import * as Utilities from "~/node_common/utilities";
|
||||
import * as LibraryManager from "~/node_common/managers/library";
|
||||
import * as Strings from "~/common/strings";
|
||||
|
||||
import FORM from "formidable";
|
||||
import FS from "fs-extra";
|
||||
|
||||
const initCORS = MW.init(MW.CORS);
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default async (req, res) => {
|
||||
initCORS(req, res);
|
||||
|
||||
if (Strings.isEmpty(req.headers.authorization)) {
|
||||
return res.status(404).send({
|
||||
decorator: "SERVER_API_KEY_MISSING",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE(jim): Get Slate to make sure we can add to it.
|
||||
let slate = await Data.getSlateById({ id: req.query.id });
|
||||
|
||||
if (!slate) {
|
||||
return res.status(404).json({
|
||||
decorator: "V1_SERVER_UPLOAD_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (slate.error) {
|
||||
return res.status(500).json({
|
||||
decorator: "V1_SERVER_UPLOAD_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
const parsed = Strings.getKey(req.headers.authorization);
|
||||
const key = await Data.getAPIKeyByKey({
|
||||
key: parsed,
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
return res.status(403).send({
|
||||
decorator: "V1_SERVER_API_KEY_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (key.error) {
|
||||
return res.status(500).send({
|
||||
decorator: "V1_SERVER_API_KEY_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
const f = new FORM.IncomingForm();
|
||||
f.uploadDir = Constants.FILE_STORAGE_URL;
|
||||
f.keepExtensions = true;
|
||||
f.parse(req, async (e, fields, files) => {
|
||||
if (e) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "V1_SERVER_UPLOAD_PARSE_FAILURE", error: true });
|
||||
}
|
||||
|
||||
if (!files.image) {
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "V1_SERVER_UPLOAD_NOT_IMAGE_TYPE", error: true });
|
||||
}
|
||||
|
||||
const path = files.image._writeStream.path;
|
||||
const data = LibraryManager.createLocalDataIncomplete(files.image);
|
||||
|
||||
// TODO(jim): Send this file to buckets.
|
||||
const id = Utilities.getIdFromCookie(req);
|
||||
const user = await Data.getUserById({
|
||||
id: key.owner_id,
|
||||
});
|
||||
|
||||
const {
|
||||
buckets,
|
||||
bucketKey,
|
||||
bucketName,
|
||||
} = await Utilities.getBucketAPIFromUserToken(user.data.tokens.api);
|
||||
|
||||
let readFile;
|
||||
let push;
|
||||
try {
|
||||
// NOTE(jim): Push pathPath to your bucket.
|
||||
readFile = await FS.readFileSync(path).buffer;
|
||||
push = await buckets.pushPath(bucketKey, data.name, readFile);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return res
|
||||
.status(500)
|
||||
.send({ decorator: "V1_SERVER_BUCKETS_PUSH_ISSUE", error: true });
|
||||
}
|
||||
|
||||
// NOTE(jim): Update your user flag.
|
||||
const updated = LibraryManager.updateDataIPFS(data, {
|
||||
ipfs: push.path.path,
|
||||
});
|
||||
|
||||
// NOTE(jim): Update your library
|
||||
const updatedUserData = LibraryManager.addData({ user, data: updated });
|
||||
|
||||
// NOTE(jim): Update your user
|
||||
const response = await Data.updateUserById({
|
||||
id: user.id,
|
||||
data: updatedUserData,
|
||||
});
|
||||
|
||||
// NOTE(jim): Remove the file when you're done with it.
|
||||
await FS.unlinkSync(`./${path}`);
|
||||
|
||||
// NOTE(jim): Make the call again to handle any time difference.
|
||||
slate = await Data.getSlateById({ id: req.query.id });
|
||||
|
||||
if (!slate) {
|
||||
return res.status(404).json({
|
||||
decorator: "V1_SERVER_UPLOAD_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (slate.error) {
|
||||
return res.status(500).json({
|
||||
decorator: "V1_SERVER_UPLOAD_SLATE_NOT_FOUND",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
// NOTE(jim): We have a key, we know the slate is real, so add to it.
|
||||
const update = await Data.updateSlateById({
|
||||
id: slate.id,
|
||||
updated_at: new Date(),
|
||||
data: {
|
||||
...slate.data,
|
||||
objects: [
|
||||
{
|
||||
id: updated.id,
|
||||
ownerId: user.id,
|
||||
name: updated.name,
|
||||
url: `https://hub.textile.io${updated.ipfs}`,
|
||||
},
|
||||
...slate.data.objects,
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
if (!update) {
|
||||
return res.status(500).json({
|
||||
decorator: "V1_SERVER_UPLOAD_TO_SLATE_ERROR",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (update.error) {
|
||||
return res.status(500).json({
|
||||
decorator: "V1_SERVER_UPLOAD_TO_SLATE_ERROR",
|
||||
error: true,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
decorator: "V1_UPLOAD_DATA_TO_SLATE",
|
||||
data: updated,
|
||||
slate: update,
|
||||
});
|
||||
});
|
||||
};
|
@ -7,6 +7,7 @@ import * as SVG from "~/components/system/svg";
|
||||
import { css } from "@emotion/react";
|
||||
|
||||
import ScenePage from "~/components/core/ScenePage";
|
||||
import CodeBlock from "~/components/system/CodeBlock";
|
||||
|
||||
const STYLES_KEY = css`
|
||||
display: flex;
|
||||
@ -82,6 +83,77 @@ class Key extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const EXAMPLE_GET_SLATE = (
|
||||
key,
|
||||
slateId
|
||||
) => `// NOTE: set a slate by ID in an async/await function
|
||||
|
||||
const response = await fetch('https://slate.host/api/v1/get-slate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// NOTE: your API key
|
||||
Authorization: 'Basic ${key}',
|
||||
},
|
||||
body: JSON.stringify({ data: {
|
||||
// NOTE: your slate id
|
||||
id: ${slateId}
|
||||
}})
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
console.log(json);`;
|
||||
|
||||
const EXAMPLE_GET_SLATE_RESPONSE = (
|
||||
key
|
||||
) => `// NOTE: get a slate by ID JSON response
|
||||
|
||||
{
|
||||
data: {
|
||||
id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
|
||||
updated_at: '2020-07-27T09:04:53.007Z',
|
||||
created_at: '2020-07-27T09:04:53.007Z',
|
||||
published_at: '2020-07-27T09:04:53.007Z',
|
||||
slatename: 'slatename',
|
||||
data: {
|
||||
name: "slatename",
|
||||
public: true,
|
||||
objects: [
|
||||
{
|
||||
id: "data-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
name: "data-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
ownerId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
url: "https://slate.host/static/social.png"
|
||||
}
|
||||
],
|
||||
ownerId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const EXAMPLE_UPLOAD_TO_SLATE = (key, slateId) => `// NOTE
|
||||
// Upload data to a Slate by id in an async/await function.
|
||||
// Uses event data from a type="file" input.
|
||||
|
||||
// NOTE: your slate id
|
||||
const url = 'https://slate.host/api/v1/upload-data/${slateId}';
|
||||
|
||||
let file = e.target.files[0];
|
||||
let data = new FormData();
|
||||
data.append("image", file);
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
// NOTE: your API key
|
||||
Authorization: 'Basic ${key}',
|
||||
},
|
||||
body: data
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
console.log(json);`;
|
||||
|
||||
export default class SceneSettingsDeveloper extends React.Component {
|
||||
state = {
|
||||
loading: false,
|
||||
@ -126,7 +198,41 @@ export default class SceneSettingsDeveloper extends React.Component {
|
||||
this.setState({ loading: false });
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
if (!this.props.viewer.keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.props.viewer.keys.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch("/api/v1/get-slate", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Basic ${this.props.viewer.keys[0].key}`,
|
||||
},
|
||||
});
|
||||
const json = await response.json();
|
||||
console.log(json);
|
||||
}
|
||||
|
||||
render() {
|
||||
let key;
|
||||
if (this.props.viewer.keys) {
|
||||
if (this.props.viewer.keys.length) {
|
||||
key = this.props.viewer.keys[0].key;
|
||||
}
|
||||
}
|
||||
|
||||
let slateId = "your-slate-uuid-v4-value";
|
||||
if (this.props.viewer.slates) {
|
||||
if (this.props.viewer.slates.length) {
|
||||
slateId = this.props.viewer.slates[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ScenePage>
|
||||
<System.H1>API Key</System.H1>
|
||||
@ -148,6 +254,36 @@ export default class SceneSettingsDeveloper extends React.Component {
|
||||
Generate
|
||||
</System.ButtonPrimary>
|
||||
</div>
|
||||
|
||||
{key ? (
|
||||
<React.Fragment>
|
||||
<System.H2 style={{ marginTop: 64 }}>Usage (JavaScript)</System.H2>
|
||||
<System.DescriptionGroup
|
||||
style={{ marginTop: 48 }}
|
||||
label="Get slate by ID"
|
||||
description="If you have the ID of your slate you can make a request for it. If you don't provide an ID you will get back the most recent slate you have made."
|
||||
/>
|
||||
<CodeBlock
|
||||
children={EXAMPLE_GET_SLATE(key, slateId)}
|
||||
style={{ maxWidth: "768px" }}
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<CodeBlock
|
||||
children={EXAMPLE_GET_SLATE_RESPONSE(key)}
|
||||
style={{ maxWidth: "768px" }}
|
||||
/>
|
||||
<System.DescriptionGroup
|
||||
style={{ marginTop: 48 }}
|
||||
label="Upload data to slate by ID"
|
||||
description="You can use an HTML input field to get a file from the JavaScript event and upload that file to a slate of your choice. You must have the correct slate ID for this to work."
|
||||
/>
|
||||
<CodeBlock
|
||||
children={EXAMPLE_UPLOAD_TO_SLATE(key, slateId)}
|
||||
style={{ maxWidth: "768px" }}
|
||||
/>
|
||||
</React.Fragment>
|
||||
) : null}
|
||||
</ScenePage>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user