Skip to content

Commit

Permalink
Merge pull request #347 from csmartinsfct/hotfix/server_files_and_assets
Browse files Browse the repository at this point in the history
Server code updated, new-ish Asset Details page and file downloads!
  • Loading branch information
0xjjpa committed Dec 24, 2018
2 parents c80ec7b + f72cd9b commit c55f13f
Show file tree
Hide file tree
Showing 15 changed files with 318 additions and 51 deletions.
76 changes: 61 additions & 15 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const app = express();
const airtableBaseAssets = dev ? 'appnvQb0LqM1nKTTQ' : 'appDMxPZPCcBkNuab';

const base = new Airtable({apiKey: process.env.AIRTABLE_KEY}).base(airtableBaseAssets);
const SIZE_OF_ASSETID = 66;

if (dev) {
app.use((req, res, next) => {
Expand All @@ -28,6 +29,7 @@ if (dev) {

let assets = [];
let assetsLoaded = false;
let filesByAssetId = {};

const multerStorage = multer.memoryStorage();
const multipleUpload = multer({
Expand Down Expand Up @@ -76,6 +78,58 @@ async function UpdateAirTableEntry(id, currentAssetIds, newAssetId, country, cit
});
}

/*
// delete files from testing
var params = {
Bucket: bucketName,
Delete: {
Objects: [
{
Key: ''
}
],
Quiet: false
}
};
s3bucket.deleteObjects(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});*/

async function ProcessFilesForAssets(){
const params = {
Bucket: bucketName,
MaxKeys: 1000, // TODO: make this dynamic
};

s3bucket.listObjectsV2(params, (err, data) => {
if (err) {
console.log(err);
setTimeout(ProcessFilesForAssets, 10000);
} else {
const filesByAssetIdTmp = {};
for(const file of data.Contents){
const key = file.Key;

const indexOfHex = key.indexOf('0x');
const indexOfSeparator = key.indexOf(':');

if(indexOfHex !== -1 && indexOfSeparator !== -1){
const assetId = key.substring(0, indexOfSeparator);
const fileName = key.substring(indexOfSeparator + 1);
if(assetId.length === SIZE_OF_ASSETID){
if(!filesByAssetIdTmp[assetId]){
filesByAssetIdTmp[assetId] = [];
}
filesByAssetIdTmp[assetId].push(fileName);
}
}
}
filesByAssetId = filesByAssetIdTmp;
}
});
}

app.use(express.json())

app.post('/api/airtable/update', async function(req, res){
Expand Down Expand Up @@ -115,20 +169,9 @@ app.get('/api/assets', (req, res) => {
});
});

app.get('/api/files/list', (req, res) => {
const params = {
Bucket: bucketName,
MaxKeys: 1000, // TODO: make this dynamic
};

s3bucket.listObjectsV2(params, (err, data) => {
if (err) {
res.statusCode = 404;
res.json(err);
} else {
res.statusCode = 200;
res.json(data);
}
app.get('/api/assets/files', (req, res) => {
res.json({
filesByAssetId,
});
});

Expand All @@ -155,7 +198,8 @@ app.post('/api/files/upload', multipleUpload, (req, res) => {
} else {
ResponseData.push(data);
if (ResponseData.length === file.length) {
debug("Uploaded file(s) successfuly.")
ProcessFilesForAssets();
console.log("Uploaded file(s) successfuly.")
res.statusCode = 200;
res.json({
error: false,
Expand Down Expand Up @@ -190,6 +234,8 @@ async function pullAssets() {
}
}

ProcessFilesForAssets();

pullAssets();

setInterval(pullAssets, 60000);
4 changes: 4 additions & 0 deletions src/apis/brain.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,9 @@ export const fetchAssets = async (user, currentEthInUsd, assetsAirTableById, cat
const fundingStages = await Promise.all(assets.map(async asset =>
apiContract.methods.fundingStage(asset.assetID).call()));

const managerPercentages = await Promise.all(assets.map(async asset =>
apiContract.methods.managerPercentage(asset.assetID).call()));

let assetsPlusMoreDetails = await Promise.all(assets.map(async (asset, index) => {
const numberOfInvestors = await getNumberOfInvestors(asset.assetID);

Expand Down Expand Up @@ -515,6 +518,7 @@ export const fetchAssets = async (user, currentEthInUsd, assetsAirTableById, cat
details: assetIdDetails.details,
imageSrc: assetIdDetails.imageSrc,
fundingStage: fundingStages[index],
managerPercentage: Number(managerPercentages[index]),
pastDate,
watchListed: alreadyFavorite,
category: assetIdDetails.category,
Expand Down
67 changes: 60 additions & 7 deletions src/components/AssetDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,22 @@ import 'antd/lib/row/style';
import Col from 'antd/lib/col';
import 'antd/lib/col/style';

import ValueDisplay from './ValueDisplay';
import Watch from './Watch';
import ConfirmationPopup from './ConfirmationPopup';
import Address from './Address';
import '../styles/AssetDetails.css';
import LocationIcon from '../images/Location-blue.svg';
import MyBitLogo from '../images/mybit-blue.svg';
import Sliders from '../images/sliders.svg';
import Civic from '../images/civic.svg';
import CalendarIcon from '../images/calendar.svg';
import BlockchainInfoContext from './BlockchainInfoContext';
import NumericInput from './NumericInput';
import { formatMonetaryValue } from '../util/helpers';
import {
formatMonetaryValue,
shortenAddress,
} from '../util/helpers';
import { S3_URL } from '../constants';

class AssetDetails extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -136,6 +143,21 @@ class AssetDetails extends React.Component {
this.clearInterval();
}

getFilesToRender(files, assetId){
if(!files || files.length === 0){
return <span>None</span>;
}
const toReturn = files.map(file => (
<a
href={`${S3_URL}${assetId}:${file}`}
>
{file}
</a>
))

return toReturn;
}

render() {
const { selectedAmountUsd, selectedAmountEth } = this.state;
const { currentEthInUsd } = this.props;
Expand All @@ -150,8 +172,12 @@ class AssetDetails extends React.Component {
address,
numberOfInvestors,
watchListed,
files,
managerPercentage
} = this.props.information;

const filesToRender = this.getFilesToRender(files, assetID);

const maxInvestment =
this.assetFunded || this.state.daysToGo < 0
? 0
Expand Down Expand Up @@ -250,11 +276,6 @@ class AssetDetails extends React.Component {
<p className="AssetDetails__right-content-details">
{description}
</p>
<b className="AssetDetails__right-title-details">Asset manager</b>
<Address
userName={address}
className="AssetDetails__right-address"
/>
</div>
</Col>

Expand Down Expand Up @@ -408,6 +429,38 @@ class AssetDetails extends React.Component {
>
Contribute
</Button>
<div className="AssetDetails__left-assetManager">
<div className="AssetDetails__left-assetManager-left">
<p className="AssetDetails__left-assetManager-title">Asset Manager</p>
<Civic className="AssetDetails__left-assetManager-civic"/>
<a
className="AssetDetails__left-assetManager-address"
href={`https://ropsten.etherscan.io/address/${address}`}
target="_blank"
rel="noopener noreferrer"
>
{shortenAddress(address, 5, 2)}
</a>
<p className="AssetDetails__left-assetManager-supportingDocuments">Supporting documents</p>
{filesToRender}
</div>
<div className="AssetDetails__left-assetManager-right">
<ValueDisplay
text="Total Management Fee"
icon={<Sliders />}
value={`${managerPercentage}%`}
hasSeparator
hasIcon
/>
<ValueDisplay
text="Asset Collateral"
icon={<MyBitLogo />}
value="0%"
hasSeparator
hasIcon
/>
</div>
</div>
</Col>
</div>
</Row>
Expand Down
54 changes: 41 additions & 13 deletions src/components/BlockchainInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
debug,
MYBIT_TICKER_COINMARKETCAP,
ETHEREUM_TICKER_COINMARKETCAP,
isAssetIdEnabled,
serverIp,
ethereumNetwork,
fetchTransactionHistoryTime,
Expand All @@ -22,7 +21,8 @@ import {
AIRTABLE_CATEGORIES_URL,
AIRTABLE_ASSETS_URL,
AIRTABLE_CATEGORIES_NUMBER_OF_FIELDS,
AIRTABLE_ASSETS_NUMBER_OF_FIELDS
AIRTABLE_ASSETS_NUMBER_OF_FIELDS,
S3_ASSET_FILES_URL,
} from '../constants';

class BlockchainInfo extends React.Component {
Expand Down Expand Up @@ -131,6 +131,27 @@ class BlockchainInfo extends React.Component {
clearInterval(this.intervalFetchTransactionHistory);
}

async pullFileInfoForAssets(assets){
try{
const response = await axios(S3_ASSET_FILES_URL);

const filesByAssetId = response.data.filesByAssetId;
console.log(filesByAssetId)

for(const asset of assets){
const assetId = asset.assetID;
if(filesByAssetId[assetId]){
asset.files = filesByAssetId[assetId];
}
}
return assets;
}catch(err){
debug("Error pulling files from server");
debug(err)
return assets;
}
}

async handleListAsset(formData, setUserListingAsset){
const {
asset,
Expand Down Expand Up @@ -358,6 +379,7 @@ class BlockchainInfo extends React.Component {
if (!data.assetsLoaded) {
return;
}

let assetsToReturn = data.assets.map((asset) => {
let watchListed = false;

Expand All @@ -366,15 +388,12 @@ class BlockchainInfo extends React.Component {
watchListed = window.localStorage.getItem(searchQuery) || false;
}

let details = isAssetIdEnabled(asset.assetID, true);
let details = this.state.assetsAirTableById[asset.assetID];
// if the asset Id is not on airtable it doens't show up in the platform
if (!details) {
details = {};
details.city = 'Zurich';
details.country = 'Switzerland';
details.description = 'Coming soon';
details.details = 'Coming soon';
details.name = 'Coming soon';
return undefined;
}

return {
...details,
...asset,
Expand All @@ -386,12 +405,19 @@ class BlockchainInfo extends React.Component {
if (process.env.NODE_ENV !== 'development') {
// filter for test assets. Only for development
assetsToReturn = assetsToReturn.filter(asset =>
asset.description !== 'Coming soon');
asset && asset.description !== 'Coming soon');
} else {
// returns all assets that were matched to the assets
// in Airtable
assetsToReturn = assetsToReturn.filter(asset =>
asset !== undefined);
}

const updatedAssets = await this.pullFileInfoForAssets(assetsToReturn);

this.setState({
usingServer: true,
assets: assetsToReturn,
assets: updatedAssets,
transactions: [],
loading: {
...this.state.loading,
Expand Down Expand Up @@ -517,9 +543,11 @@ class BlockchainInfo extends React.Component {
usingServer: false,
});
await Brain.fetchAssets(this.state.user, this.state.prices.ether.price, this.state.assetsAirTableById, this.state.categoriesAirTable)
.then((response) => {
.then( async (response) => {
const updatedAssets = await this.pullFileInfoForAssets(response);
console.log(updatedAssets)
this.setState({
assets: response,
assets: updatedAssets,
loading: { ...this.state.loading, assets: false },
}, () => {
if(updateNotification){
Expand Down
18 changes: 18 additions & 0 deletions src/components/ValueDisplay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

import '../styles/ValueDisplay.css';

const ValueDisplay = ({value, text, icon, hasIcon, hasSeparator, className}) => (
<div className={`ValueDisplay ${className}`}>
{hasIcon && (
<span className="ValueDisplay__icon">{icon}</span>
)}
{text}
{hasSeparator && (
<div className="ValueDisplay__separator" />
)}
<b className="ValueDisplay__value">{value}</b>
</div>
)

export default ValueDisplay;
4 changes: 4 additions & 0 deletions src/components/pages/AssetDetailsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ const AssetDetailsPage = ({
fundingStage: asset.fundingStage,
pastDate: asset.pastDate,
watchListed: asset.watchListed,
files: asset.files,
managerPercentage: asset.managerPercentage,
};

console.log(assetInformation)

return (
<div>
<Button onClick={history.goBack} className="AssetDetailsPage--back-btn">
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const AIRTABLE_CATEGORIES_URL = process.env.NODE_ENV === 'development' ?
export const AIRTABLE_ASSETS_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:8080/api/airtable/assets' : '/api/airtable/assets';
export const UPDATE_ASSETS_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:8080/api/airtable/update' : '/api/airtable/update';
export const S3_UPLOAD_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:8080/api/files/upload' : '/api/files/upload';
export const S3_ASSET_FILES_URL = process.env.NODE_ENV === 'development' ? 'http://localhost:8080/api/assets/files' : '/api/assets/files';
export const AIRTABLE_CATEGORIES_NUMBER_OF_FIELDS = 3;
export const AIRTABLE_ASSETS_NUMBER_OF_FIELDS = 6;
export const MAX_FILES_UPLOAD = 2;
Expand Down

0 comments on commit c55f13f

Please sign in to comment.