Skip to content

Commit

Permalink
feat: users APIs (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
HungLV46 authored Aug 17, 2024
1 parent 3c8c7fa commit db84498
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 25 deletions.
4 changes: 2 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ model User {
banner_img String
additional_info Json?
products Product[]
user_attributes UserAttribute[]
products Product[]
attributes UserAttribute[]
@@index(name)
@@index(wallet_address)
Expand Down
3 changes: 3 additions & 0 deletions src/apis/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ export * from '#apis/routes/products/update';
export * from '#apis/routes/products/create';
export * from '#apis/routes/products/get';

export * from '#apis/routes/users/create';
export * from '#apis/routes/users/update';

// Search API
export * from '#apis/routes/elastic-search/search';

Expand Down
7 changes: 5 additions & 2 deletions src/apis/routes/products/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { prisma } from '#common/db';
import Joi from 'joi';
import { Prisma } from '@prisma/client';

export const createProductionRoute: Hapi.ServerRoute = {
export const createProductRoute: Hapi.ServerRoute = {
method: 'POST',
path: '/products',
options: {
Expand Down Expand Up @@ -31,6 +31,7 @@ export const createProductionRoute: Hapi.ServerRoute = {
value: Joi.string().required().example('attribute value'),
}),
)
.optional()
.default([]),
metadata: Joi.object({
previews: Joi.array()
Expand All @@ -41,7 +42,9 @@ export const createProductionRoute: Hapi.ServerRoute = {
'https://loremflickr.com/640/480?lock=1572275828555776',
]),
cta_url: Joi.string().default('').example('https://www.google.com'),
}).required(),
})
.optional()
.default({}),
collections: Joi.array()
.items(
Joi.object({
Expand Down
2 changes: 1 addition & 1 deletion src/apis/routes/products/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Hapi from '@hapi/hapi';
import { prisma } from '#common/db';
import Joi from 'joi';

export const getProductionRoute: Hapi.ServerRoute = {
export const getProductRoute: Hapi.ServerRoute = {
method: 'GET',
path: '/products/{id}',
options: {
Expand Down
49 changes: 29 additions & 20 deletions src/apis/routes/products/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { prisma } from '#common/db';
import { Prisma } from '@prisma/client';
import Joi from 'joi';

export const updateProductionRoute: Hapi.ServerRoute = {
export const updateProductRoute: Hapi.ServerRoute = {
method: 'PUT',
path: '/products/{id}',
options: {
Expand All @@ -17,42 +17,51 @@ export const updateProductionRoute: Hapi.ServerRoute = {
}),
payload: Joi.object({
// TODO make optional
name: Joi.string().required().example('Product name'),
owner_id: Joi.number().required().example(1),
name: Joi.string().optional().example('Product name'),
owner_id: Joi.number().optional().example(1),
avatar_img: Joi.string()
.required()
.optional()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
banner_img: Joi.string()
.required()
.optional()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
category: Joi.string().required().example('game'),
description: Joi.string().required().example('description of product'),
featured: Joi.boolean().default(false),
category: Joi.string().optional().example('game'),
description: Joi.string().optional().example('description of product'),
featured: Joi.boolean().optional().default(false).example('false'),
attributes: Joi.array()
.items(
Joi.object({
name: Joi.string().required().example('attribute name'),
value: Joi.string().required().example('attribute value'),
name: Joi.string().required(),
value: Joi.string().required(),
}),
)
.default([]),
.optional()
.default([])
.example([
{ name: 'attribute name', value: 'attribute value' },
{ name: 'attribute name 2', value: 'attribute value 2' },
]),
metadata: Joi.object({
previews: Joi.array()
.items(Joi.string())
.default([])
.example([
previews: Joi.array().items(Joi.string()).optional().default([]),
cta_url: Joi.string().optional().default(''),
})
.optional()
.default({})
.example({
previews: [
'https://loremflickr.com/640/480?lock=1572275828555776',
'https://loremflickr.com/640/480?lock=1572275828555776',
]),
cta_url: Joi.string().default('').example('https://www.google.com'),
}).required(),
],
cta_url: 'https://www.google.com',
}),
collections: Joi.array()
.items(
Joi.object({
chain_id: Joi.string().required(),
contract_address: Joi.string().required(),
}),
)
.optional()
.default([])
.example([
{ chain_id: '1', contract_address: '0x1234x' },
Expand All @@ -76,7 +85,7 @@ export const updateProductionRoute: Hapi.ServerRoute = {
} as Prisma.ProductUpdateInput;
const id = request.params.id;

// create new collections
// create new collections TODO refactor
const existingCollections = await prisma.collection.findMany({
where: { OR: payload.collections as any /** TODO use where in */ },
});
Expand All @@ -97,7 +106,7 @@ export const updateProductionRoute: Hapi.ServerRoute = {
});
}

// update product & create new product - collection relation
// update product & create new product - collection relation TODO refactor
await Promise.all([
prisma.product.update({
where: { id: Number(request.params.id) },
Expand Down
70 changes: 70 additions & 0 deletions src/apis/routes/users/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Hapi from '@hapi/hapi';
import { prisma } from '#common/db';
import Joi from 'joi';
import { Prisma } from '@prisma/client';

export const createUserionRoute: Hapi.ServerRoute = {
method: 'POST',
path: '/users',
options: {
description: 'Create a new user',
notes: 'Create user and its attributes',
tags: ['api', 'user', 'create'],
plugins: { 'hapi-swagger': {} },
validate: {
payload: Joi.object({
name: Joi.string().required().example('User name'),
bio: Joi.string().required().example('Bio'),
email: Joi.string().required().email().example('[email protected]'),
wallet_address: Joi.string().required().example('0x1234567890'),
avatar_img: Joi.string()
.required()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
banner_img: Joi.string()
.required()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
attributes: Joi.array()
.items(
Joi.object({
name: Joi.string().required().example('attribute name'),
value: Joi.string().required().example('attribute value'),
}),
)
.default([]),
additional_info: Joi.object({
headline: Joi.string().optional().example('headline'),
location: Joi.string().optional().example('location'),
socials: Joi.array()
.items(
Joi.object({
name: Joi.string().required().example('twitter'),
url: Joi.string().required().example('https://twitter.com'),
}),
)
.default([]),
})
.optional()
.default({}),
}),
},
// TODO validate response: { schema: Joi.object({}) }
},
handler: async (request: Hapi.Request) => {
const payload = request.payload as any;

// create new user
const userData = {
name: payload.name,
bio: payload.bio,
email: payload.email,
wallet_address: payload.wallet_address,
avatar_img: payload.avatar_img,
banner_img: payload.banner_img,
additional_info: payload.additional_info,
attributes: { create: payload.attributes },
} as Prisma.UserCreateInput;
const user = await prisma.user.create({ data: userData });

return { data: { id: user.id } };
},
};
86 changes: 86 additions & 0 deletions src/apis/routes/users/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Hapi from '@hapi/hapi';
import { prisma } from '#common/db';
import { Prisma } from '@prisma/client';
import Joi from 'joi';

export const updateUserRoute: Hapi.ServerRoute = {
method: 'PUT',
path: '/users/{id}',
options: {
description: 'Update user by its ID',
notes: 'Update user, its attributes and collections',
tags: ['api', 'user', 'update'],
plugins: { 'hapi-swagger': {} },
validate: {
params: Joi.object({
id: Joi.number().required().example(1),
}),
payload: Joi.object({
name: Joi.string().optional().example('User name'),
bio: Joi.string().optional().example('Bio'),
email: Joi.string().optional().email().example('[email protected]'),
wallet_address: Joi.string().optional().example('0x1234567890'),
avatar_img: Joi.string()
.optional()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
banner_img: Joi.string()
.optional()
.example('https://loremflickr.com/640/480?lock=1572275828555776'),
attributes: Joi.array()
.items(
Joi.object({
name: Joi.string().required().example('attribute name'),
value: Joi.string().required().example('attribute value'),
}),
)
.default([]),
additional_info: Joi.object({
headline: Joi.string().optional().example('headline'),
location: Joi.string().optional().example('location'),
socials: Joi.array()
.optional()
.items(
Joi.object({
name: Joi.string().required().example('twitter'),
url: Joi.string().required().example('https://twitter.com'),
}),
)
.default([])
.optional(),
}).optional(),
}),
},
// response: { schema: Joi.object({}) }
},
handler: async (request: Hapi.Request) => {
const id = Number(request.params.id);
const payload = request.payload as any;

// create new user
const user = {
name: payload.name,
bio: payload.bio,
avatar_img: payload.avatar_img,
banner_img: payload.banner_img,
additional_info: payload.additional_info,
} as Prisma.UserCreateInput;

await Promise.all([
prisma.user.update({
where: { id: Number(request.params.id) },
data: user,
}),
prisma.$transaction([
prisma.userAttribute.deleteMany({ where: { user_id: id } }),
prisma.userAttribute.createMany({
data: payload.attributes.map((att: any) => ({
...att,
user_id: id,
})) as Prisma.UserAttributeCreateManyInput[],
}),
]),
]);

return { data: { id } };
},
};

0 comments on commit db84498

Please sign in to comment.