mirror of
https://github.com/dap-ps/discover.git
synced 2025-03-04 02:40:38 +00:00
Merge pull request #16 from dap-ps/fetching-dapps-flow
Fetching dapps flow
This commit is contained in:
commit
fc7e1d50d6
@ -1,158 +1,179 @@
|
|||||||
const DAppMetadata = require('./../models/dapps-metadata-model');
|
const DAppMetadata = require('./../models/dapps-metadata-model')
|
||||||
|
|
||||||
const TemplateParser = require('./../inputs/template-parser');
|
const TemplateParser = require('./../inputs/template-parser')
|
||||||
const DAppsMetadataInputTemplates = require('./../inputs/templates/dapps-metadata');
|
const DAppsMetadataInputTemplates = require('./../inputs/templates/dapps-metadata')
|
||||||
|
|
||||||
const IPFSService = require('./../services/ipfs-service');
|
const IPFSService = require('./../services/ipfs-service')
|
||||||
const DiscoverService = require('./../services/discover-service');
|
const DiscoverService = require('./../services/discover-service')
|
||||||
const DAppImageService = require('./../services/dapp-image-service');
|
const DAppImageService = require('./../services/dapp-image-service')
|
||||||
const DAppMetadataService = require('./../services/dapp-metadata-service');
|
const DAppMetadataService = require('./../services/dapp-metadata-service')
|
||||||
|
|
||||||
const ApprovalEmail = require('./../emails/approval-email');
|
const ApprovalEmail = require('./../emails/approval-email')
|
||||||
const BadRequestError = require('./../errors/bad-request-error');
|
const BadRequestError = require('./../errors/bad-request-error')
|
||||||
|
|
||||||
const DAPP_METADATA_STATUSES = require('./../constants/dapp-metadata-statuses');
|
const DAPP_METADATA_STATUSES = require('./../constants/dapp-metadata-statuses')
|
||||||
|
|
||||||
const web3 = require('./../blockchain/web3');
|
const web3 = require('./../blockchain/web3')
|
||||||
const logger = require('./../logger/logger').getLoggerFor('DApps-Metadata-Controller');
|
const logger = require('./../logger/logger').getLoggerFor(
|
||||||
|
'DApps-Metadata-Controller',
|
||||||
|
)
|
||||||
|
|
||||||
class DAppsMetadataController {
|
class DAppsMetadataController {
|
||||||
|
static async uploadDAppMetadata(req, res) {
|
||||||
|
try {
|
||||||
|
const parsedInput = TemplateParser.parse(
|
||||||
|
req.body,
|
||||||
|
DAppsMetadataInputTemplates.UploadingTemplate,
|
||||||
|
)
|
||||||
|
|
||||||
static async uploadDAppMetadata(req, res) {
|
const uploadedMetadata = await DAppMetadataService.upload(
|
||||||
try {
|
req,
|
||||||
const parsedMetadata = TemplateParser.parse(req.body, DAppsMetadataInputTemplates.UploadingTemplate);
|
parsedInput,
|
||||||
const uploadedMetadata = await DAppMetadataService.upload(req, parsedMetadata);
|
)
|
||||||
|
|
||||||
logger.info(`A dapp metadata with hash [${uploadedMetadata.hash}] has been uploaded successfully`);
|
logger.info(
|
||||||
|
`A dapp metadata with hash [${uploadedMetadata.hash}] has been uploaded successfully`,
|
||||||
|
)
|
||||||
|
|
||||||
res.status(200).json({ hash: uploadedMetadata.hash });
|
res.status(200).json({ hash: uploadedMetadata.hash })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error.message);
|
logger.error(error.message)
|
||||||
throw new BadRequestError(error);
|
throw new BadRequestError(error)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async sendApprovalEmail(req, res) {
|
||||||
|
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
|
||||||
|
|
||||||
|
if (!dappMetadata) {
|
||||||
|
return void res.status(404).send()
|
||||||
}
|
}
|
||||||
|
|
||||||
static async sendApprovalEmail(req, res) {
|
if (dappMetadata.status == DAPP_METADATA_STATUSES.NEW) {
|
||||||
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
|
const approvalEmail = new ApprovalEmail(dappMetadata)
|
||||||
|
approvalEmail.send()
|
||||||
if (!dappMetadata) {
|
|
||||||
return void res.status(404).send();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dappMetadata.status == DAPP_METADATA_STATUSES.NEW) {
|
|
||||||
const approvalEmail = new ApprovalEmail(dappMetadata.details);
|
|
||||||
approvalEmail.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMetadataStatus(req, res) {
|
res.status(200).send()
|
||||||
waitToBeMined(req.body.txHash, async () => {
|
}
|
||||||
const dapp = await DiscoverService.retrieveDApp(req.params.dappId);
|
|
||||||
const dappMetadata = await DAppMetadata.findByBytes32Hash(dapp.metadata);
|
|
||||||
const initialDAppMetadata = await DAppMetadata.findOne({ 'compressedMetadata': req.params.dappId });
|
|
||||||
|
|
||||||
if (dappMetadata && initialDAppMetadata && initialDAppMetadata.status == DAPP_METADATA_STATUSES.APPROVED) {
|
static async setMetadataStatus(req, res) {
|
||||||
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED;
|
waitToBeMined(req.body.txHash, async () => {
|
||||||
await dappMetadata.save();
|
const dapp = await DiscoverService.retrieveDApp(req.params.dappId)
|
||||||
}
|
const dappMetadata = await DAppMetadata.findByBytes32Hash(dapp.metadata)
|
||||||
});
|
const initialDAppMetadata = await DAppMetadata.findOne({
|
||||||
|
compressedMetadata: req.params.dappId,
|
||||||
|
})
|
||||||
|
|
||||||
res.status(200).send();
|
if (
|
||||||
|
dappMetadata &&
|
||||||
|
initialDAppMetadata &&
|
||||||
|
initialDAppMetadata.status == DAPP_METADATA_STATUSES.APPROVED
|
||||||
|
) {
|
||||||
|
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED
|
||||||
|
await dappMetadata.save()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).send()
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getDAppMetadata(req, res) {
|
||||||
|
try {
|
||||||
|
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
|
||||||
|
|
||||||
|
if (dappMetadata) {
|
||||||
|
return void res
|
||||||
|
.status(200)
|
||||||
|
.jsonCutSensitives(dappMetadata, ['_id', '__v'])
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(404).send()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message)
|
||||||
|
res.status(404).send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getDAppImage(req, res) {
|
||||||
|
try {
|
||||||
|
const dappImage = await DAppImageService.retrieveImage(req.params.hash)
|
||||||
|
|
||||||
|
if (dappImage) {
|
||||||
|
const imageBuffer = Buffer.from(dappImage.content, 'base64')
|
||||||
|
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'image/png',
|
||||||
|
'Content-Length': imageBuffer.length,
|
||||||
|
})
|
||||||
|
return void res.end(imageBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(404).send()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error.message)
|
||||||
|
res.status(404).send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getAllDappsMetadata(req, res) {
|
||||||
|
const dappsMetadata = await DAppMetadata.find()
|
||||||
|
const dappsFormatedMetadata = {}
|
||||||
|
|
||||||
|
for (let i = 0; i < dappsMetadata.length; i++) {
|
||||||
|
const metadataHash = dappsMetadata[i].hash
|
||||||
|
dappsFormatedMetadata[metadataHash] = dappsMetadata[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getDAppMetadata(req, res) {
|
res.status(200).json(dappsFormatedMetadata)
|
||||||
try {
|
}
|
||||||
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
|
|
||||||
|
|
||||||
if (dappMetadata) {
|
static async approveDApp(req, res) {
|
||||||
return void res.status(200).jsonCutSensitives(dappMetadata, ['_id', '__v']);
|
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
|
||||||
}
|
|
||||||
|
|
||||||
res.status(404).send();
|
if (dappMetadata) {
|
||||||
} catch (error) {
|
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED
|
||||||
logger.error(error.message);
|
|
||||||
res.status(404).send();
|
const hasStaked = await DiscoverService.hasStaked(
|
||||||
}
|
dappMetadata.compressedMetadata,
|
||||||
|
)
|
||||||
|
if (hasStaked) {
|
||||||
|
dappMetadata.ipfsHash = await IPFSService.addContent(
|
||||||
|
dappMetadata.details,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
await dappMetadata.save()
|
||||||
|
|
||||||
|
logger.info(`A dapp with hash [${dappMetadata.hash}] has been approved`)
|
||||||
|
return void res.status(200).send()
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getDAppImage(req, res) {
|
res.status(404).send()
|
||||||
try {
|
}
|
||||||
const dappImage = await DAppImageService.retrieveImage(req.params.hash);
|
|
||||||
|
|
||||||
if (dappImage) {
|
static async rejectDApp(req, res) {
|
||||||
const imageBuffer = Buffer.from(dappImage.content, 'base64');
|
const dappMetadata = await DAppMetadata.findOne({ hash: req.params.hash })
|
||||||
|
|
||||||
res.writeHead(200, {
|
if (dappMetadata) {
|
||||||
'Content-Type': 'image/png',
|
await dappMetadata.remove()
|
||||||
'Content-Length': imageBuffer.length
|
return void res.status(200).send()
|
||||||
});
|
|
||||||
return void res.end(imageBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(404).send();
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(error.message);
|
|
||||||
res.status(404).send();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getAllDappsMetadata(req, res) {
|
res.status(404).send()
|
||||||
const dappsMetadata = await DAppMetadata.find();
|
}
|
||||||
const dappsFormatedMetadata = {}
|
|
||||||
|
|
||||||
for (let i = 0; i < dappsMetadata.length; i++) {
|
|
||||||
const metadataHash = dappsMetadata[i].hash;
|
|
||||||
dappsFormatedMetadata[metadataHash] = dappsMetadata[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(200).json(dappsFormatedMetadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async approveDApp(req, res) {
|
|
||||||
let dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
|
|
||||||
|
|
||||||
if (dappMetadata) {
|
|
||||||
dappMetadata.status = DAPP_METADATA_STATUSES.APPROVED;
|
|
||||||
|
|
||||||
const hasStaked = await DiscoverService.hasStaked(dappMetadata.compressedMetadata);
|
|
||||||
if (hasStaked) {
|
|
||||||
dappMetadata.ipfsHash = await IPFSService.addContent(dappMetadata.details);
|
|
||||||
}
|
|
||||||
|
|
||||||
await dappMetadata.save();
|
|
||||||
|
|
||||||
logger.info(`A dapp with hash [${dappMetadata.hash}] has been approved`);
|
|
||||||
return void res.status(200).send();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(404).send();
|
|
||||||
}
|
|
||||||
|
|
||||||
static async rejectDApp(req, res) {
|
|
||||||
const dappMetadata = await DAppMetadata.findOne({ 'hash': req.params.hash });
|
|
||||||
|
|
||||||
if (dappMetadata) {
|
|
||||||
await dappMetadata.remove();
|
|
||||||
return void res.status(200).send();
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(404).send();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const waitToBeMined = async function (txHash, callback) {
|
const waitToBeMined = async function(txHash, callback) {
|
||||||
const updateMetadataTx = await web3.eth.getTransaction(txHash);
|
const updateMetadataTx = await web3.eth.getTransaction(txHash)
|
||||||
|
|
||||||
if (!updateMetadataTx.blockNumber) {
|
if (!updateMetadataTx.blockNumber) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
waitToBeMined(txHash, callback);
|
waitToBeMined(txHash, callback)
|
||||||
}, 10000);
|
}, 10000)
|
||||||
}
|
} else {
|
||||||
else {
|
callback()
|
||||||
callback();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DAppsMetadataController;
|
module.exports = DAppsMetadataController
|
||||||
|
@ -2,7 +2,7 @@ const Email = require('./base-email');
|
|||||||
|
|
||||||
class ApprovalEmail extends Email {
|
class ApprovalEmail extends Email {
|
||||||
constructor(dapp) {
|
constructor(dapp) {
|
||||||
const emailBody = `A DApp metadata ${JSON.stringify(dapp.details)} has been uploaded`;
|
const emailBody = `A DApp metadata ${JSON.stringify(dapp.details)} has been uploaded. You can connect with the Dapp owner at email: ${dapp.email}`;
|
||||||
super(process.env.APPROVE_NOTIFIER_MAIL, process.env.APPROVER_MAIL, `Uploaded DApp Metadata. Hash - ${dapp.hash}`, emailBody);
|
super(process.env.APPROVE_NOTIFIER_MAIL, process.env.APPROVER_MAIL, `Uploaded DApp Metadata. Hash - ${dapp.hash}`, emailBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"UploadingTemplate": {
|
"UploadingTemplate": {
|
||||||
"name": true,
|
"email": true,
|
||||||
"url": true,
|
"metadata": {
|
||||||
"description": true,
|
"name": true,
|
||||||
"category": true,
|
"url": true,
|
||||||
"image": true,
|
"description": true,
|
||||||
"dateAdded": true,
|
"category": true,
|
||||||
"uploader": true
|
"image": true,
|
||||||
|
"dateAdded": true,
|
||||||
|
"uploader": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,3 +9,32 @@
|
|||||||
[2019-06-04 11:39:00]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
[2019-06-04 11:39:00]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
[2019-06-04 11:42:55]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmXpVWSYayBYPzjiPdhTjmjCcbuY3Qr6ZYteWGaB6fDm4m] has been uploaded successfully
|
[2019-06-04 11:42:55]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmXpVWSYayBYPzjiPdhTjmjCcbuY3Qr6ZYteWGaB6fDm4m] has been uploaded successfully
|
||||||
[2019-06-04 14:15:12]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmTmHntVv6ixcQwtFEivSQ1kY4N5mzjmHVPEfhBRcUD6AC] has been uploaded successfully
|
[2019-06-04 14:15:12]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmTmHntVv6ixcQwtFEivSQ1kY4N5mzjmHVPEfhBRcUD6AC] has been uploaded successfully
|
||||||
|
[2019-07-20 10:23:51]-[ERROR]-[DApps-Metadata-Controller]: metadata is not defined
|
||||||
|
[2019-07-20 10:27:21]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmeJKQtcEASSbmUgqEco4wXcpTVA21jWuEsnkGADEWZyFe] has been uploaded successfully
|
||||||
|
[2019-07-20 10:55:32]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmaviKASDQ9Bc1ntwnPkVr2Kds4zXSrhud1hGj7Mc4NdGv] has been uploaded successfully
|
||||||
|
[2019-07-20 10:57:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmNUSXTixR4DZtPQ5vuBoEAZtv5Pe6CQdkgpRyPYfsbVs6] has been uploaded successfully
|
||||||
|
[2019-07-20 10:59:15]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmVv5G6UvVBAFsMQtff8Sk9p12Hn29g959wUeE3WjsdGUv] has been uploaded successfully
|
||||||
|
[2019-07-20 11:00:45]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmQiiVYUTtpg1DtiKnVKVfkfKkM7Brt7JHVFLcVf3H1yDV] has been uploaded successfully
|
||||||
|
[2019-07-20 11:04:34]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmNMPu9ykeAmmjBoN4g3zBC5HGypr6K4MFb3Tjkmd78i5B] has been uploaded successfully
|
||||||
|
[2019-07-20 11:06:41]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmScorFHZqFYze8RYNXpXuJPTh4ptwTcLeGPE5TodC6gnw] has been uploaded successfully
|
||||||
|
[2019-07-20 11:06:50]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:09:14]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmeyTjkdgSA2M28xugPNRXCjSmsQNHWfsNeYyCfK1FyqV9] has been uploaded successfully
|
||||||
|
[2019-07-20 11:10:55]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmQDFjSnY5pTo2k8uHgvYBFYKB1C9RtrNFxt4enLizP9Hp] has been uploaded successfully
|
||||||
|
[2019-07-20 11:12:14]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmZ4yiDhHmWf1tTsio4vrTzZrE51XKbtm8NzYUV68cxXZz] has been uploaded successfully
|
||||||
|
[2019-07-20 11:12:14]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:32:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [Qmf5RuGyCJFVVtCq7KLXgWwmgRVhTi7oKyiN1Nqk7Fw7Rv] has been uploaded successfully
|
||||||
|
[2019-07-20 11:32:31]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:35:27]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmcsiJkjcfuGvVYK55j9RC2DCBwvHPjrcBrG7UztM3G9xw] has been uploaded successfully
|
||||||
|
[2019-07-20 11:35:27]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:38:06]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmbJ1t7GmMujpvVcFpdGQ58dTxFAtNYaUxNNEXrXS9hnHJ] has been uploaded successfully
|
||||||
|
[2019-07-20 11:38:06]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:39:17]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmPheif9S68kEo4hzuszveWMk5LMEsUb2f5MR8nStkiZBs] has been uploaded successfully
|
||||||
|
[2019-07-20 11:39:17]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:45:48]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmcFPhH8yLG7ERjbEv6kyWsPEGMu2JufXud7Regdn4KNHz] has been uploaded successfully
|
||||||
|
[2019-07-20 11:45:48]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:47:31]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmWvNbgnR82ZkjWmAC7SMisA7k7zKCz7Fqu9HKVwyhJqFY] has been uploaded successfully
|
||||||
|
[2019-07-20 11:47:31]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 11:49:43]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmRtZmATHLNgxSZPbsDXaDiRe7hURagzCWYqbG7rdtS9T1] has been uploaded successfully
|
||||||
|
[2019-07-20 11:50:02]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
[2019-07-20 12:10:07]-[INFO]-[DApps-Metadata-Controller]: A dapp metadata with hash [QmYA7iGvK4641Fu2uPSKe5ahUmrMxrksFDtigvQb4VDtXd] has been uploaded successfully
|
||||||
|
[2019-07-20 12:10:07]-[ERROR]-[Base-Email]: Email service verification failed due to Error: connect ECONNREFUSED 127.0.0.1:587
|
||||||
|
@ -2,6 +2,7 @@ let mongoose = require('mongoose');
|
|||||||
let Schema = mongoose.Schema;
|
let Schema = mongoose.Schema;
|
||||||
|
|
||||||
const bs58 = require('bs58');
|
const bs58 = require('bs58');
|
||||||
|
const validator = require('validator');
|
||||||
|
|
||||||
const dappCategories = require('./../constants/dapp-categories').ALL_CATEGORIES;
|
const dappCategories = require('./../constants/dapp-categories').ALL_CATEGORIES;
|
||||||
const metadataStatuses = require('./../constants/dapp-metadata-statuses').ALL_STATUSES;
|
const metadataStatuses = require('./../constants/dapp-metadata-statuses').ALL_STATUSES;
|
||||||
@ -41,6 +42,16 @@ let DAppsMetadataSchema = new Schema({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
email: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
validate: {
|
||||||
|
validator: function (value) {
|
||||||
|
return validator.isEmail(value);
|
||||||
|
},
|
||||||
|
message: props => `${props.value} is not a valid email!`
|
||||||
|
}
|
||||||
|
},
|
||||||
hash: {
|
hash: {
|
||||||
type: String,
|
type: String,
|
||||||
unique: true,
|
unique: true,
|
||||||
|
@ -1,37 +1,45 @@
|
|||||||
const DAppMetadata = require('./../models/dapps-metadata-model');
|
const validator = require('validator')
|
||||||
|
const web3Utils = require('web3-utils')
|
||||||
|
const DAppMetadata = require('./../models/dapps-metadata-model')
|
||||||
|
|
||||||
const DAppImageService = require('./../services/dapp-image-service');
|
const DAppImageService = require('./../services/dapp-image-service')
|
||||||
|
|
||||||
const validator = require('validator');
|
|
||||||
const web3Utils = require('web3-utils');
|
|
||||||
|
|
||||||
class DAppMetadataService {
|
class DAppMetadataService {
|
||||||
|
static async upload(req, details) {
|
||||||
|
try {
|
||||||
|
if (!validator.isURL(details.metadata.url, { require_protocol: true })) {
|
||||||
|
throw new Error(`Invalid url: ${details.metadata.url}`)
|
||||||
|
}
|
||||||
|
|
||||||
static async upload(req, metadata) {
|
if (!web3Utils.isAddress(details.metadata.uploader)) {
|
||||||
try {
|
throw new Error(
|
||||||
|
`Metadata uploader [${details.metadata.uploader}] is not a valid address`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!validator.isURL(metadata.url, { require_protocol: true })) {
|
const compressedMetadata = web3Utils.keccak256(
|
||||||
throw new Error(`Invalid url: ${metadata.url}`);
|
JSON.stringify(details.metadata),
|
||||||
}
|
)
|
||||||
|
details.metadata.image = await DAppImageService.upload(
|
||||||
|
req,
|
||||||
|
details.metadata.image,
|
||||||
|
)
|
||||||
|
const dappMetadata = await DAppMetadata.create({
|
||||||
|
details: details.metadata,
|
||||||
|
compressedMetadata,
|
||||||
|
email: details.email,
|
||||||
|
})
|
||||||
|
|
||||||
if (!web3Utils.isAddress(metadata.uploader)) {
|
return dappMetadata
|
||||||
throw new Error(`Metadata uploader [${metadata.url}] is not a valid address`);
|
} catch (error) {
|
||||||
}
|
// Code 11000 is because of uniqueness, so just return the already existing document
|
||||||
|
if (error.code == 11000) {
|
||||||
|
return DAppMetadata.findByPlainMetadata(details.metadata)
|
||||||
|
}
|
||||||
|
|
||||||
const compressedMetadata = web3Utils.keccak256(JSON.stringify(metadata));
|
throw new Error(error.message)
|
||||||
metadata.image = await DAppImageService.upload(req, metadata.image);
|
|
||||||
const dappMetadata = await DAppMetadata.create({ details: metadata, compressedMetadata: compressedMetadata });
|
|
||||||
|
|
||||||
return dappMetadata;
|
|
||||||
} catch (error) {
|
|
||||||
// Code 11000 is because of uniqueness, so just return the already existing document
|
|
||||||
if (error.code == 11000) {
|
|
||||||
return DAppMetadata.findByPlainMetadata(metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(error.message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DAppMetadataService;
|
module.exports = DAppMetadataService
|
||||||
|
@ -74,7 +74,7 @@ module.exports = {
|
|||||||
SafeMath: { deploy: false },
|
SafeMath: { deploy: false },
|
||||||
TestBancorFormula: { deploy: false },
|
TestBancorFormula: { deploy: false },
|
||||||
MiniMeToken: {
|
MiniMeToken: {
|
||||||
address: '0x25B1bD06fBfC2CbDbFc174e10f1B78b1c91cc77B'
|
address: '0x25B1bD06fBfC2CbDbFc174e10f1B78b1c91cc77B',
|
||||||
},
|
},
|
||||||
Discover: { address: '0x17e7a7330d23fc6a2ab8578a627408f815396662' },
|
Discover: { address: '0x17e7a7330d23fc6a2ab8578a627408f815396662' },
|
||||||
// MiniMeToken: {
|
// MiniMeToken: {
|
||||||
@ -112,9 +112,11 @@ module.exports = {
|
|||||||
// used with "embark run testnet"
|
// used with "embark run testnet"
|
||||||
testnet: {
|
testnet: {
|
||||||
deployment: {
|
deployment: {
|
||||||
accounts: [{
|
accounts: [
|
||||||
mnemonic: wallet.mnemonic,
|
{
|
||||||
}],
|
mnemonic: wallet.mnemonic,
|
||||||
|
},
|
||||||
|
],
|
||||||
host: `ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a`,
|
host: `ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a`,
|
||||||
port: false,
|
port: false,
|
||||||
type: 'rpc',
|
type: 'rpc',
|
||||||
@ -124,7 +126,7 @@ module.exports = {
|
|||||||
'$WEB3',
|
'$WEB3',
|
||||||
'https://ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a',
|
'https://ropsten.infura.io/v3/8675214b97b44e96b70d05326c61fd6a',
|
||||||
],
|
],
|
||||||
dappAutoEnable: false
|
dappAutoEnable: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// merges with the settings in default
|
// merges with the settings in default
|
||||||
|
11
package.json
11
package.json
@ -8,6 +8,7 @@
|
|||||||
"@trailofbits/embark-contract-info": "^1.0.0",
|
"@trailofbits/embark-contract-info": "^1.0.0",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"bignumber.js": "^8.1.1",
|
"bignumber.js": "^8.1.1",
|
||||||
|
"bn.js": "^5.0.0",
|
||||||
"bs58": "^4.0.1",
|
"bs58": "^4.0.1",
|
||||||
"connected-react-router": "^6.3.2",
|
"connected-react-router": "^6.3.2",
|
||||||
"debounce": "^1.2.0",
|
"debounce": "^1.2.0",
|
||||||
@ -15,6 +16,7 @@
|
|||||||
"embark": "4.0.1",
|
"embark": "4.0.1",
|
||||||
"embark-solium": "0.0.1",
|
"embark-solium": "0.0.1",
|
||||||
"history": "^4.7.2",
|
"history": "^4.7.2",
|
||||||
|
"idb": "4.0.3",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.11.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
@ -31,11 +33,10 @@
|
|||||||
"redux": "^4.0.1",
|
"redux": "^4.0.1",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"reselect": "^4.0.0",
|
"reselect": "^4.0.0",
|
||||||
"web3-utils": "^1.0.0-beta.35",
|
"validator": "^11.1.0",
|
||||||
"webpack": "4.28.3",
|
|
||||||
"idb": "4.0.3",
|
|
||||||
"web3": "1.0.0-beta.34",
|
"web3": "1.0.0-beta.34",
|
||||||
"validator": "latest"
|
"web3-utils": "^1.0.0-beta.35",
|
||||||
|
"webpack": "4.28.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
@ -78,4 +79,4 @@
|
|||||||
"prettier": "^1.16.4",
|
"prettier": "^1.16.4",
|
||||||
"webpack": "4.28.3"
|
"webpack": "4.28.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,20 @@ import DiscoverContract from '../../../../embarkArtifacts/contracts/Discover'
|
|||||||
|
|
||||||
const BN = require('bn.js')
|
const BN = require('bn.js')
|
||||||
|
|
||||||
|
const EMPTY_METADATA = {
|
||||||
|
developer: '',
|
||||||
|
id: '',
|
||||||
|
metadata: {
|
||||||
|
status: 'EMPTY',
|
||||||
|
},
|
||||||
|
balance: 0,
|
||||||
|
rate: 0,
|
||||||
|
available: 0,
|
||||||
|
votesMinted: 0,
|
||||||
|
votesCast: 0,
|
||||||
|
effectiveBalance: 0,
|
||||||
|
}
|
||||||
|
|
||||||
class DiscoverService extends BlockchainService {
|
class DiscoverService extends BlockchainService {
|
||||||
constructor(sharedContext) {
|
constructor(sharedContext) {
|
||||||
super(sharedContext, DiscoverContract, DiscoverValidator)
|
super(sharedContext, DiscoverContract, DiscoverValidator)
|
||||||
@ -17,10 +31,11 @@ class DiscoverService extends BlockchainService {
|
|||||||
|
|
||||||
// View methods
|
// View methods
|
||||||
async upVoteEffect(id, amount) {
|
async upVoteEffect(id, amount) {
|
||||||
await this.validator.validateUpVoteEffect(id, amount)
|
const tokenAmount = new BN(amount, 10)
|
||||||
|
await this.validator.validateUpVoteEffect(id, tokenAmount)
|
||||||
|
|
||||||
return DiscoverContract.methods
|
return DiscoverContract.methods
|
||||||
.upvoteEffect(id, amount)
|
.upvoteEffect(id, tokenAmount.toString())
|
||||||
.call({ from: this.sharedContext.account })
|
.call({ from: this.sharedContext.account })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,9 +47,56 @@ class DiscoverService extends BlockchainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDAppsCount() {
|
async getDAppsCount() {
|
||||||
return DiscoverContract.methods
|
return MetadataClient.getDappsCount()
|
||||||
.getDAppsCount()
|
}
|
||||||
.call({ from: this.sharedContext.account })
|
|
||||||
|
async getAllDappsWithMetadata() {
|
||||||
|
try {
|
||||||
|
const contractDappsCount = await DiscoverContract.methods
|
||||||
|
.getDAppsCount()
|
||||||
|
.call({ from: this.sharedContext.account })
|
||||||
|
|
||||||
|
const dappsCache = JSON.parse(
|
||||||
|
JSON.stringify(await MetadataClient.retrieveMetadataCache()),
|
||||||
|
)
|
||||||
|
const dapps = []
|
||||||
|
|
||||||
|
for (let i = 0; i < contractDappsCount; i++) {
|
||||||
|
const dapp = await DiscoverContract.methods
|
||||||
|
.dapps(i)
|
||||||
|
.call({ from: this.sharedContext.account })
|
||||||
|
|
||||||
|
const dappMetadata = dappsCache[dapp.metadata]
|
||||||
|
delete dappsCache[dapp.metadata]
|
||||||
|
dapp.metadata = dappMetadata.details
|
||||||
|
dapp.metadata.status = dappMetadata.status
|
||||||
|
|
||||||
|
dapps.push(dapp)
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(dappsCache).forEach(metadataHash => {
|
||||||
|
const dappMetadata = dappsCache[metadataHash]
|
||||||
|
|
||||||
|
dapps.push({
|
||||||
|
developer: '',
|
||||||
|
id: dappMetadata.compressedMetadata,
|
||||||
|
metadata: {
|
||||||
|
...dappMetadata.details,
|
||||||
|
status: dappMetadata.status,
|
||||||
|
},
|
||||||
|
balance: 0,
|
||||||
|
rate: 0,
|
||||||
|
available: 0,
|
||||||
|
votesMinted: 0,
|
||||||
|
votesCast: 0,
|
||||||
|
effectiveBalance: 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return dapps
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Error fetching dapps. Details: ${error.message}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDAppByIndexWithMetadata(index) {
|
async getDAppByIndexWithMetadata(index) {
|
||||||
@ -43,9 +105,10 @@ class DiscoverService extends BlockchainService {
|
|||||||
.dapps(index)
|
.dapps(index)
|
||||||
.call({ from: this.sharedContext.account })
|
.call({ from: this.sharedContext.account })
|
||||||
|
|
||||||
const dappMetadata = await MetadataClient.retrieveMetadataCache(
|
const dappMetadata = await MetadataClient.retrieveDAppFromCache(
|
||||||
dapp.metadata,
|
dapp.metadata,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dappMetadata === null) return null
|
if (dappMetadata === null) return null
|
||||||
dapp.metadata = dappMetadata.details
|
dapp.metadata = dappMetadata.details
|
||||||
dapp.metadata.status = dappMetadata.status
|
dapp.metadata.status = dappMetadata.status
|
||||||
@ -56,21 +119,25 @@ class DiscoverService extends BlockchainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDAppById(id) {
|
async getDAppById(id) {
|
||||||
let dapp
|
let dapp = EMPTY_METADATA
|
||||||
try {
|
const dappExists = await this.isDAppExists(id)
|
||||||
const dappId = await DiscoverContract.methods
|
|
||||||
.id2index(id)
|
|
||||||
.call({ from: this.sharedContext.account })
|
|
||||||
|
|
||||||
dapp = await DiscoverContract.methods
|
if (dappExists) {
|
||||||
.dapps(dappId)
|
try {
|
||||||
.call({ from: this.sharedContext.account })
|
const dappId = await DiscoverContract.methods
|
||||||
} catch (error) {
|
.id2index(id)
|
||||||
throw new Error('Searching DApp does not exists')
|
.call({ from: this.sharedContext.account })
|
||||||
}
|
|
||||||
|
|
||||||
if (dapp.id != id) {
|
dapp = await DiscoverContract.methods
|
||||||
throw new Error('Error fetching correct data from contract')
|
.dapps(dappId)
|
||||||
|
.call({ from: this.sharedContext.account })
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('Searching DApp does not exists')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dapp.id != id) {
|
||||||
|
throw new Error('Error fetching correct data from contract')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dapp
|
return dapp
|
||||||
@ -78,10 +145,11 @@ class DiscoverService extends BlockchainService {
|
|||||||
|
|
||||||
async getDAppDataById(id) {
|
async getDAppDataById(id) {
|
||||||
const dapp = await this.getDAppById(id)
|
const dapp = await this.getDAppById(id)
|
||||||
|
if (dapp.metadata.status == 'EMPTY') return EMPTY_METADATA
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const dappMetadata = await MetadataClient.retrieveMetadata(dapp.metadata)
|
const dappMetadata = await MetadataClient.retrieveMetadata(dapp.metadata)
|
||||||
if (dappMetadata === null) return null
|
if (dappMetadata === null) return EMPTY_METADATA
|
||||||
dapp.metadata = dappMetadata.details
|
dapp.metadata = dappMetadata.details
|
||||||
dapp.metadata.status = dappMetadata.status
|
dapp.metadata.status = dappMetadata.status
|
||||||
|
|
||||||
@ -105,17 +173,16 @@ class DiscoverService extends BlockchainService {
|
|||||||
|
|
||||||
async checkIfCreatorOfDApp(id) {
|
async checkIfCreatorOfDApp(id) {
|
||||||
const dapp = await this.getDAppById(id)
|
const dapp = await this.getDAppById(id)
|
||||||
|
if (dapp.metadata.status == 'EMPTY') return false
|
||||||
this.sharedContext.account = await super.getAccount()
|
this.sharedContext.account = await super.getAccount()
|
||||||
|
|
||||||
return dapp.developer.toLowerCase() == this.sharedContext.account
|
return dapp.developer.toLowerCase() == this.sharedContext.account
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction methods
|
// Transaction methods
|
||||||
async createDApp(amount, metadata) {
|
async createDApp(amount, metadata, email) {
|
||||||
const tokenAmount = this.decimalMultiplier.mul(new BN(amount, 10))
|
const tokenAmount = this.decimalMultiplier.mul(new BN(amount, 10))
|
||||||
|
|
||||||
console.log(tokenAmount)
|
|
||||||
|
|
||||||
const ConnectedDiscoverContract = await super.__unlockServiceAccount(
|
const ConnectedDiscoverContract = await super.__unlockServiceAccount(
|
||||||
DiscoverContract,
|
DiscoverContract,
|
||||||
)
|
)
|
||||||
@ -126,17 +193,21 @@ class DiscoverService extends BlockchainService {
|
|||||||
const dappId = web3.utils.keccak256(JSON.stringify(dappMetadata))
|
const dappId = web3.utils.keccak256(JSON.stringify(dappMetadata))
|
||||||
await this.validator.validateDAppCreation(dappId, tokenAmount)
|
await this.validator.validateDAppCreation(dappId, tokenAmount)
|
||||||
|
|
||||||
const uploadedMetadata = await MetadataClient.upload(dappMetadata)
|
const uploadedMetadata = await MetadataClient.upload(dappMetadata, email)
|
||||||
|
|
||||||
const callData = ConnectedDiscoverContract.methods
|
let createdTx = ''
|
||||||
.createDApp(dappId, tokenAmount, uploadedMetadata)
|
|
||||||
.encodeABI()
|
|
||||||
|
|
||||||
const createdTx = await this.sharedContext.SNTService.approveAndCall(
|
if (tokenAmount.gt(new BN(0, 10))) {
|
||||||
this.contract,
|
const callData = ConnectedDiscoverContract.methods
|
||||||
tokenAmount,
|
.createDApp(dappId, tokenAmount.toString(), uploadedMetadata)
|
||||||
callData,
|
.encodeABI()
|
||||||
)
|
|
||||||
|
createdTx = await this.sharedContext.SNTService.approveAndCall(
|
||||||
|
this.contract,
|
||||||
|
tokenAmount,
|
||||||
|
callData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
await MetadataClient.requestApproval(uploadedMetadata)
|
await MetadataClient.requestApproval(uploadedMetadata)
|
||||||
|
|
||||||
@ -149,7 +220,7 @@ class DiscoverService extends BlockchainService {
|
|||||||
await this.validator.validateUpVoting(id, tokenAmount)
|
await this.validator.validateUpVoting(id, tokenAmount)
|
||||||
|
|
||||||
const callData = DiscoverContract.methods
|
const callData = DiscoverContract.methods
|
||||||
.upvote(id, tokenAmount)
|
.upvote(id, tokenAmount.toString())
|
||||||
.encodeABI()
|
.encodeABI()
|
||||||
return this.sharedContext.SNTService.approveAndCall(
|
return this.sharedContext.SNTService.approveAndCall(
|
||||||
this.contract,
|
this.contract,
|
||||||
@ -167,7 +238,7 @@ class DiscoverService extends BlockchainService {
|
|||||||
const tokenAmount = this.decimalMultiplier.mul(amountBN)
|
const tokenAmount = this.decimalMultiplier.mul(amountBN)
|
||||||
|
|
||||||
const callData = DiscoverContract.methods
|
const callData = DiscoverContract.methods
|
||||||
.downvote(dapp.id, tokenAmount)
|
.downvote(dapp.id, tokenAmount.toString())
|
||||||
.encodeABI()
|
.encodeABI()
|
||||||
return this.sharedContext.SNTService.approveAndCall(
|
return this.sharedContext.SNTService.approveAndCall(
|
||||||
this.contract,
|
this.contract,
|
||||||
@ -185,7 +256,8 @@ class DiscoverService extends BlockchainService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return broadcastContractFn(
|
return broadcastContractFn(
|
||||||
ConnectedDiscoverContract.methods.withdraw(id, tokenAmount).send,
|
ConnectedDiscoverContract.methods.withdraw(id, tokenAmount.toString())
|
||||||
|
.send,
|
||||||
this.sharedContext.account,
|
this.sharedContext.account,
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -27,12 +27,6 @@ class DiscoverValidator {
|
|||||||
throw new Error('You must submit a unique ID')
|
throw new Error('You must submit a unique ID')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount.lte(0)) {
|
|
||||||
throw new Error(
|
|
||||||
'You must spend some SNT to submit a ranking in order to avoid spam',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const safeMax = await this.service.safeMax()
|
const safeMax = await this.service.safeMax()
|
||||||
if (amount.div(this.decimalMultiplier).toNumber() > safeMax) {
|
if (amount.div(this.decimalMultiplier).toNumber() > safeMax) {
|
||||||
throw new Error('You cannot stake more SNT than the ceiling dictates')
|
throw new Error('You cannot stake more SNT than the ceiling dictates')
|
||||||
|
@ -40,7 +40,11 @@ class SNTService extends BlockchainService {
|
|||||||
const ConnectedSNTToken = await super.__unlockServiceAccount(SNTToken)
|
const ConnectedSNTToken = await super.__unlockServiceAccount(SNTToken)
|
||||||
await this.validator.validateApproveAndCall(spender, amount)
|
await this.validator.validateApproveAndCall(spender, amount)
|
||||||
return broadcastContractFn(
|
return broadcastContractFn(
|
||||||
ConnectedSNTToken.methods.approveAndCall(spender, amount, callData).send,
|
ConnectedSNTToken.methods.approveAndCall(
|
||||||
|
spender,
|
||||||
|
amount.toString(),
|
||||||
|
callData,
|
||||||
|
).send,
|
||||||
this.sharedContext.account,
|
this.sharedContext.account,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ const waitOneMoreBlock = async function(prevBlockNumber) {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
getTxStatus: async txHash => {
|
getTxStatus: async txHash => {
|
||||||
|
if (!txHash) {
|
||||||
|
return TRANSACTION_STATUSES.Successful
|
||||||
|
}
|
||||||
|
|
||||||
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
||||||
if (txReceipt) {
|
if (txReceipt) {
|
||||||
await waitOneMoreBlock(txReceipt.blockNumber)
|
await waitOneMoreBlock(txReceipt.blockNumber)
|
||||||
|
@ -6,11 +6,11 @@ import metadataClientEndpoints from './endpoints/metadata-client-endpoints'
|
|||||||
let metadataCache = null
|
let metadataCache = null
|
||||||
|
|
||||||
class MetadataClient {
|
class MetadataClient {
|
||||||
static async upload(metadata) {
|
static async upload(metadata, email) {
|
||||||
try {
|
try {
|
||||||
const uploadedDataResponse = await HTTPClient.postRequest(
|
const uploadedDataResponse = await HTTPClient.postRequest(
|
||||||
metadataClientEndpoints.UPLOAD,
|
metadataClientEndpoints.UPLOAD,
|
||||||
metadata,
|
{ metadata, email },
|
||||||
)
|
)
|
||||||
|
|
||||||
return helpers.getBytes32FromIpfsHash(uploadedDataResponse.data.hash)
|
return helpers.getBytes32FromIpfsHash(uploadedDataResponse.data.hash)
|
||||||
@ -76,7 +76,20 @@ class MetadataClient {
|
|||||||
return formatedDappsMetadata
|
return formatedDappsMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
static async retrieveMetadataCache(metadataBytes32) {
|
static async getDappsCount() {
|
||||||
|
if (metadataCache === null)
|
||||||
|
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
|
||||||
|
return Object.keys(metadataCache).length
|
||||||
|
}
|
||||||
|
|
||||||
|
static async retrieveMetadataCache() {
|
||||||
|
if (metadataCache === null)
|
||||||
|
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
|
||||||
|
|
||||||
|
return metadataCache
|
||||||
|
}
|
||||||
|
|
||||||
|
static async retrieveDAppFromCache(metadataBytes32) {
|
||||||
if (metadataCache === null)
|
if (metadataCache === null)
|
||||||
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
|
metadataCache = await MetadataClient.retrieveAllDappsMetadata()
|
||||||
const result = metadataCache[metadataBytes32]
|
const result = metadataCache[metadataBytes32]
|
||||||
|
@ -64,16 +64,18 @@ const DappListItem = props => {
|
|||||||
<img src={sntIcon} alt="SNT" width="16" height="16" />
|
<img src={sntIcon} alt="SNT" width="16" height="16" />
|
||||||
{dapp.sntValue}
|
{dapp.sntValue}
|
||||||
</span>
|
</span>
|
||||||
<div className={styles.voteTriggers}>
|
{dapp.sntValue > 0 && (
|
||||||
<span className={styles.vote} onClick={handleUpVote}>
|
<div className={styles.voteTriggers}>
|
||||||
<img src={upvoteArrowIcon} alt="" />
|
<span className={styles.vote} onClick={handleUpVote}>
|
||||||
Upvote
|
<img src={upvoteArrowIcon} alt="" />
|
||||||
</span>
|
Upvote
|
||||||
<span className={styles.vote} onClick={handleDownVote}>
|
</span>
|
||||||
<img src={downvoteArrowIcon} alt="" />
|
<span className={styles.vote} onClick={handleDownVote}>
|
||||||
Downvote
|
<img src={downvoteArrowIcon} alt="" />
|
||||||
</span>
|
Downvote
|
||||||
</div>
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,6 +7,7 @@ export default class DappModel {
|
|||||||
this.sntValue = 0
|
this.sntValue = 0
|
||||||
|
|
||||||
// metadata
|
// metadata
|
||||||
|
this.email = ''
|
||||||
this.name = ''
|
this.name = ''
|
||||||
this.image = ''
|
this.image = ''
|
||||||
this.desc = ''
|
this.desc = ''
|
||||||
|
@ -2,6 +2,7 @@ const submit = {
|
|||||||
visible_submit: false,
|
visible_submit: false,
|
||||||
visible_rating: false,
|
visible_rating: false,
|
||||||
id: '',
|
id: '',
|
||||||
|
email: '',
|
||||||
name: '',
|
name: '',
|
||||||
desc: '',
|
desc: '',
|
||||||
url: '',
|
url: '',
|
||||||
|
@ -67,16 +67,14 @@ embarkJSConnectorWeb3.getNetworkId = function() {
|
|||||||
EmbarkJS.Blockchain.registerProvider('web3', embarkJSConnectorWeb3)
|
EmbarkJS.Blockchain.registerProvider('web3', embarkJSConnectorWeb3)
|
||||||
EmbarkJS.Blockchain.setProvider('web3', {})
|
EmbarkJS.Blockchain.setProvider('web3', {})
|
||||||
if (!global.__Web3) {
|
if (!global.__Web3) {
|
||||||
const web3ConnectionConfig = require('/Users/georgispasov/Development/LimeLabs/status/discover/src/embarkArtifacts/config/blockchain.json')
|
const web3ConnectionConfig = require('./config/blockchain.json')
|
||||||
EmbarkJS.Blockchain.connect(web3ConnectionConfig, err => {
|
EmbarkJS.Blockchain.connect(web3ConnectionConfig, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const namehash =
|
const namehash = global.namehash || require('./modules/eth-ens-namehash')
|
||||||
global.namehash ||
|
|
||||||
require('/Users/georgispasov/Development/LimeLabs/status/discover/src/embarkArtifacts/modules/eth-ens-namehash')
|
|
||||||
;('use strict')
|
;('use strict')
|
||||||
|
|
||||||
/*global namehash*/
|
/*global namehash*/
|
||||||
|
@ -32,26 +32,16 @@ export const fetchAllDappsAction = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { transactionStatus } = state
|
const { transactionStatus } = state
|
||||||
let dappSource = await discoverService.getDAppByIndexWithMetadata(0)
|
let dappSource = ''
|
||||||
if (dappSource !== null) {
|
|
||||||
const dappModel = DappModel.instanceFromBlockchainWithMetadata(
|
const allDapps = await discoverService.getAllDappsWithMetadata()
|
||||||
dappSource,
|
for (let i = 0; i < allDapps.length; i++) {
|
||||||
)
|
dappSource = allDapps[i]
|
||||||
dappState = dappState.creditDapp(dappModel)
|
|
||||||
if (
|
|
||||||
dappModel.id !== transactionStatus.dappId ||
|
|
||||||
transactionStatus.type !== TYPE_SUBMIT
|
|
||||||
) {
|
|
||||||
dispatch(onUpdateDappsAction(dappState))
|
|
||||||
Database.creditDapp(dappModel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = N - 1; i >= 1; i -= 1) {
|
|
||||||
dappSource = await discoverService.getDAppByIndexWithMetadata(i)
|
|
||||||
if (dappSource !== null) {
|
if (dappSource !== null) {
|
||||||
const dappModel = DappModel.instanceFromBlockchainWithMetadata(
|
const dappModel = DappModel.instanceFromBlockchainWithMetadata(
|
||||||
dappSource,
|
dappSource,
|
||||||
)
|
)
|
||||||
|
|
||||||
dappState = dappState.creditDapp(dappModel)
|
dappState = dappState.creditDapp(dappModel)
|
||||||
if (
|
if (
|
||||||
dappModel.id !== transactionStatus.dappId ||
|
dappModel.id !== transactionStatus.dappId ||
|
||||||
|
@ -18,6 +18,7 @@ import {
|
|||||||
switchToRatingAction,
|
switchToRatingAction,
|
||||||
onInputSntValueAction,
|
onInputSntValueAction,
|
||||||
updateAction,
|
updateAction,
|
||||||
|
onInputEmailAction,
|
||||||
} from './Submit.reducer'
|
} from './Submit.reducer'
|
||||||
import { showAlertAction } from '../Alert/Alert.reducer';
|
import { showAlertAction } from '../Alert/Alert.reducer';
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ const mapStateToProps = state =>
|
|||||||
Object.assign(state.submit, { dappState: state.dapps })
|
Object.assign(state.submit, { dappState: state.dapps })
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onClickClose: () => dispatch(closeSubmitAction()),
|
onClickClose: () => dispatch(closeSubmitAction()),
|
||||||
|
onInputEmail: name => dispatch(onInputEmailAction(name)),
|
||||||
onInputName: name => dispatch(onInputNameAction(name)),
|
onInputName: name => dispatch(onInputNameAction(name)),
|
||||||
onInputDesc: name => dispatch(onInputDescAction(name)),
|
onInputDesc: name => dispatch(onInputDescAction(name)),
|
||||||
onInputUrl: name => dispatch(onInputUrlAction(name)),
|
onInputUrl: name => dispatch(onInputUrlAction(name)),
|
||||||
|
@ -23,6 +23,7 @@ class Submit extends React.Component {
|
|||||||
this.imgCanvas = React.createRef()
|
this.imgCanvas = React.createRef()
|
||||||
this.previousMoveX = 0
|
this.previousMoveX = 0
|
||||||
this.previousMoveY = 0
|
this.previousMoveY = 0
|
||||||
|
this.onInputEmail = this.onInputEmail.bind(this)
|
||||||
this.onInputName = this.onInputName.bind(this)
|
this.onInputName = this.onInputName.bind(this)
|
||||||
this.onInputDesc = this.onInputDesc.bind(this)
|
this.onInputDesc = this.onInputDesc.bind(this)
|
||||||
this.onInputUrl = this.onInputUrl.bind(this)
|
this.onInputUrl = this.onInputUrl.bind(this)
|
||||||
@ -71,6 +72,11 @@ class Submit extends React.Component {
|
|||||||
imgNode.src = img
|
imgNode.src = img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onInputEmail(e) {
|
||||||
|
const { onInputEmail } = this.props
|
||||||
|
onInputEmail(e.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
onInputName(e) {
|
onInputName(e) {
|
||||||
const { onInputName } = this.props
|
const { onInputName } = this.props
|
||||||
onInputName(e.target.value)
|
onInputName(e.target.value)
|
||||||
@ -169,6 +175,7 @@ class Submit extends React.Component {
|
|||||||
onSubmit,
|
onSubmit,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
id,
|
id,
|
||||||
|
email,
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
url,
|
url,
|
||||||
@ -178,6 +185,7 @@ class Submit extends React.Component {
|
|||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const metadata = {
|
const metadata = {
|
||||||
|
email,
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
image: img,
|
image: img,
|
||||||
@ -214,6 +222,8 @@ class Submit extends React.Component {
|
|||||||
visible_submit,
|
visible_submit,
|
||||||
visible_rating,
|
visible_rating,
|
||||||
onClickClose,
|
onClickClose,
|
||||||
|
email,
|
||||||
|
id,
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
url,
|
url,
|
||||||
@ -265,6 +275,19 @@ class Submit extends React.Component {
|
|||||||
{visible_submit && (
|
{visible_submit && (
|
||||||
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
||||||
<div className={imgControl ? styles.withImgControl : ''}>
|
<div className={imgControl ? styles.withImgControl : ''}>
|
||||||
|
{id === '' && (
|
||||||
|
<div className={styles.block}>
|
||||||
|
<div className={styles.labelRow}>
|
||||||
|
<span>Your eMail</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="eMail"
|
||||||
|
value={email}
|
||||||
|
onChange={this.onInputEmail}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className={styles.block}>
|
<div className={styles.block}>
|
||||||
<div className={styles.labelRow}>
|
<div className={styles.labelRow}>
|
||||||
<span>Name of your Ðapp</span>
|
<span>Name of your Ðapp</span>
|
||||||
@ -473,6 +496,7 @@ class Submit extends React.Component {
|
|||||||
Submit.propTypes = {
|
Submit.propTypes = {
|
||||||
visible_submit: PropTypes.bool.isRequired,
|
visible_submit: PropTypes.bool.isRequired,
|
||||||
visible_rating: PropTypes.bool.isRequired,
|
visible_rating: PropTypes.bool.isRequired,
|
||||||
|
email: PropTypes.string.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
desc: PropTypes.string.isRequired,
|
desc: PropTypes.string.isRequired,
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
@ -485,6 +509,7 @@ Submit.propTypes = {
|
|||||||
imgControlY: PropTypes.number.isRequired,
|
imgControlY: PropTypes.number.isRequired,
|
||||||
sntValue: PropTypes.string.isRequired,
|
sntValue: PropTypes.string.isRequired,
|
||||||
onClickClose: PropTypes.func.isRequired,
|
onClickClose: PropTypes.func.isRequired,
|
||||||
|
onInputEmail: PropTypes.func.isRequired,
|
||||||
onInputName: PropTypes.func.isRequired,
|
onInputName: PropTypes.func.isRequired,
|
||||||
onInputDesc: PropTypes.func.isRequired,
|
onInputDesc: PropTypes.func.isRequired,
|
||||||
onInputUrl: PropTypes.func.isRequired,
|
onInputUrl: PropTypes.func.isRequired,
|
||||||
|
@ -16,6 +16,7 @@ import BlockchainSDK from '../../common/blockchain'
|
|||||||
|
|
||||||
const SHOW_SUBMIT_AFTER_CHECK = 'SUBMIT_SHOW_SUBMIT_AFTER_CHECK'
|
const SHOW_SUBMIT_AFTER_CHECK = 'SUBMIT_SHOW_SUBMIT_AFTER_CHECK'
|
||||||
const CLOSE_SUBMIT = 'SUBMIT_CLOSE_SUBMIT'
|
const CLOSE_SUBMIT = 'SUBMIT_CLOSE_SUBMIT'
|
||||||
|
const ON_INPUT_EMAIL = 'SUBMIT_ON_INPUT_EMAIL'
|
||||||
const ON_INPUT_NAME = 'SUBMIT_ON_INPUT_NAME'
|
const ON_INPUT_NAME = 'SUBMIT_ON_INPUT_NAME'
|
||||||
const ON_INPUT_DESC = 'SUBMIT_ON_INPUT_DESC'
|
const ON_INPUT_DESC = 'SUBMIT_ON_INPUT_DESC'
|
||||||
const ON_INPUT_URL = 'SUBMIT_ON_INPUT_URL'
|
const ON_INPUT_URL = 'SUBMIT_ON_INPUT_URL'
|
||||||
@ -81,6 +82,11 @@ export const closeSubmitAction = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const onInputEmailAction = email => ({
|
||||||
|
type: ON_INPUT_EMAIL,
|
||||||
|
payload: email,
|
||||||
|
})
|
||||||
|
|
||||||
export const onInputNameAction = name => ({
|
export const onInputNameAction = name => ({
|
||||||
type: ON_INPUT_NAME,
|
type: ON_INPUT_NAME,
|
||||||
payload: name,
|
payload: name,
|
||||||
@ -144,14 +150,18 @@ export const submitAction = (dapp, sntValue) => {
|
|||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
const blockchain = await BlockchainSDK.getInstance()
|
const blockchain = await BlockchainSDK.getInstance()
|
||||||
const { tx, id } = await blockchain.DiscoverService.createDApp(sntValue, {
|
const { tx, id } = await blockchain.DiscoverService.createDApp(
|
||||||
name: dapp.name,
|
sntValue,
|
||||||
url: dapp.url,
|
{
|
||||||
description: dapp.description,
|
name: dapp.name,
|
||||||
category: dapp.category,
|
url: dapp.url,
|
||||||
image: dapp.image,
|
description: dapp.description,
|
||||||
dateAdded: dapp.dateAdded,
|
category: dapp.category,
|
||||||
})
|
image: dapp.image,
|
||||||
|
dateAdded: dapp.dateAdded,
|
||||||
|
},
|
||||||
|
dapp.email,
|
||||||
|
)
|
||||||
dispatch(onReceiveTransactionInfoAction(id, tx))
|
dispatch(onReceiveTransactionInfoAction(id, tx))
|
||||||
dispatch(checkTransactionStatusAction(tx))
|
dispatch(checkTransactionStatusAction(tx))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -199,6 +209,7 @@ const showSubmitAfterCheck = (state, dapp) => {
|
|||||||
visible_submit: true,
|
visible_submit: true,
|
||||||
visible_rating: false,
|
visible_rating: false,
|
||||||
id: dapp !== undefined ? dapp.id : '',
|
id: dapp !== undefined ? dapp.id : '',
|
||||||
|
email: dapp !== undefined ? dapp.email : '',
|
||||||
name: dapp !== undefined ? dapp.name : '',
|
name: dapp !== undefined ? dapp.name : '',
|
||||||
desc: dapp !== undefined ? dapp.description : '',
|
desc: dapp !== undefined ? dapp.description : '',
|
||||||
url: dapp !== undefined ? dapp.url : '',
|
url: dapp !== undefined ? dapp.url : '',
|
||||||
@ -219,6 +230,12 @@ const closeSubmit = state => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onInputEmail = (state, email) => {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
email,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const onInputName = (state, name) => {
|
const onInputName = (state, name) => {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
name,
|
name,
|
||||||
@ -303,6 +320,7 @@ const onInputSntValue = (state, sntValue) => {
|
|||||||
const map = {
|
const map = {
|
||||||
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
||||||
[CLOSE_SUBMIT]: closeSubmit,
|
[CLOSE_SUBMIT]: closeSubmit,
|
||||||
|
[ON_INPUT_EMAIL]: onInputEmail,
|
||||||
[ON_INPUT_NAME]: onInputName,
|
[ON_INPUT_NAME]: onInputName,
|
||||||
[ON_INPUT_DESC]: onInputDesc,
|
[ON_INPUT_DESC]: onInputDesc,
|
||||||
[ON_INPUT_URL]: onInputUrl,
|
[ON_INPUT_URL]: onInputUrl,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user