Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creations on chain #265

Merged
merged 7 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions app/api/src/controllers/creation.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,22 @@ export const updateCreationById = catchAsync(async (req, res): Promise<void> =>

res.send(updatedCreation);
});

export const publishCreationOnchain = catchAsync(async (req, res): Promise<void> => {
// get original creation
const foundCreation = await creationService.getCreationById(req.params.creation_id);

// block publishing on chain if creation is draft
if (foundCreation?.is_draft) {
throw new ApiError(httpStatus.NOT_ACCEPTABLE, `draft creation cannot be published onchain`);
}

// update creation
const updatedCreation = await creationService.updateCreationById(
req.params.creation_id,
{ is_onchain: true },
{ owner_id: (req.user as IUserDoc).user_id }
);

res.send(updatedCreation);
});
1 change: 1 addition & 0 deletions app/api/src/db/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ const init = async (): Promise<QueryResult<any>> => {
is_claimable bool default true,
ipfs_hash character varying,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
is_onchain bool default false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new field added to db

CONSTRAINT author_id
FOREIGN KEY(author_id)
REFERENCES users(user_id)
Expand Down
14 changes: 13 additions & 1 deletion app/api/src/docs/components.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ components:
type: bool
is_claimable:
type: bool
is_onchain:
type: bool
created_at:
type: string
format: date-time
Expand All @@ -191,6 +193,7 @@ components:
created_at: 2022-09-05T19:00:00.000Z
is_draft: false
is_claimable: true
is_onchain: false

CreationProof:
type: object
Expand Down Expand Up @@ -584,7 +587,16 @@ components:
$ref: '#/components/schemas/Error'
example:
code: 406
message: creation has ongoing litigation process
message: creation has ongoing litigation process
CreationDraftNotAllowedOnchain:
description: Draft creation cannot be published onchain
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
code: 406
message: draft creation cannot be published onchain
CreationAlreadyAssignedToLitigation:
description: Creation already assigned to a litigation
content:
Expand Down
32 changes: 30 additions & 2 deletions app/api/src/routes/v1/creation.route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import express from 'express';
import validate from '../../middlewares/validate';
import * as creationValidation from '../../validations/creation.validation';
import * as creationController from '../../controllers/creation.controller';
import auth from '../../middlewares/auth';
import validate from '../../middlewares/validate';
import * as creationValidation from '../../validations/creation.validation';

const router = express.Router();

Expand All @@ -17,6 +17,10 @@ router
.patch(auth(), validate(creationValidation.updateCreation), creationController.updateCreationById)
.delete(auth(), validate(creationValidation.deleteCreation), creationController.deleteCreationById);

router
.route('/:creation_id/onchain')
.post(auth(), validate(creationValidation.publishCreationOnchain), creationController.publishCreationOnchain);

router
.route('/:creation_id/proof')
.get(validate(creationValidation.getCreationProof), creationController.getCreationProofById);
Expand Down Expand Up @@ -465,3 +469,27 @@ export default router;
* "500":
* $ref: '#/components/responses/InternalServerError'
*/

/**
* @swagger
* /creations/{creation_id}/onchain:
* post:
* summary: Publish creation on chain
* description: Stores the publish status of a creation on chain.
* tags: [Creation]
* security:
* - bearerAuth: []
* responses:
* "201":
* description: Created
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Creation'
* "404":
* $ref: '#/components/responses/CreationNotFound'
* "406":
* $ref: '#/components/responses/CreationDraftNotAllowedOnchain'
* "500":
* $ref: '#/components/responses/InternalServerError'
*/
16 changes: 11 additions & 5 deletions app/api/src/services/creation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ICreation {
is_draft: boolean;
is_claimable: boolean;
ipfs_hash: string;
is_onchain: boolean;
}
interface ICreationQuery {
limit: number;
Expand Down Expand Up @@ -57,6 +58,7 @@ interface ICreationDoc {
is_draft: boolean;
is_claimable: boolean;
ipfs_hash: string;
is_onchain: boolean;
}

/**
Expand Down Expand Up @@ -226,15 +228,19 @@ export const queryCreations = async (options: ICreationQuery): Promise<ICreation
query: `SELECT * ${populator({
tableAlias: 'c',
fields: typeof options.populate === 'string' ? [options.populate] : options.populate,
})} FROM creation c where c.creation_type='${options.creation_type}' and not exists (SELECT creation_id from litigation WHERE creation_id = c.creation_id) OFFSET $1 LIMIT $2;`,
})} FROM creation c where c.creation_type='${
options.creation_type
}' and not exists (SELECT creation_id from litigation WHERE creation_id = c.creation_id) OFFSET $1 LIMIT $2;`,
count: `SELECT COUNT(*) as total_results FROM creation c where c.creation_type='${options.creation_type}' and not exists (SELECT creation_id from litigation WHERE creation_id = c.creation_id)
OFFSET $1 LIMIT $2`,
},
creationByTypetopAuthors: {
query: `SELECT * ${populator({
tableAlias: 'c',
fields: typeof options.populate === 'string' ? [options.populate] : options.populate,
})} FROM creation c where c.creation_type='${options.creation_type}' and not exists (SELECT creation_id from litigation WHERE creation_id = c.creation_id) and exists
})} FROM creation c where c.creation_type='${
options.creation_type
}' and not exists (SELECT creation_id from litigation WHERE creation_id = c.creation_id) and exists
(SELECT user_id,
(
SELECT
Expand Down Expand Up @@ -490,10 +496,10 @@ export const queryCreations = async (options: ICreationQuery): Promise<ICreation

const result = await db.instance.query(
typeof options.creation_type === 'string' && options.top_authors === true
? queryModes.creationByTypetopAuthors.query
? queryModes.creationByTypetopAuthors.query
: typeof options.creation_type === 'string' && options.top_authors === false
? queryModes.creationByType.query :
options.top_authors
? queryModes.creationByType.query
: options.top_authors
? queryModes.topAuthors.query
: options.is_trending
? queryModes.trending.query
Expand Down
12 changes: 9 additions & 3 deletions app/api/src/validations/creation.validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export const queryCreations = {
otherwise: Joi.optional(),
}),
creation_type: Joi.string()
.valid(...Object.values(supportedMediaTypes))
.optional(),
.valid(...Object.values(supportedMediaTypes))
.optional(),
is_fully_assigned: Joi.bool().when('is_trending', {
is: Joi.bool().exist(),
then: Joi.forbidden(),
Expand All @@ -44,7 +44,7 @@ export const queryCreations = {
populate: Joi.alternatives()
.try(Joi.string().valid(...creationDeepFields), Joi.array().items(Joi.string().valid(...creationDeepFields)))
.optional(),
top_authors: Joi.bool().default(false).optional(),
top_authors: Joi.bool().default(false).optional(),
}),
};

Expand Down Expand Up @@ -91,3 +91,9 @@ export const deleteCreation = {
creation_id: Joi.string().uuid().required(),
}),
};

export const publishCreationOnchain = {
params: Joi.object().keys({
creation_id: Joi.string().uuid().required(),
}),
};
37 changes: 37 additions & 0 deletions app/web-frontend/craco.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable no-param-reassign */
/* eslint-disable unicorn/prefer-module */
const webpack = require('webpack');

module.exports = {
webpack: {
configure: (config) => {
const wasmExtensionRegExp = /\.wasm$/;
config.resolve.extensions.push('.wasm');
config.resolve.fallback = {
...config.resolve.fallback,
buffer: require.resolve('buffer'),
stream: require.resolve('stream'),
};
config.plugins = [
...config.plugins,
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
];
config.experiments = {
syncWebAssembly: true,
asyncWebAssembly: true,
};

for (const rule of config.module.rules) {
for (const oneOf of (rule.oneOf || [])) {
if (oneOf.type === 'asset/resource') {
oneOf.exclude.push(wasmExtensionRegExp);
}
}
}

return config;
},
},
};
13 changes: 9 additions & 4 deletions app/web-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@craco/craco": "^7.0.0",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@emurgo/cardano-serialization-lib-asmjs": "^10.2.0",
"@hookform/resolvers": "^2.9.8",
"@meshsdk/core": "^1.3.0",
"@meshsdk/react": "^1.1.3",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.9.0",
"@mui/styles": "^5.9.0",
Expand All @@ -17,6 +20,7 @@
"@types/popper.js": "^1.11.0",
"blakejs": "^1.1.1",
"buffer": "^6.0.3",
"craco": "5.0.1",
"joi": "^17.6.0",
"js-cookie": "^3.0.1",
"materialize-css": "^1.0.0-rc.2",
Expand All @@ -35,6 +39,7 @@
"react-slick": "^0.29.0",
"react-transition-group": "^4.4.5",
"slick-carousel": "^1.8.1",
"stream": "^0.0.2",
"web-vitals": "^2.1.4",
"zustand": "^4.1.1"
},
Expand All @@ -54,10 +59,10 @@
"lint-staged": "^12.3.7"
},
"scripts": {
"start": "react-scripts --max-old-space-size=8192 start",
"build": "react-scripts --max-old-space-size=8192 build",
"test": "set CI=true&& react-scripts --passWithNoTests test",
"eject": "react-scripts eject",
"start": "craco start",
"build": "craco build",
"test": "set CI=true&& craco --passWithNoTests test",
"eject": "craco eject",
"lint": "eslint ./src --ext .js",
"lint:fix": "eslint ./src --ext .js --fix",
"prepare": "cd .. && cd .. && husky install app/web-frontend/.husky"
Expand Down
2 changes: 1 addition & 1 deletion app/web-frontend/src/api/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const REQUEST_TEMPLATE = (endpoint) => ({

const User = { ...REQUEST_TEMPLATE('users'), invite: REQUEST_TEMPLATE('users/invite').create };
const Material = REQUEST_TEMPLATE('materials');
const Creation = REQUEST_TEMPLATE('creations');
const Creation = { ...REQUEST_TEMPLATE('creations'), storePublishStatus: async (id) => await REQUEST_TEMPLATE(`creations/${id}/onchain`).create() };
const Decision = REQUEST_TEMPLATE('decision');
const Recognition = REQUEST_TEMPLATE('recognitions');
const Litigation = REQUEST_TEMPLATE('litigations');
Expand Down
12 changes: 9 additions & 3 deletions app/web-frontend/src/components/LoginForm/useLogin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const useLogin = ({ inviteToken = null }) => {
const [selectedWalletAddressHashed, setSelectedWalletAddressHashed] = useState(null);
const [availableWallets, setAvailableWallets] = useState([]);

const getWalletsList = () => setAvailableWallets(getAvailableWallets());
const getWalletsList = async () => setAvailableWallets(await getAvailableWallets());

const getSelectedWalletAddress = async (wallet) => {
try {
Expand Down Expand Up @@ -41,15 +41,21 @@ const useLogin = ({ inviteToken = null }) => {
isSuccess: loginSuccess,
isLoading: isLoggingIn,
} = useMutation({
mutationFn: async () => {
mutationFn: async (selectedWallet) => {
// login with wallet
const response = inviteToken
? await Auth.signup({
invite_token: inviteToken,
wallet_address: selectedWalletAddressOriginal,
})
: await Auth.login({ wallet_address: selectedWalletAddressOriginal });
authUser.setUser({ ...response.user, hashedWalletAddress: selectedWalletAddressHashed });

// store cookies
authUser.setUser({
...response.user,
selectedWallet: selectedWallet.wallet,
hashedWalletAddress: selectedWalletAddressHashed,
});
authUser.setJWTToken(response.token);
},
});
Expand Down
26 changes: 26 additions & 0 deletions app/web-frontend/src/components/cards/CreationCard/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ function CreationCard({
canDelete = true,
onEditClick = () => {},
onDeleteClick = () => {},
canPublish = false,
isPublished = false,
onPublish = () => {},
}) {
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(null);
const [showMediaPreview, setShowMediaPreview] = useState(null);
Expand Down Expand Up @@ -247,6 +250,29 @@ function CreationCard({
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 1024 1024" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91.5c1.9 0 3.8-.7 5.2-2L869 536.2a32.07 32.07 0 0 0 0-48.4z" /></svg>
</Link>
</Box>
{canPublish && (
<Box
display="flex"
flexDirection="column"
alignItems="flex-start"
justifyContent="center"
>
{isPublished ? (
<Chip
style={{
backgroundColor: 'var(--color-black)',
color: 'var(--color-white)',
fontSize: '14px',
}}
label="Published"
/>
) : (
<Button onClick={onPublish} className="approveButton">
Publish
</Button>
)}
</Box>
)}
</Grid>

{interactionBtns && (
Expand Down
16 changes: 16 additions & 0 deletions app/web-frontend/src/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
const API_BASE_URL = 'https://pocre-api.herokuapp.com/v1/';

const POCRE_WALLET_ADDRESS = 'addr_test1qr0nvz3xurstmkj3h3a32knxsgpzvz4g8z3lvhhya9ffzh74uhu2hd3kjx8v9p906g4sejyj3w7q76zqwsgt4w9drfnsp8jhz7'; // preview testnet address || IMPORTANT: dont make real transactions

const CHARGES = {
CREATION_PUBLISHING_ADA: 9,
};

const TRANSACTION_PURPOSES = {
CREATION_PUBLISHING: 'Creation Publishing',
};

const IPFS_BASE_URL = 'https://gateway.pinata.cloud/ipfs/';

export {
API_BASE_URL,
POCRE_WALLET_ADDRESS,
CHARGES,
IPFS_BASE_URL,
TRANSACTION_PURPOSES,
};
Loading