edit account: fixes issues with avatar updating, adds local settings for a user

This commit is contained in:
jimmylee 2020-06-30 23:41:54 -07:00
parent 6b3b867559
commit 8251bc0ba7
7 changed files with 171 additions and 144 deletions

1
.gitignore vendored
View File

@ -19,4 +19,3 @@ public/static/files/*
public/static/system/* public/static/system/*
!public/static/system/.gitkeep !public/static/system/.gitkeep
!public/static/system/avatar.png

View File

@ -1,7 +1,7 @@
const STATIC_ADDRESS_TYPE_MAP = { const STATIC_ADDRESS_TYPE_MAP = {
bls: "BLS", bls: 'BLS',
secp256k1: "SECP256K1", secp256k1: 'SECP256K1',
multisig: "MULTISIG", multisig: 'MULTISIG',
}; };
const transformAddresses = (addrsList, info) => { const transformAddresses = (addrsList, info) => {
@ -28,8 +28,8 @@ const transformPeers = (peersList) => {
return peersList.map((each) => { return peersList.map((each) => {
return { return {
id: each.addrInfo.id, id: each.addrInfo.id,
"peer-avatar": null, 'peer-avatar': null,
"chain-head": null, 'chain-head': null,
height: null, height: null,
location: null, location: null,
upload: null, upload: null,
@ -39,7 +39,7 @@ const transformPeers = (peersList) => {
}; };
export const getInitialState = (props) => { export const getInitialState = (props) => {
const { status, messageList, peersList, addrsList, info, library } = props; const { status, messageList, peersList, addrsList, info, library, local } = props;
if (!info || !info.id) { if (!info || !info.id) {
return { return {
@ -57,8 +57,8 @@ export const getInitialState = (props) => {
return { return {
id: info.id, id: info.id,
name: "New Node", name: local.name,
photoURL: "/static/system/avatar.png", photoURL: local.photo,
upload_bandwidth: 0, upload_bandwidth: 0,
download_bandwidth: 0, download_bandwidth: 0,
@ -70,19 +70,13 @@ export const getInitialState = (props) => {
settings_cold_enabled: info.defaultConfig.cold.enabled, settings_cold_enabled: info.defaultConfig.cold.enabled,
settings_cold_default_address: info.defaultConfig.cold.filecoin.addr, settings_cold_default_address: info.defaultConfig.cold.filecoin.addr,
settings_cold_default_duration: settings_cold_default_duration: info.defaultConfig.cold.filecoin.dealMinDuration,
info.defaultConfig.cold.filecoin.dealMinDuration, settings_cold_default_replication_factor: info.defaultConfig.cold.filecoin.repFactor,
settings_cold_default_replication_factor: settings_cold_default_excluded_miners: info.defaultConfig.cold.filecoin.excludedMinersList,
info.defaultConfig.cold.filecoin.repFactor, settings_cold_default_trusted_miners: info.defaultConfig.cold.filecoin.trustedMinersList,
settings_cold_default_excluded_miners:
info.defaultConfig.cold.filecoin.excludedMinersList,
settings_cold_default_trusted_miners:
info.defaultConfig.cold.filecoin.trustedMinersList,
settings_cold_default_max_price: info.defaultConfig.cold.filecoin.maxPrice, settings_cold_default_max_price: info.defaultConfig.cold.filecoin.maxPrice,
settings_cold_default_auto_renew: settings_cold_default_auto_renew: info.defaultConfig.cold.filecoin.renew.enabled,
info.defaultConfig.cold.filecoin.renew.enabled, settings_cold_default_auto_renew_max_price: info.defaultConfig.cold.filecoin.renew.threshold,
settings_cold_default_auto_renew_max_price:
info.defaultConfig.cold.filecoin.renew.threshold,
notifications: [], notifications: [],
payment_channels_active: [], payment_channels_active: [],

View File

@ -1,30 +1,30 @@
import * as Constants from "~/node_common/constants"; import * as Constants from '~/node_common/constants';
import FS from "fs-extra"; import FS from 'fs-extra';
export const resetFileSystem = async () => { export const resetFileSystem = async () => {
console.log("[ prototype ] deleting old token and library data "); console.log('[ prototype ] deleting old token and library data ');
if (FS.existsSync(`./.data`)) { if (FS.existsSync(`./.data`)) {
FS.removeSync("./.data", { recursive: true }); FS.removeSync('./.data', { recursive: true });
} }
console.log("[ prototype ] deleting old avatar data "); console.log('[ prototype ] deleting old avatar data ');
if (FS.existsSync(Constants.AVATAR_STORAGE_URL)) { if (FS.existsSync(Constants.AVATAR_STORAGE_URL)) {
FS.removeSync(Constants.AVATAR_STORAGE_URL, { recursive: true }); FS.removeSync(Constants.AVATAR_STORAGE_URL, { recursive: true });
} }
console.log("[ prototype ] deleting old file data "); console.log('[ prototype ] deleting old file data ');
if (FS.existsSync(Constants.FILE_STORAGE_URL)) { if (FS.existsSync(Constants.FILE_STORAGE_URL)) {
FS.removeSync(Constants.FILE_STORAGE_URL, { recursive: true }); FS.removeSync(Constants.FILE_STORAGE_URL, { recursive: true });
} }
console.log("[ prototype ] creating new avatar folder "); console.log('[ prototype ] creating new avatar folder ');
FS.mkdirSync(Constants.AVATAR_STORAGE_URL, { recursive: true }); FS.mkdirSync(Constants.AVATAR_STORAGE_URL, { recursive: true });
FS.writeFileSync(`${Constants.AVATAR_STORAGE_URL}.gitkeep`, ""); FS.writeFileSync(`${Constants.AVATAR_STORAGE_URL}.gitkeep`, '');
console.log("[ prototype ] creating new local file folder "); console.log('[ prototype ] creating new local file folder ');
FS.mkdirSync(Constants.FILE_STORAGE_URL, { recursive: true }); FS.mkdirSync(Constants.FILE_STORAGE_URL, { recursive: true });
FS.writeFileSync(`${Constants.FILE_STORAGE_URL}.gitkeep`, ""); FS.writeFileSync(`${Constants.FILE_STORAGE_URL}.gitkeep`, '');
return true; return true;
}; };
@ -66,7 +66,7 @@ export const emitState = async ({ state, client, PG }) => {
}); });
if (client) { if (client) {
client.send(JSON.stringify({ action: "UPDATE_VIEWER", data })); client.send(JSON.stringify({ action: 'UPDATE_VIEWER', data }));
} }
return data; return data;
@ -74,18 +74,18 @@ export const emitState = async ({ state, client, PG }) => {
export const getFileName = (s) => { export const getFileName = (s) => {
let target = s; let target = s;
if (target.endsWith("/")) { if (target.endsWith('/')) {
target = target.substring(0, target.length - 1); target = target.substring(0, target.length - 1);
} }
return target.substr(target.lastIndexOf("/") + 1); return target.substr(target.lastIndexOf('/') + 1);
}; };
export const createFile = ({ id, data }) => { export const createFile = ({ id, data }) => {
return { return {
decorator: "FILE", decorator: 'FILE',
id: id, id: id,
icon: "PNG", icon: 'PNG',
file: getFileName(id), file: getFileName(id),
miner: null, miner: null,
job_id: null, job_id: null,
@ -103,10 +103,10 @@ export const createFile = ({ id, data }) => {
export const createFolder = ({ id }) => { export const createFolder = ({ id }) => {
return { return {
decorator: "FOLDER", decorator: 'FOLDER',
id, id,
folderId: id, folderId: id,
icon: "FOLDER", icon: 'FOLDER',
file: getFileName(id), file: getFileName(id),
name: getFileName(id), name: getFileName(id),
pageTitle: null, pageTitle: null,
@ -130,22 +130,16 @@ export const refreshLibrary = async ({ state, PG, FFS }) => {
for (let j = 0; j < state.library[i].children.length; j++) { for (let j = 0; j < state.library[i].children.length; j++) {
if (state.library[i].children[j].job_id) { if (state.library[i].children[j].job_id) {
if (state.library[i].children[j].storage_status === 1) { if (state.library[i].children[j].storage_status === 1) {
console.log( console.log('[ prototype ] update file', state.library[i].children[j]);
"[ prototype ] update file",
state.library[i].children[j]
);
state.library[i].children[j].storage_status = 2; state.library[i].children[j].storage_status = 2;
write = true; write = true;
continue; continue;
} }
PG.ffs.watchJobs((job) => { PG.ffs.watchJobs((job) => {
console.log("[ prototype ] job status", job.status); console.log('[ prototype ] job status', job.status);
if (job.status === FFS.JobStatus.JOB_STATUS_SUCCESS) { if (job.status === FFS.JobStatus.JOB_STATUS_SUCCESS) {
console.log( console.log('[ prototype ] update file', state.library[i].children[j]);
"[ prototype ] update file",
state.library[i].children[j]
);
state.library[i].children[j].storage_status = 6; state.library[i].children[j].storage_status = 6;
write = true; write = true;
} }
@ -155,10 +149,7 @@ export const refreshLibrary = async ({ state, PG, FFS }) => {
} }
if (write) { if (write) {
FS.writeFileSync( FS.writeFileSync('./.data/library.json', JSON.stringify({ library: state.library }));
"./.data/library.json",
JSON.stringify({ library: state.library })
);
} }
return { ...state }; return { ...state };

View File

@ -10,8 +10,8 @@
"start": "NODE_ENV=production node . --unhandled-rejections=strict" "start": "NODE_ENV=production node . --unhandled-rejections=strict"
}, },
"dependencies": { "dependencies": {
"@babel/preset-env": "^7.9.0", "@babel/preset-env": "^7.10.4",
"@babel/register": "^7.9.0", "@babel/register": "^7.10.4",
"@emotion/babel-preset-css-prop": "^10.0.27", "@emotion/babel-preset-css-prop": "^10.0.27",
"@emotion/cache": "11.0.0-next.12", "@emotion/cache": "11.0.0-next.12",
"@emotion/core": "^10.0.28", "@emotion/core": "^10.0.28",
@ -35,6 +35,7 @@
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-tippy": "^1.3.4", "react-tippy": "^1.3.4",
"three": "^0.108.0", "three": "^0.108.0",
"uuid": "^8.0.0",
"ws": "^7.3.0" "ws": "^7.3.0"
} }
} }

View File

@ -1,39 +1,39 @@
import * as React from "react"; import * as React from 'react';
import * as Fixtures from "~/common/fixtures"; import * as Fixtures from '~/common/fixtures';
import * as Actions from "~/common/actions"; import * as Actions from '~/common/actions';
import * as State from "~/common/state"; import * as State from '~/common/state';
import SceneDataTransfer from "~/scenes/SceneDataTransfer"; import SceneDataTransfer from '~/scenes/SceneDataTransfer';
import SceneDeals from "~/scenes/SceneDeals"; import SceneDeals from '~/scenes/SceneDeals';
import SceneEditAccount from "~/scenes/SceneEditAccount"; import SceneEditAccount from '~/scenes/SceneEditAccount';
import SceneFile from "~/scenes/SceneFile"; import SceneFile from '~/scenes/SceneFile';
import SceneFilesFolder from "~/scenes/SceneFilesFolder"; import SceneFilesFolder from '~/scenes/SceneFilesFolder';
import SceneHome from "~/scenes/SceneHome"; import SceneHome from '~/scenes/SceneHome';
import SceneLogs from "~/scenes/SceneLogs"; import SceneLogs from '~/scenes/SceneLogs';
import SceneMiners from "~/scenes/SceneMiners"; import SceneMiners from '~/scenes/SceneMiners';
import ScenePaymentChannels from "~/scenes/ScenePaymentChannels"; import ScenePaymentChannels from '~/scenes/ScenePaymentChannels';
import ScenePeers from "~/scenes/ScenePeers"; import ScenePeers from '~/scenes/ScenePeers';
import SceneSettings from "~/scenes/SceneSettings"; import SceneSettings from '~/scenes/SceneSettings';
import SceneStats from "~/scenes/SceneStats"; import SceneStats from '~/scenes/SceneStats';
import SceneStatus from "~/scenes/SceneStatus"; import SceneStatus from '~/scenes/SceneStatus';
import SceneStorageMarket from "~/scenes/SceneStorageMarket"; import SceneStorageMarket from '~/scenes/SceneStorageMarket';
import SceneWallet from "~/scenes/SceneWallet"; import SceneWallet from '~/scenes/SceneWallet';
import SidebarCreateWalletAddress from "~/components/sidebars/SidebarCreateWalletAddress"; import SidebarCreateWalletAddress from '~/components/sidebars/SidebarCreateWalletAddress';
import SidebarDeleteWalletAddress from "~/components/sidebars/SidebarDeleteWalletAddress"; import SidebarDeleteWalletAddress from '~/components/sidebars/SidebarDeleteWalletAddress';
import SidebarWalletSendFunds from "~/components/sidebars/SidebarWalletSendFunds"; import SidebarWalletSendFunds from '~/components/sidebars/SidebarWalletSendFunds';
import SidebarFileStorageDeal from "~/components/sidebars/SidebarFileStorageDeal"; import SidebarFileStorageDeal from '~/components/sidebars/SidebarFileStorageDeal';
import SidebarFileRetrievalDeal from "~/components/sidebars/SidebarFileRetrievalDeal"; import SidebarFileRetrievalDeal from '~/components/sidebars/SidebarFileRetrievalDeal';
import SidebarCreatePaymentChannel from "~/components/sidebars/SidebarCreatePaymentChannel"; import SidebarCreatePaymentChannel from '~/components/sidebars/SidebarCreatePaymentChannel';
import SidebarAddMiner from "~/components/sidebars/SidebarAddMiner"; import SidebarAddMiner from '~/components/sidebars/SidebarAddMiner';
import SidebarAddPeer from "~/components/sidebars/SidebarAddPeer"; import SidebarAddPeer from '~/components/sidebars/SidebarAddPeer';
import SidebarNotifications from "~/components/sidebars/SidebarNotifications"; import SidebarNotifications from '~/components/sidebars/SidebarNotifications';
import SidebarRedeemPaymentChannel from "~/components/sidebars/SidebarRedeemPaymentChannel"; import SidebarRedeemPaymentChannel from '~/components/sidebars/SidebarRedeemPaymentChannel';
import ApplicationNavigation from "~/components/core/ApplicationNavigation"; import ApplicationNavigation from '~/components/core/ApplicationNavigation';
import ApplicationHeader from "~/components/core/ApplicationHeader"; import ApplicationHeader from '~/components/core/ApplicationHeader';
import ApplicationLayout from "~/components/core/ApplicationLayout"; import ApplicationLayout from '~/components/core/ApplicationLayout';
import WebsitePrototypeWrapper from "~/components/core/WebsitePrototypeWrapper"; import WebsitePrototypeWrapper from '~/components/core/WebsitePrototypeWrapper';
const getCurrentNavigationStateById = (navigation, targetId) => { const getCurrentNavigationStateById = (navigation, targetId) => {
let target = null; let target = null;
@ -82,7 +82,7 @@ export default class IndexPage extends React.Component {
currentIndex: 0, currentIndex: 0,
data: null, data: null,
selected: { selected: {
address: "", address: '',
}, },
viewer: State.getInitialState(this.props), viewer: State.getInitialState(this.props),
sidebar: null, sidebar: null,
@ -92,10 +92,10 @@ export default class IndexPage extends React.Component {
this._socket = new WebSocket(`ws://localhost:${this.props.wsPort}`); this._socket = new WebSocket(`ws://localhost:${this.props.wsPort}`);
this._socket.onmessage = (m) => { this._socket.onmessage = (m) => {
console.log(m); console.log(m);
if (m.type === "message") { if (m.type === 'message') {
const parsed = JSON.parse(m.data); const parsed = JSON.parse(m.data);
if (parsed.action === "UPDATE_VIEWER") { if (parsed.action === 'UPDATE_VIEWER') {
this.rehydrate({ data: parsed.data }); this.rehydrate({ data: parsed.data });
} }
} }
@ -103,16 +103,17 @@ export default class IndexPage extends React.Component {
} }
rehydrate = async ({ data }) => { rehydrate = async ({ data }) => {
console.log(data);
this.setState({ viewer: { ...State.getInitialState(data) } }); this.setState({ viewer: { ...State.getInitialState(data) } });
}; };
_handleSubmit = async (data) => { _handleSubmit = async (data) => {
if (this.props.production) { if (this.props.production) {
alert("TODO"); alert('TODO');
return this._handleDismissSidebar(); return this._handleDismissSidebar();
} }
if (data.type === "CREATE_WALLET_ADDRESS") { if (data.type === 'CREATE_WALLET_ADDRESS') {
const address = await Actions.createWalletAddress({ const address = await Actions.createWalletAddress({
name: data.name, name: data.name,
type: data.wallet_type, type: data.wallet_type,
@ -120,7 +121,7 @@ export default class IndexPage extends React.Component {
}); });
} }
if (data.type === "SEND_WALLET_ADDRESS_FILECOIN") { if (data.type === 'SEND_WALLET_ADDRESS_FILECOIN') {
const response = await Actions.sendWalletAddressFilecoin({ const response = await Actions.sendWalletAddressFilecoin({
source: data.source, source: data.source,
target: data.target, target: data.target,
@ -152,19 +153,19 @@ export default class IndexPage extends React.Component {
}; };
_handleAction = (options) => { _handleAction = (options) => {
if (options.type === "NAVIGATE") { if (options.type === 'NAVIGATE') {
return this._handleNavigateTo({ id: options.value }, options.data); return this._handleNavigateTo({ id: options.value }, options.data);
} }
if (options.type === "ACTION") { if (options.type === 'ACTION') {
return alert(JSON.stringify(options)); return alert(JSON.stringify(options));
} }
if (options.type === "DOWNLOAD") { if (options.type === 'DOWNLOAD') {
return alert(JSON.stringify(options)); return alert(JSON.stringify(options));
} }
if (options.type === "SIDEBAR") { if (options.type === 'SIDEBAR') {
return this.setState({ sidebar: this.sidebars[options.value] }); return this.setState({ sidebar: this.sidebars[options.value] });
} }
@ -268,9 +269,7 @@ export default class IndexPage extends React.Component {
return null; return null;
} }
const navigation = Fixtures.generateNavigationState( const navigation = Fixtures.generateNavigationState(this.state.viewer.library);
this.state.viewer.library
);
const next = this.state.history[this.state.currentIndex]; const next = this.state.history[this.state.currentIndex];
const current = getCurrentNavigationStateById(navigation, next.id); const current = getCurrentNavigationStateById(navigation, next.id);
@ -323,22 +322,17 @@ export default class IndexPage extends React.Component {
} }
const title = `Prototype 0.0.1 : ${current.target.pageTitle}`; const title = `Prototype 0.0.1 : ${current.target.pageTitle}`;
const description = "This is an early preview."; const description = 'This is an early preview.';
const url = "https://fps.onrender.com/v1"; const url = 'https://fps.onrender.com/v1';
return ( return (
<React.Fragment> <React.Fragment>
<WebsitePrototypeWrapper <WebsitePrototypeWrapper title={title} description={description} url={url}>
title={title}
description={description}
url={url}
>
<ApplicationLayout <ApplicationLayout
navigation={navigationElement} navigation={navigationElement}
header={headerElement} header={headerElement}
sidebar={sidebarElement} sidebar={sidebarElement}
onDismissSidebar={this._handleDismissSidebar} onDismissSidebar={this._handleDismissSidebar}>
>
{scene} {scene}
</ApplicationLayout> </ApplicationLayout>
</WebsitePrototypeWrapper> </WebsitePrototypeWrapper>

View File

@ -1,11 +1,11 @@
import * as React from "react"; import * as React from 'react';
import * as System from "~/components/system"; import * as System from '~/components/system';
import * as Actions from "~/common/actions"; import * as Actions from '~/common/actions';
import { css } from "@emotion/react"; import { css } from '@emotion/react';
import ScenePage from "~/components/core/ScenePage"; import ScenePage from '~/components/core/ScenePage';
import Avatar from "~/components/core/Avatar"; import Avatar from '~/components/core/Avatar';
const STYLES_FILE_HIDDEN = css` const STYLES_FILE_HIDDEN = css`
height: 1px; height: 1px;
@ -18,21 +18,23 @@ const STYLES_FILE_HIDDEN = css`
`; `;
export default class SceneEditAccount extends React.Component { export default class SceneEditAccount extends React.Component {
state = { name: this.props.viewer.name };
_handleUpload = async (e) => { _handleUpload = async (e) => {
e.persist(); e.persist();
let file = e.target.files[0]; let file = e.target.files[0];
if (!file) { if (!file) {
alert("Something went wrong"); alert('Something went wrong');
} }
let data = new FormData(); let data = new FormData();
data.append("image", file); data.append('image', file);
const options = { const options = {
method: "POST", method: 'POST',
headers: { headers: {
Accept: "application/json", Accept: 'application/json',
}, },
body: data, body: data,
}; };
@ -40,8 +42,23 @@ export default class SceneEditAccount extends React.Component {
await fetch(`/_/upload/avatar`, options); await fetch(`/_/upload/avatar`, options);
}; };
_handleSave = async (e) => {
const options = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({ local: { name: this.state.name } }),
};
await fetch(`/_/local-settings`, options);
};
_handleChange = (e) => { _handleChange = (e) => {
this.props.onViewerChange(e); e.persist();
this.setState({ [e.target.name]: e.target.value });
}; };
render() { render() {
@ -55,24 +72,11 @@ export default class SceneEditAccount extends React.Component {
description="This image will appear in various lists." description="This image will appear in various lists."
/> />
<Avatar <Avatar style={{ marginTop: 24 }} size={256} url={this.props.viewer.photoURL} />
style={{ marginTop: 24 }}
size={256}
url={this.props.viewer.photoURL}
/>
<div style={{ marginTop: 24 }}> <div style={{ marginTop: 24 }}>
<input <input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
css={STYLES_FILE_HIDDEN} <System.ButtonPrimary style={{ margin: '0 16px 16px 0' }} type="label" htmlFor="file">
type="file"
id="file"
onChange={this._handleUpload}
/>
<System.ButtonPrimary
style={{ margin: "0 16px 16px 0" }}
type="label"
htmlFor="file"
>
Upload Upload
</System.ButtonPrimary> </System.ButtonPrimary>
</div> </div>
@ -82,10 +86,14 @@ export default class SceneEditAccount extends React.Component {
label="Name" label="Name"
description="The name of your Filecoin Client can be seen by your peers." description="The name of your Filecoin Client can be seen by your peers."
name="name" name="name"
value={this.props.viewer.name} value={this.state.name}
placeholder="Name" placeholder="Name"
onChange={this._handleChange} onChange={this._handleChange}
/> />
<div style={{ marginTop: 24 }}>
<System.ButtonPrimary onClick={this._handleSave}>Save</System.ButtonPrimary>
</div>
</ScenePage> </ScenePage>
); );
} }

View File

@ -4,6 +4,9 @@ import * as Utilities from '~/node_common/utilities';
import * as Constants from '~/node_common/constants'; import * as Constants from '~/node_common/constants';
import { createPow, ffs } from '@textile/powergate-client'; import { createPow, ffs } from '@textile/powergate-client';
// NOTE(jim):
// https://github.com/textileio/js-powergate-client
const PowerGate = createPow({ host: Constants.POWERGATE_HOST }); const PowerGate = createPow({ host: Constants.POWERGATE_HOST });
import FS from 'fs-extra'; import FS from 'fs-extra';
@ -13,6 +16,7 @@ import formidable from 'formidable';
import next from 'next'; import next from 'next';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import compression from 'compression'; import compression from 'compression';
import { v4 as uuid } from 'uuid';
// TODO(jim): Support multiple desktop applications. // TODO(jim): Support multiple desktop applications.
let client = null; let client = null;
@ -62,12 +66,13 @@ app.prepare().then(async () => {
peersList: null, peersList: null,
addrsList: null, addrsList: null,
info: null, info: null,
local: null,
}; };
if (!production) { if (!production) {
try {
// TODO(jim): Remove later. // TODO(jim): Remove later.
// We wipe all of the local data each time you run the application. // We wipe all of the local data each time you run the application.
try {
await Utilities.resetFileSystem(); await Utilities.resetFileSystem();
const updates = await Utilities.refresh({ PG: PowerGate }); const updates = await Utilities.refresh({ PG: PowerGate });
@ -75,11 +80,13 @@ app.prepare().then(async () => {
console.log('[ prototype ] updated without token'); console.log('[ prototype ] updated without token');
// NOTE(jim): This is a configuration folder with all of the client tokens. // NOTE(jim): This is a configuration folder with all of the client tokens.
// TODO(jim): Unnecessary if we use a local and remote postgres.
if (!FS.existsSync(`./.data`)) { if (!FS.existsSync(`./.data`)) {
FS.mkdirSync(`./.data`, { recursive: true }); FS.mkdirSync(`./.data`, { recursive: true });
} }
// NOTE(jim): This will create a token for authentication with powergate. // NOTE(jim): This will create a token for authentication with powergate.
// TODO(jim): Roll this up into Postgres instead.
if (!FS.existsSync('./.data/powergate-token')) { if (!FS.existsSync('./.data/powergate-token')) {
const FFS = await PowerGate.ffs.create(); const FFS = await PowerGate.ffs.create();
state.token = FFS.token ? FFS.token : null; state.token = FFS.token ? FFS.token : null;
@ -103,7 +110,9 @@ app.prepare().then(async () => {
state = await Utilities.updateStateData(state, tokenUpdates); state = await Utilities.updateStateData(state, tokenUpdates);
console.log('[ prototype ] updated with token'); console.log('[ prototype ] updated with token');
// NOTE(jim): Local library retrieval or creation
// TODO(jim): Needs to support nested folders in the future. // TODO(jim): Needs to support nested folders in the future.
// TODO(jim): May consider a move to buckets.
if (!FS.existsSync('./.data/library.json')) { if (!FS.existsSync('./.data/library.json')) {
const librarySchema = { const librarySchema = {
library: [ library: [
@ -121,8 +130,23 @@ app.prepare().then(async () => {
const parsedLibrary = FS.readFileSync('./.data/library.json', 'utf8'); const parsedLibrary = FS.readFileSync('./.data/library.json', 'utf8');
state.library = JSON.parse(parsedLibrary).library; state.library = JSON.parse(parsedLibrary).library;
} }
// NOTE(jim): Local settings retrieval or creation
// TODO(jim): Move this to postgres later.
if (!FS.existsSync('./.data/local-settings.json')) {
const localSettingsSchema = {
local: { photo: null, name: `node-${uuid()}` },
};
FS.writeFileSync('./.data/local-settings.json', JSON.stringify(localSettingsSchema));
state.local = localSettingsSchema.local;
} else {
const parsedLocal = FS.readFileSync('./data/local-settings.json', 'utf8');
state.local = JSON.parse(parsedLocal).local;
}
} catch (e) { } catch (e) {
console.log('[ prototype ] "/" - WILL REDIRECT TO /SYSTEM '); console.log(e);
console.log('[ prototype ] "/" -- WILL REDIRECT TO /SYSTEM ');
console.log('[ prototype ] SLATE WILL NOT RUN LOCALLY UNTIL YOU HAVE '); console.log('[ prototype ] SLATE WILL NOT RUN LOCALLY UNTIL YOU HAVE ');
console.log('[ prototype ] PROPERLY CONFIGURED POWERGATE AND '); console.log('[ prototype ] PROPERLY CONFIGURED POWERGATE AND ');
console.log('[ prototype ] CONNECTED TO THE FILECOIN NETWORK (DEVNET/TESTNET) '); console.log('[ prototype ] CONNECTED TO THE FILECOIN NETWORK (DEVNET/TESTNET) ');
@ -196,6 +220,7 @@ app.prepare().then(async () => {
} }
} }
// NOTE(jim): Writes the updated deal state.
if (write) { if (write) {
FS.writeFileSync('./.data/library.json', JSON.stringify({ library: state.library })); FS.writeFileSync('./.data/library.json', JSON.stringify({ library: state.library }));
} }
@ -238,6 +263,7 @@ app.prepare().then(async () => {
} }
} }
// NOTE(jim): Writes the added file.
if (pushed) { if (pushed) {
FS.writeFileSync('./.data/library.json', JSON.stringify({ library: state.library })); FS.writeFileSync('./.data/library.json', JSON.stringify({ library: state.library }));
} }
@ -263,14 +289,20 @@ app.prepare().then(async () => {
if (error) { if (error) {
return res.status(500).send({ error }); return res.status(500).send({ error });
} else { } else {
const newPath = form.uploadDir + 'avatar.png'; const newName = `avatar-${uuid()}.png`;
const newPath = form.uploadDir + newName;
FS.rename(files.image.path, newPath, function (err) {}); FS.rename(files.image.path, newPath, function (err) {});
// NOTE(jim): updates avatar photo.
state.local.photo = `/static/system/${newName}`;
FS.writeFileSync('./.data/local-settings.json', JSON.stringify({ local: { ...state.local } }));
state = await Utilities.emitState({ state = await Utilities.emitState({
state, state,
client, client,
PG: PowerGate, PG: PowerGate,
}); });
return res.status(200).send({ success: true }); return res.status(200).send({ success: true });
} }
}); });
@ -288,6 +320,14 @@ app.prepare().then(async () => {
return res.status(200).send({ success: true, data }); return res.status(200).send({ success: true, data });
}); });
server.post('/_/local-settings', async (req, res) => {
state.local = { ...state.local, ...req.body.local };
FS.writeFileSync('./.data/local-settings.json', JSON.stringify({ local: { ...state.local } }));
state = await Utilities.emitState({ state, client, PG: PowerGate });
return res.status(200).send({ success: true });
});
server.post('/_/wallet/create', async (req, res) => { server.post('/_/wallet/create', async (req, res) => {
let data; let data;
try { try {