diff --git a/package.json b/package.json index 18e99bf..4fec147 100644 --- a/package.json +++ b/package.json @@ -16,22 +16,29 @@ "body-parser": "^1.19.0", "cors": "^2.8.5", "coveralls": "^3.1.0", + "data-uri-to-buffer": "^3.0.1", "dotenv": "^8.2.0", "express": "^4.17.1", + "express-fileupload": "^1.2.1", "graphql": "^15.4.0", "helmet": "^4.1.1", "husky": "^4.3.0", + "imagekit": "^3.1.2", "jest": "^26.5.2", "jsonwebtoken": "^8.5.1", "mongodb": "^3.6.2", "morgan": "^1.10.0", "prettier": "^2.1.2", + "sharp": "^0.28.1", "ts-jest": "^26.4.1", "tslint": "^6.1.3", "tslint-config-airbnb": "^5.11.2" }, "devDependencies": { + "@types/express-fileupload": "^1.1.6", + "@types/imagekit": "^3.1.1", "@types/node": "^14.14.19", + "@types/sharp": "^0.28.0", "nodemon": "^2.0.6", "ts-node": "^9.1.1", "typescript": "^4.1.3" diff --git a/src/app.ts b/src/app.ts index 0ec1571..c0fbeb4 100644 --- a/src/app.ts +++ b/src/app.ts @@ -9,6 +9,8 @@ import { userRouter } from './routes/user'; import { ApolloServer } from 'apollo-server-express'; import { typeDefs } from './typeDefs'; import { resolvers } from './resolvers'; +import { typeRouter } from './routes/type'; +import fileUpload from 'express-fileupload'; class App { server = new ApolloServer({ typeDefs, resolvers }); @@ -22,9 +24,16 @@ class App { private config(): void { this.app.use(bodyParser.urlencoded({ extended: false })); - this.app.use(bodyParser.json()); + this.app.use(bodyParser.json({ limit: '150mb', type: 'application/json' })); this.app.use(cors()); - this.app.use(helmet({ contentSecurityPolicy: process.env.NODE_ENV === 'production' ? undefined : false })); + this.app.use( + helmet({ contentSecurityPolicy: process.env.NODE_ENV === 'production' ? undefined : false }), + ); + this.app.use( + fileUpload({ + createParentPath: true, + }), + ); this.app.use(morgan('combined')); const app = this.app; this.server.applyMiddleware({ app }); @@ -40,6 +49,7 @@ class App { this.app.use('/api/joke', jokeRouter); this.app.use('/api/jokes', jokeRouter); this.app.use('/api/user', userRouter); + this.app.use('/api/type', typeRouter); } } diff --git a/src/controllers/joke/CreateJoke.controller.ts b/src/controllers/joke/CreateJoke.controller.ts index de9ffe0..7f1b324 100644 --- a/src/controllers/joke/CreateJoke.controller.ts +++ b/src/controllers/joke/CreateJoke.controller.ts @@ -1,10 +1,16 @@ import { Request, Response } from 'express'; import { createJokeService } from '../../services/joke/CreateJoke.service'; +import sessionToken from '../../util/getSessionToken'; export const createJokeController = async (req: Request, res: Response) => { try { - const createdJoke = await createJokeService(req.body); - res.send(createdJoke); + const createdJoke = await createJokeService(sessionToken(req), req.body); + + if (createdJoke.success) { + res.send(createdJoke); + } else { + res.status(400).send(createdJoke); + } } catch (err) { res.status(500).send(err); } diff --git a/src/controllers/joke/DeleteJoke.controller.ts b/src/controllers/joke/DeleteJoke.controller.ts index 75316d2..2a72b74 100644 --- a/src/controllers/joke/DeleteJoke.controller.ts +++ b/src/controllers/joke/DeleteJoke.controller.ts @@ -1,9 +1,10 @@ import { Request, Response } from 'express'; import { deleteJokeService } from '../../services/joke/DeleteJoke.service'; +import sessionToken from '../../util/getSessionToken'; export const deleteJokeController = async (req: Request, res: Response) => { try { - const removedJoke = await deleteJokeService(req.params.id); + const removedJoke = await deleteJokeService(sessionToken(req), req.params.id); res.send(removedJoke); } catch (err) { res.status(500).send(err); diff --git a/src/controllers/joke/JokePagination.controller.ts b/src/controllers/joke/JokePagination.controller.ts new file mode 100644 index 0000000..7b634d8 --- /dev/null +++ b/src/controllers/joke/JokePagination.controller.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; +import { jokePaginationService } from '../../services/joke/JokePagination.service'; + +export const JokePaginationController = async (req: Request, res: Response) => { + const skip = req.query.skip as string; + const limit = req.query.limit as string; + + if (isNaN(Number(skip)) && isNaN(Number(limit))) throw new Error('non vaild numbers'); + + try { + const jokes = await jokePaginationService(Number(skip), Number(limit)); + + res.send(jokes); + } catch (err) { + console.error(err); + res.status(500).send(err); + } +}; diff --git a/src/controllers/type/CountType.controller.ts b/src/controllers/type/CountType.controller.ts new file mode 100644 index 0000000..2b54afc --- /dev/null +++ b/src/controllers/type/CountType.controller.ts @@ -0,0 +1,13 @@ +import { Request, Response } from 'express'; +import { countTypeService } from '../../services/type/CountType.service'; + +export const countTypeController = async (req: Request, res: Response) => { + const type = req.params.type; + try { + const typeCount = await countTypeService(type); + res.send(typeCount); + } catch (err) { + console.log(err); + res.status(500).send(err); + } +}; diff --git a/src/controllers/type/CreateType.controller.ts b/src/controllers/type/CreateType.controller.ts new file mode 100644 index 0000000..7f8811d --- /dev/null +++ b/src/controllers/type/CreateType.controller.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; +import { createTypeService } from '../../services/type/CreateType.service'; +import sessionToken from '../../util/getSessionToken'; + +export const createTypeController = async (req: Request, res: Response) => { + try { + const postedType = await createTypeService(sessionToken(req), req.body); + + if (postedType.success) { + res.send(postedType); + } else { + res.status(400).send(postedType); + } + } catch (err) { + console.log(err); + res.status(500).send(err); + } +}; diff --git a/src/controllers/type/GetType.controller.ts b/src/controllers/type/GetType.controller.ts new file mode 100644 index 0000000..f2b19f6 --- /dev/null +++ b/src/controllers/type/GetType.controller.ts @@ -0,0 +1,12 @@ +import { Request, Response } from 'express'; +import { getTypeService } from '../../services/type/GetType.serivce'; + +export const getTypeController = async (req: Request, res: Response) => { + try { + const types = await getTypeService(); + res.send(types); + } catch (err) { + console.log(err); + res.status(500).send(err); + } +}; diff --git a/src/controllers/type/UpdateType.controller.ts b/src/controllers/type/UpdateType.controller.ts new file mode 100644 index 0000000..1546c25 --- /dev/null +++ b/src/controllers/type/UpdateType.controller.ts @@ -0,0 +1,14 @@ +import { Request, Response } from 'express'; +import { updateTypeService } from '../../services/type/UpdateType.service'; + +export const updateTypeController = async (req: Request, res: Response) => { + const id = req.params.id; + const num = req.body.countNumber; + try { + const updatedType = await updateTypeService(id, num); + res.send(updatedType); + } catch (err) { + console.log(err); + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/CreateUserProfileImage.controller.ts b/src/controllers/user/CreateUserProfileImage.controller.ts new file mode 100644 index 0000000..c7306e4 --- /dev/null +++ b/src/controllers/user/CreateUserProfileImage.controller.ts @@ -0,0 +1,21 @@ +import { Request, Response } from 'express'; +import { CreateUserProfileImageService } from '../../services/user/CreateUserProfileImage.service'; +import sessionToken from '../../util/getSessionToken'; + +export const createUserProfileImageController = async (req: Request, res: Response) => { + try { + if (!req.body.file) { + throw new Error('No file uploaded'); + } + + const file = req.body.file; + const fileName = req.params.fileName; + + const profileImage = await CreateUserProfileImageService(sessionToken(req), file, fileName); + + res.send(profileImage); + } catch (err) { + console.log(err); + res.status(500).send(err.message || err); + } +}; diff --git a/src/controllers/user/GetUserLikes.controller.ts b/src/controllers/user/GetUserLikes.controller.ts new file mode 100644 index 0000000..5852766 --- /dev/null +++ b/src/controllers/user/GetUserLikes.controller.ts @@ -0,0 +1,17 @@ +import { Request, Response } from 'express'; +import { getUserLikesService } from '../../services/user/GetUserLikes.service'; + +export const getUserLikesController = async (req: Request, res: Response) => { + const userId = req.params.userId; + try { + const userLikes = await getUserLikesService(userId); + + if (!userLikes.success) { + res.status(500).send(userLikes); + } + + res.send(userLikes); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/GetUserPosts.controller.ts b/src/controllers/user/GetUserPosts.controller.ts new file mode 100644 index 0000000..1046dc9 --- /dev/null +++ b/src/controllers/user/GetUserPosts.controller.ts @@ -0,0 +1,17 @@ +import { Request, Response } from 'express'; +import { getUserPostService } from '../../services/user/GetUserPosts.service'; + +export const getUserPostController = async (req: Request, res: Response) => { + const userId = req.params.userId; + try { + const userPosts = await getUserPostService(userId); + + if (!userPosts.success) { + res.status(500).send(userPosts); + } + + res.send(userPosts); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/LikeJoke.controller.ts b/src/controllers/user/LikeJoke.controller.ts new file mode 100644 index 0000000..a36bb5b --- /dev/null +++ b/src/controllers/user/LikeJoke.controller.ts @@ -0,0 +1,32 @@ +import { Request, Response } from 'express'; +import { authUser } from '../../services/user/authUser.service'; +import { LikeJokeService } from '../../services/user/LikeJoke.service'; +import sessionToken from '../../util/getSessionToken'; + +export const CreateLikeJokeController = async (req: Request, res: Response) => { + try { + const jokeId = req.params.jokeId as string; + + const likeJokeResult = await LikeJokeService(sessionToken(req), jokeId); + + if (likeJokeResult?.success === false) { + return res.status(500).send(likeJokeResult); + } + + res.send(likeJokeResult); + } catch (err) { + res.status(500).send(err); + } +}; + +export const ListLikeJokeController = async (req: Request, res: Response) => { + try { + const likeJokeResult = await authUser(sessionToken(req)); + + if (likeJokeResult instanceof Error) throw likeJokeResult; + + res.send(likeJokeResult.likes); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/ProfileUser.controller.ts b/src/controllers/user/ProfileUser.controller.ts index 29c3afc..de86883 100644 --- a/src/controllers/user/ProfileUser.controller.ts +++ b/src/controllers/user/ProfileUser.controller.ts @@ -1,11 +1,10 @@ import { Request, Response } from 'express'; import { profileUserService } from '../../services/user/ProfileUser.service'; +import sessionToken from '../../util/getSessionToken'; export const profileUserController = async (req: Request, res: Response) => { try { - const sessionToken = req.headers.authorization?.split(' ')[1]; - - const userProfile = await profileUserService(sessionToken); + const userProfile = await profileUserService(sessionToken(req)); res.send(userProfile); } catch (err) { res.status(500).send(err); diff --git a/src/controllers/user/PublicUser.controller.ts b/src/controllers/user/PublicUser.controller.ts new file mode 100644 index 0000000..36e8ab9 --- /dev/null +++ b/src/controllers/user/PublicUser.controller.ts @@ -0,0 +1,11 @@ +import { Request, Response } from 'express'; +import { publicUserService } from '../../services/user/PublicUser.service'; + +export const publicUserController = async (req: Request, res: Response) => { + try { + const userProfile = await publicUserService(req.params.id); + res.send(userProfile); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/UnlikeJoke.controller.ts b/src/controllers/user/UnlikeJoke.controller.ts new file mode 100644 index 0000000..14b8f3e --- /dev/null +++ b/src/controllers/user/UnlikeJoke.controller.ts @@ -0,0 +1,19 @@ +import { Request, Response } from 'express'; +import { UnlikeJokeService } from '../../services/user/UnlikeJoke.service'; +import sessionToken from '../../util/getSessionToken'; + +export const UnlikeJokeController = async (req: Request, res: Response) => { + try { + const jokeId = req.params.jokeId as string; + + const unlikeJokeResult = await UnlikeJokeService(sessionToken(req), jokeId); + + if (unlikeJokeResult?.success === false) { + return res.status(500).send(unlikeJokeResult); + } + + res.send(unlikeJokeResult); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/controllers/user/UpdateUser.controller.ts b/src/controllers/user/UpdateUser.controller.ts new file mode 100644 index 0000000..31a70b5 --- /dev/null +++ b/src/controllers/user/UpdateUser.controller.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; +import { UpdateUserService } from '../../services/user/UpdateUser.service'; +import sessionToken from '../../util/getSessionToken'; + +export const updateUserController = async (req: Request, res: Response) => { + const updates = req.body; + try { + const updatedUser = await UpdateUserService(sessionToken(req), updates); + + if (!updatedUser.success) { + res.status(500).send(updatedUser); + } + + res.send(updatedUser); + } catch (err) { + res.status(500).send(err); + } +}; diff --git a/src/index.ts b/src/index.ts index 393e73d..2a7d302 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,34 @@ require('dotenv').config(); import mongodb from 'mongodb'; +import ImageKit from 'imagekit'; + const port = process.env.PORT || 8080; const user = process.env.DB_USER; const password = process.env.DB_PASS; const host = process.env.DB_HOST; +const publicKey = process.env.IMAGEKIT_PUBLIC_KEY as string; +const privateKey = process.env.IMAGEKIT_PRIVATE_KEY as string; +const urlEndpoint = process.env.IMAGEKIT_URLENDPOINT as string; + const MongoClient = mongodb.MongoClient; const uri = `mongodb+srv://${user}:${password}@${host}`; -export const mongoService = new MongoClient(uri, { useNewUrlParser: true }); +//const uri = `mongodb://localhost:27017`; + +export const imagekit = new ImageKit({ + publicKey, + privateKey, + urlEndpoint, +}); + +export const mongoService = new MongoClient(uri, { + useNewUrlParser: true, + useUnifiedTopology: true, +}); const retryConnection = () => { mongoService.connect().catch((e) => { console.error(e); - retryConnection(); }); }; diff --git a/src/models/joke.ts b/src/models/joke.ts new file mode 100644 index 0000000..08ab93d --- /dev/null +++ b/src/models/joke.ts @@ -0,0 +1,23 @@ +import { ObjectID } from 'mongodb'; +import { UserLikeInformation } from './user'; + +type Joke = { + _id: string; + type: string; + punchLine: string; + likes: Array; + author: { + name: string; + id: ObjectID; + }; + date: string; + approved: boolean; +}; + +type CreateJokeBody = { + type: string; + setup: string; + punchline: string; +}; + +export { Joke, CreateJokeBody }; diff --git a/src/models/type.ts b/src/models/type.ts new file mode 100644 index 0000000..07e6d08 --- /dev/null +++ b/src/models/type.ts @@ -0,0 +1,15 @@ +export type CreateType = { + type: string; + color: string; +}; + +export type Type = { + _id: string; + type: string; + author: { + id: string; + displayName: string; + } | null; + date: number; + postCount: number; +}; diff --git a/src/models/user.ts b/src/models/user.ts new file mode 100644 index 0000000..032b0d2 --- /dev/null +++ b/src/models/user.ts @@ -0,0 +1,23 @@ +import { ObjectID } from 'mongodb'; + +type User = { + firstName: string; + lastName: string; + email: string; + password: string; + sessionToken: string; + photoUrl: string; + displayName: string; + likes: string[]; + posts: string[]; + admin: boolean; + _id: string; + bio: string; +}; + +type UserLikeInformation = { + id: string; + displayName: string; +}; + +export { User, UserLikeInformation }; diff --git a/src/routes/joke.ts b/src/routes/joke.ts index 2e18e5b..54da4be 100644 --- a/src/routes/joke.ts +++ b/src/routes/joke.ts @@ -5,6 +5,7 @@ import { deleteJokeController } from '../controllers/joke/DeleteJoke.controller' import { jokeByIdController } from '../controllers/joke/JokeById.controller'; import { jokeBySearchController } from '../controllers/joke/JokeBySearch.controller'; import { jokeByTypeController } from '../controllers/joke/JokeByType.controller'; +import { JokePaginationController } from '../controllers/joke/JokePagination.controller'; import asyncMiddleware from '../middleware/async.middleware'; const router: Router = Router(); @@ -13,12 +14,14 @@ router.get('/count', asyncMiddleware(countJokeController)); router.get('/search', asyncMiddleware(jokeBySearchController)); +router.get('/pagination', asyncMiddleware(JokePaginationController)); + router.get('/:id', asyncMiddleware(jokeByIdController)); router.get('/type/:type', asyncMiddleware(jokeByTypeController)); router.post('/create', asyncMiddleware(createJokeController)); -router.delete('/delete', asyncMiddleware(deleteJokeController)); +router.delete('/delete/:id', asyncMiddleware(deleteJokeController)); export const jokeRouter: Router = router; diff --git a/src/routes/type.ts b/src/routes/type.ts new file mode 100644 index 0000000..cdae2d2 --- /dev/null +++ b/src/routes/type.ts @@ -0,0 +1,18 @@ +import { Router } from 'express'; +import { countTypeController } from '../controllers/type/CountType.controller'; +import { createTypeController } from '../controllers/type/CreateType.controller'; +import { getTypeController } from '../controllers/type/GetType.controller'; +import { updateTypeController } from '../controllers/type/UpdateType.controller'; +import asyncMiddleware from '../middleware/async.middleware'; + +const router: Router = Router(); + +router.get('/count/:type', asyncMiddleware(countTypeController)); + +router.get('/', asyncMiddleware(getTypeController)); + +router.post('/', asyncMiddleware(createTypeController)); + +router.put('/:id', asyncMiddleware(updateTypeController)); + +export const typeRouter: Router = router; diff --git a/src/routes/user.ts b/src/routes/user.ts index 513fd03..9445a81 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -2,7 +2,17 @@ import { Router } from 'express'; import { createUserController } from '../controllers/user/CreateUser.controller'; import { loginUserController } from '../controllers/user/LoginUser.controller'; import { profileUserController } from '../controllers/user/ProfileUser.controller'; +import { + CreateLikeJokeController, + ListLikeJokeController, +} from '../controllers/user/LikeJoke.controller'; import asyncMiddleware from '../middleware/async.middleware'; +import { publicUserController } from '../controllers/user/PublicUser.controller'; +import { getUserPostController } from '../controllers/user/GetUserPosts.controller'; +import { getUserLikesController } from '../controllers/user/GetUserLikes.controller'; +import { updateUserController } from '../controllers/user/UpdateUser.controller'; +import { UnlikeJokeController } from '../controllers/user/UnlikeJoke.controller'; +import { createUserProfileImageController } from '../controllers/user/CreateUserProfileImage.controller'; const router: Router = Router(); @@ -12,4 +22,20 @@ router.post('/login', asyncMiddleware(loginUserController)); router.get('/profile', asyncMiddleware(profileUserController)); +router.get('/like', asyncMiddleware(ListLikeJokeController)); + +router.get('/public/profile/:id', asyncMiddleware(publicUserController)); + +router.put('/unlike/:jokeId', asyncMiddleware(UnlikeJokeController)); + +router.post('/like/:jokeId', asyncMiddleware(CreateLikeJokeController)); + +router.get('/likes/:userId', asyncMiddleware(getUserLikesController)); + +router.get('/posts/:userId', asyncMiddleware(getUserPostController)); + +router.post('/image/:fileName', asyncMiddleware(createUserProfileImageController)); + +router.put('/', asyncMiddleware(updateUserController)); + export const userRouter: Router = router; diff --git a/src/services/image/ImageUpload.service.ts b/src/services/image/ImageUpload.service.ts new file mode 100644 index 0000000..5b14809 --- /dev/null +++ b/src/services/image/ImageUpload.service.ts @@ -0,0 +1,23 @@ +import { imagekit } from '../../index'; +import sharp from 'sharp'; +import dataUriToBuffer from 'data-uri-to-buffer'; + +export const imageUploadService = async ( + file: string, + fileName: string, +): Promise => { + try { + const originalImage = dataUriToBuffer(file); + + const updatedFile = await sharp(originalImage).resize({ width: 120, height: 120 }).toBuffer(); + + const result = await imagekit.upload({ + file: updatedFile, + fileName, + }); + + return result; + } catch (error) { + return error; + } +}; diff --git a/src/services/joke/CreateJoke.service.ts b/src/services/joke/CreateJoke.service.ts index ce77fb4..fc0ad5d 100644 --- a/src/services/joke/CreateJoke.service.ts +++ b/src/services/joke/CreateJoke.service.ts @@ -1,16 +1,57 @@ import { mongoService } from '../..'; +import { CreateJokeBody } from '../../models/joke'; +import oID from '../../util/oID'; +import { countTypeService } from '../type/CountType.service'; +import { authUser } from '../user/authUser.service'; -interface Body { - type: string; - setup: string; - punchline: string; -} - -export const createJokeService = async (body: Body) => { +export const createJokeService = async (sessionToken: string | undefined, body: CreateJokeBody) => { try { - const result = await mongoService.db('Jokes').collection('DadJokes').insertOne(body); - return { success: true, body: result }; + const user = await authUser(sessionToken); + + if (user instanceof Error) throw user; + + const typeExist = await countTypeService(body.type); + + if (!typeExist.body) throw new Error('Must choose an existing type'); + + const result = await mongoService + .db('Jokes') + .collection('DadJokes') + .insertOne({ + type: body.type, + punchline: body.punchline, + setup: body.setup, + author: { + name: user.displayName, + id: oID(user._id), + }, + likes: [], + date: Math.floor(new Date().getTime() / 1000), + approved: false, + }); + + const jokeId = result.ops[0]._id as string; + user.posts.push(jokeId); + + await mongoService + .db('Users') + .collection('Profile') + .updateOne({ _id: oID(user._id) }, { $set: { posts: user.posts } }); + + await mongoService + .db('Jokes') + .collection('Types') + .updateOne( + { + _id: oID(typeExist.body?._id), + }, + { + $set: { postCount: typeExist.body?.postCount + 1 }, + }, + ); + + return { success: true, body: result.ops[0] }; } catch (err) { - return { success: false, error: err }; + return { success: false, error: err.message || err }; } }; diff --git a/src/services/joke/DeleteJoke.service.ts b/src/services/joke/DeleteJoke.service.ts index e8d07d5..e0068e6 100644 --- a/src/services/joke/DeleteJoke.service.ts +++ b/src/services/joke/DeleteJoke.service.ts @@ -1,12 +1,79 @@ -import { ObjectId } from 'mongodb'; import { mongoService } from '../..'; +import { User } from '../../models/user'; +import oID from '../../util/oID'; +import { countTypeService } from '../type/CountType.service'; +import { authUser } from '../user/authUser.service'; +import { jokeByIdService } from './JokeById.service'; -export const deleteJokeService = async (id: string) => { - const objectid = new ObjectId(id); +export const deleteJokeService = async (sessionToken: string | undefined, id: string) => { try { - const result = await mongoService.db('Jokes').collection('DadJokes').deleteOne({ _id: objectid }); - return { success: true, body: result }; + const user = await authUser(sessionToken); + + if (user instanceof Error) throw user; + + const joke = await jokeByIdService(id); + + if (!joke.body) throw new Error('Joke does not exist'); + + const typeExist = await countTypeService(joke.body?.type); + + if (!typeExist.body) throw new Error('Type does not exist'); + + const postIndex = user.posts.findIndex((p) => p == id); + user.posts.splice(postIndex, 1); + + if (String(joke.body?.author.id) == String(user._id) || user.admin) { + await mongoService + .db('Jokes') + .collection('DadJokes') + .deleteOne({ _id: oID(id) }); + if (user.admin) { + const unknownUserID = joke.body?.author.id; + + const unknownUser = (await mongoService + .db('Users') + .collection('Profile') + .findOne({ _id: unknownUserID })) as User; + + const index = unknownUser.posts.findIndex((p) => p == id); + unknownUser.posts.splice(index, 1); + + await mongoService + .db('Users') + .collection('Profile') + .updateOne( + { + _id: unknownUserID, + }, + { $set: { posts: unknownUser.posts } }, + ); + } else { + await mongoService + .db('Users') + .collection('Profile') + .updateOne( + { + _id: oID(user._id), + }, + { $set: { posts: user.posts } }, + ); + } + + await mongoService + .db('Jokes') + .collection('Types') + .updateOne( + { + _id: typeExist.body?._id, + }, + { $set: { postCount: typeExist.body?.postCount - 1 } }, + ); + } else { + throw new Error('unauthorized to delete this joke'); + } + + return { success: true, body: joke.body }; } catch (err) { - return { success: false, error: err }; + return { success: false, error: err.message }; } }; diff --git a/src/services/joke/JokeById.service.ts b/src/services/joke/JokeById.service.ts index 4f1b278..25a1549 100644 --- a/src/services/joke/JokeById.service.ts +++ b/src/services/joke/JokeById.service.ts @@ -1,10 +1,14 @@ import { ObjectId } from 'mongodb'; import { mongoService } from '../..'; +import { Joke } from '../../models/joke'; export const jokeByIdService = async (id: string) => { try { const oId = new ObjectId(id); - const result = await mongoService.db('Jokes').collection('DadJokes').findOne({ _id: oId }); + const result = (await mongoService + .db('Jokes') + .collection('DadJokes') + .findOne({ _id: oId })) as Joke; return { success: true, body: result }; } catch (err) { return { success: false, error: err }; diff --git a/src/services/joke/JokePagination.service.ts b/src/services/joke/JokePagination.service.ts new file mode 100644 index 0000000..0df3784 --- /dev/null +++ b/src/services/joke/JokePagination.service.ts @@ -0,0 +1,17 @@ +import { mongoService } from '../..'; + +export const jokePaginationService = async (skip: number, limit: number) => { + try { + const result = await mongoService + .db('Jokes') + .collection('DadJokes') + .find({ approved: true }) + .skip(skip) + .limit(limit) + .toArray(); + + return { success: true, body: result }; + } catch (err) { + return { success: false, body: err }; + } +}; diff --git a/src/services/random/RandomJoke.service.ts b/src/services/random/RandomJoke.service.ts index 8a768d6..ace681a 100644 --- a/src/services/random/RandomJoke.service.ts +++ b/src/services/random/RandomJoke.service.ts @@ -5,7 +5,7 @@ export const randomJokeService = async (count: number) => { const result = await mongoService .db('Jokes') .collection('DadJokes') - .aggregate([{ $sample: { size: count > 5 ? 5 : count } }]) + .aggregate([{ $match: { approved: true } }, { $sample: { size: count > 5 ? 5 : count } }]) .toArray(); return { success: true, body: result }; } catch (err) { diff --git a/src/services/type/CountType.service.ts b/src/services/type/CountType.service.ts new file mode 100644 index 0000000..d67995a --- /dev/null +++ b/src/services/type/CountType.service.ts @@ -0,0 +1,17 @@ +import { mongoService } from '../..'; +import { Type } from '../../models/type'; + +export const countTypeService = async (type: string) => { + try { + const result: Type | null = await mongoService + .db('Jokes') + .collection('Types') + .findOne({ type: type }); + + if (!result) throw new Error('type does not exist'); + + return { success: true, body: result }; + } catch (err) { + return { success: false, error: err }; + } +}; diff --git a/src/services/type/CreateType.service.ts b/src/services/type/CreateType.service.ts new file mode 100644 index 0000000..5944572 --- /dev/null +++ b/src/services/type/CreateType.service.ts @@ -0,0 +1,35 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; +import { authUser } from '../user/authUser.service'; +import { CreateType } from '../../models/type'; +import { countTypeService } from './CountType.service'; + +export const createTypeService = async (sessionToken: string | undefined, body: CreateType) => { + try { + const user = await authUser(sessionToken); + + if (user instanceof Error) throw user; + + const findType = await countTypeService(body.type); + + if (findType) throw new Error('Must have unique type name'); + + const result = await mongoService + .db('Jokes') + .collection('Types') + .insertOne({ + type: body.type, + color: body.color, + author: { + name: user.displayName, + id: oID(user._id), + }, + date: Math.floor(new Date().getTime() / 1000), + postCount: 0, + }); + + return { success: true, body: result.ops[0] }; + } catch (err) { + return { success: false, error: err.message || err }; + } +}; diff --git a/src/services/type/DeleteType.service.ts b/src/services/type/DeleteType.service.ts new file mode 100644 index 0000000..f1036a2 --- /dev/null +++ b/src/services/type/DeleteType.service.ts @@ -0,0 +1,15 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; + +export const deleteTypeService = async (id: string) => { + try { + const result = await mongoService + .db('Jokes') + .collection('Types') + .deleteOne({ _id: oID(id) }); + + return { success: true, body: result.result.ok }; + } catch (err) { + return { success: false, error: err }; + } +}; diff --git a/src/services/type/GetType.serivce.ts b/src/services/type/GetType.serivce.ts new file mode 100644 index 0000000..1784cf8 --- /dev/null +++ b/src/services/type/GetType.serivce.ts @@ -0,0 +1,10 @@ +import { mongoService } from '../..'; + +export const getTypeService = async () => { + try { + const result = await mongoService.db('Jokes').collection('Types').find().toArray(); + return { success: true, body: result }; + } catch (err) { + return { success: false, error: err }; + } +}; diff --git a/src/services/type/UpdateType.service.ts b/src/services/type/UpdateType.service.ts new file mode 100644 index 0000000..cbafc67 --- /dev/null +++ b/src/services/type/UpdateType.service.ts @@ -0,0 +1,15 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; + +export const updateTypeService = async (id: string, postCount: number) => { + try { + const result = await mongoService + .db('Jokes') + .collection('Types') + .updateOne({ _id: oID(id) }, { $set: { postCount: postCount } }); + + return { success: true, body: result.upsertedCount }; + } catch (err) { + return { success: false, error: err }; + } +}; diff --git a/src/services/user/CreateUser.service.ts b/src/services/user/CreateUser.service.ts index 08788a4..1f76e0d 100644 --- a/src/services/user/CreateUser.service.ts +++ b/src/services/user/CreateUser.service.ts @@ -11,6 +11,8 @@ interface Body { password: string; company: string | null; photoUrl: string | null; + displayName: string; + bio: string | null; } export const createUserService = async (body: Body) => { @@ -21,7 +23,6 @@ export const createUserService = async (body: Body) => { { name: `${body.firstName} ${body.lastName}`, email: body.email, - company: body.company, photoUrl: body.photoUrl, }, secret, @@ -34,10 +35,14 @@ export const createUserService = async (body: Body) => { firstName: body.firstName, lastName: body.lastName, email: body.email, - company: body.company, password: hash, sessionToken: token, - photoUrl: body.company, + photoUrl: body.photoUrl, + displayName: body.displayName, + likes: [], + posts: [], + bio: body.bio, + admin: false, }); return { success: true, body: result.ops[0] }; } catch (err) { diff --git a/src/services/user/CreateUserProfileImage.service.ts b/src/services/user/CreateUserProfileImage.service.ts new file mode 100644 index 0000000..a91bf7c --- /dev/null +++ b/src/services/user/CreateUserProfileImage.service.ts @@ -0,0 +1,20 @@ +import { imageUploadService } from '../image/ImageUpload.service'; +import { UpdateUserService } from './UpdateUser.service'; + +export const CreateUserProfileImageService = async ( + sessionToken: string | undefined, + file: string, + fileName: string, +) => { + try { + const uploadedImage = await imageUploadService(file, fileName); + + const updatedUser = await UpdateUserService(sessionToken, { + photoUrl: uploadedImage.url, + }); + + return updatedUser; + } catch (error) { + return { success: false, error: error }; + } +}; diff --git a/src/services/user/GetUserLikes.service.ts b/src/services/user/GetUserLikes.service.ts new file mode 100644 index 0000000..5e189de --- /dev/null +++ b/src/services/user/GetUserLikes.service.ts @@ -0,0 +1,28 @@ +import { mongoService } from '../..'; +import { User } from '../../models/user'; +import oID from '../../util/oID'; + +export const getUserLikesService = async (userId: string) => { + try { + const user: User | null = await mongoService + .db('Users') + .collection('Profile') + .findOne({ _id: oID(userId) }); + + if (!user) throw new Error('user does not exist'); + + const userLikes = await mongoService + .db('Jokes') + .collection('DadJokes') + .find({ + _id: { + $in: [...user.likes], + }, + }) + .toArray(); + + return { success: true, body: userLikes }; + } catch (error) { + return { success: false, body: error }; + } +}; diff --git a/src/services/user/GetUserPosts.service.ts b/src/services/user/GetUserPosts.service.ts new file mode 100644 index 0000000..736017c --- /dev/null +++ b/src/services/user/GetUserPosts.service.ts @@ -0,0 +1,30 @@ +import { mongoService } from '../..'; +import { User } from '../../models/user'; +import oID from '../../util/oID'; + +export const getUserPostService = async (userId: string) => { + try { + const user: User | null = await mongoService + .db('Users') + .collection('Profile') + .findOne({ _id: oID(userId) }); + + if (!user) throw new Error('user does not exist'); + + console.log(user.posts); + + const userPosts = await mongoService + .db('Jokes') + .collection('DadJokes') + .find({ + _id: { + $in: [...user.posts], + }, + }) + .toArray(); + + return { success: true, body: userPosts }; + } catch (error) { + return { success: false, body: error }; + } +}; diff --git a/src/services/user/LikeJoke.service.ts b/src/services/user/LikeJoke.service.ts new file mode 100644 index 0000000..7d7f6ce --- /dev/null +++ b/src/services/user/LikeJoke.service.ts @@ -0,0 +1,36 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; +import { jokeByIdService } from '../joke/JokeById.service'; +import { authUser } from './authUser.service'; + +export const LikeJokeService = async (sessionToken: string | undefined, jokeId: string) => { + try { + const user = await authUser(sessionToken); + const joke = await jokeByIdService(jokeId); + + if (user instanceof Error) throw user; + + user.likes.push(oID(jokeId) as any); + joke.body?.likes.push({ id: user._id, displayName: user.displayName }); + + await mongoService + .db('Users') + .collection('Profile') + .updateOne( + { + _id: oID(user._id), + }, + { $set: { likes: user.likes } }, + ); + + await mongoService + .db('Jokes') + .collection('DadJokes') + .updateOne({ _id: oID(jokeId) }, { $set: { likes: joke.body?.likes } }); + + return { success: true }; + } catch (err) { + console.error(err); + return { success: false, error: err.message }; + } +}; diff --git a/src/services/user/ProfileUser.service.ts b/src/services/user/ProfileUser.service.ts index 4577da9..53183ef 100644 --- a/src/services/user/ProfileUser.service.ts +++ b/src/services/user/ProfileUser.service.ts @@ -18,8 +18,7 @@ export const profileUserService = async (sessionToken: string | undefined) => { const result = await mongoService .db('Users') .collection('Profile') - .find({ $text: { $search: `"${sessionToken}"` } }) - .toArray(); + .findOne({ $text: { $search: `"${sessionToken}"` } }); return { success: true, body: result }; } catch (err) { diff --git a/src/services/user/PublicUser.service.ts b/src/services/user/PublicUser.service.ts new file mode 100644 index 0000000..c4454bc --- /dev/null +++ b/src/services/user/PublicUser.service.ts @@ -0,0 +1,27 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; +import { User } from '../../models/user'; + +export const publicUserService = async (_id: string) => { + try { + const user = (await mongoService + .db('Users') + .collection('Profile') + .findOne({ _id: oID(_id) })) as User; + + const result = { + displayName: user.displayName, + email: user.email, + name: `${user.firstName} ${user.lastName}`, + likes: user.likes, + posts: user.posts, + photoUrl: user.photoUrl, + bio: user.bio, + }; + + return { success: true, body: result }; + } catch (err) { + console.log(err); + return { success: false, error: err.message }; + } +}; diff --git a/src/services/user/UnlikeJoke.service.ts b/src/services/user/UnlikeJoke.service.ts new file mode 100644 index 0000000..ec0ca68 --- /dev/null +++ b/src/services/user/UnlikeJoke.service.ts @@ -0,0 +1,41 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; +import { jokeByIdService } from '../joke/JokeById.service'; +import { authUser } from './authUser.service'; + +export const UnlikeJokeService = async (sessionToken: string | undefined, jokeId: string) => { + try { + const user = await authUser(sessionToken); + const joke = await jokeByIdService(jokeId); + + if (user instanceof Error) throw user; + + const indexUserLiked = user.likes.findIndex((id) => id == jokeId); + const indexPostLiked = joke.body?.likes.findIndex((j) => j.id == user._id); + + user.likes.splice(indexUserLiked, 1); + + if (typeof indexPostLiked === 'undefined') throw new Error('User never liked post'); + joke.body?.likes.splice(indexPostLiked, 1); + + await mongoService + .db('Users') + .collection('Profile') + .updateOne( + { + _id: oID(user._id), + }, + { $set: { likes: user.likes } }, + ); + + await mongoService + .db('Jokes') + .collection('DadJokes') + .updateOne({ _id: oID(jokeId) }, { $set: { likes: joke.body?.likes } }); + + return { success: true }; + } catch (err) { + console.error(err); + return { success: false, error: err.message }; + } +}; diff --git a/src/services/user/UpdateUser.service.ts b/src/services/user/UpdateUser.service.ts new file mode 100644 index 0000000..cfc041b --- /dev/null +++ b/src/services/user/UpdateUser.service.ts @@ -0,0 +1,39 @@ +import { mongoService } from '../..'; +import oID from '../../util/oID'; +import { jokeByIdService } from '../joke/JokeById.service'; +import { authUser } from './authUser.service'; + +type UpdateUserPayload = { + photoUrl?: string; + email?: string; + firstName?: string; + lastName?: string; + displayName?: string; + bio?: string; +}; + +export const UpdateUserService = async ( + sessionToken: string | undefined, + updatePayload: UpdateUserPayload, +) => { + try { + const user = await authUser(sessionToken); + + if (user instanceof Error) throw user; + + const updatedOptions = { + ...user, + ...updatePayload, + }; + + await mongoService + .db('Users') + .collection('Profile') + .findOneAndUpdate({ _id: user._id }, { $set: { ...updatedOptions } }); + + return { success: true }; + } catch (err) { + console.error(err); + return { success: false, error: err.message }; + } +}; diff --git a/src/services/user/authUser.service.ts b/src/services/user/authUser.service.ts new file mode 100644 index 0000000..cff2eaa --- /dev/null +++ b/src/services/user/authUser.service.ts @@ -0,0 +1,28 @@ +import { mongoService } from '../..'; +import jwt from 'jsonwebtoken'; +import 'dotenv'; +import { User } from '../../models/user'; + +export const authUser = async (sessionToken: string | undefined): Promise => { + try { + if (typeof sessionToken === 'undefined') throw new Error('session Token no present'); + + const secret = process.env.PRIVATE_KEY as string; + jwt.verify(sessionToken, secret, (err, decoded) => { + if (err) { + throw new Error('invaild session token'); + } + }); + + const result: User[] = await mongoService + .db('Users') + .collection('Profile') + .find({ $text: { $search: `"${sessionToken}"` } }) + .toArray(); + + return result[0]; + } catch (err) { + console.error(err); + return err; + } +}; diff --git a/src/util/getSessionToken.ts b/src/util/getSessionToken.ts new file mode 100644 index 0000000..4437bf9 --- /dev/null +++ b/src/util/getSessionToken.ts @@ -0,0 +1,7 @@ +import { Request } from 'express'; + +const sessionToken = (req: Request) => { + return req.headers.authorization?.split(' ')[1]; +}; + +export default sessionToken; diff --git a/src/util/oID.ts b/src/util/oID.ts new file mode 100644 index 0000000..232edfc --- /dev/null +++ b/src/util/oID.ts @@ -0,0 +1,7 @@ +import { ObjectId } from 'mongodb'; + +const oID = (_id: string): ObjectId => { + return new ObjectId(_id); +}; + +export default oID; diff --git a/yarn.lock b/yarn.lock index d4bff6f..94fb0a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -636,11 +636,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/bcrypt@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-3.0.0.tgz#851489a9065a067cb7f3c9cbe4ce9bed8bba0876" - integrity sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ== - "@types/bcryptjs@^2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" @@ -695,6 +690,13 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.9.tgz#4bd1fcac72eca8d5bec93e76c7fdcbdc1bc2cd4a" integrity sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg== +"@types/express-fileupload@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@types/express-fileupload/-/express-fileupload-1.1.6.tgz#fdc3b1d6f54fe4522867f8550f0acf24bcbf5c45" + integrity sha512-8z92PCVgvWvG1TpxucRU9oRz3hZc5cUz+CkeDe4XwVmg2DJDdd/7QASMsJzIo+9Pbfp7LfTEWSeEFUJZBohv9g== + dependencies: + "@types/express" "*" + "@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.17": version "4.17.17" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.17.tgz#6ba02465165b6c9c3d8db3a28def6b16fc9b70f5" @@ -758,6 +760,13 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69" integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA== +"@types/imagekit@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@types/imagekit/-/imagekit-3.1.1.tgz#2bbe5f75a8c575749c00ded5ea6d2dd344f88357" + integrity sha512-+Z90eIFtJ/gGyKWpFVOgeFSXxeLrb5r2Yhg91sUV9bW5xLCD34MACTOWtDsawVCPvJWpbBda9Twi9juvNKCKpQ== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -894,6 +903,13 @@ "@types/mime" "*" "@types/node" "*" +"@types/sharp@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.28.0.tgz#d61865182e386f1ec8d8b6a052da846695638a84" + integrity sha512-YvRFnQM44wAihAKzBDzu3BxnEohpqWd/5KXkwsSUl3qFTb51NyKHCKHX1D62YAy0jZij5aXgm/33v/Cv6VVsdA== + dependencies: + "@types/node" "*" + "@types/stack-utils@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" @@ -985,6 +1001,16 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.11.0" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1185,6 +1211,19 @@ apollo-utilities@^1.0.1, apollo-utilities@^1.3.0: ts-invariant "^0.4.0" tslib "^1.10.0" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -1349,6 +1388,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1394,6 +1438,15 @@ bl@^2.2.1: readable-stream "^2.3.5" safe-buffer "^5.1.1" +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + body-parser@1.19.0, body-parser@^1.18.3, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" @@ -1489,6 +1542,14 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1614,6 +1675,11 @@ chokidar@^3.2.2: optionalDependencies: fsevents "~2.1.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -1660,6 +1726,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -1673,7 +1744,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1692,11 +1763,27 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014" + integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" + integrity sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.4" + combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1736,6 +1823,11 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -1869,6 +1961,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" + integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -1921,6 +2018,13 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-response@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" + integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw== + dependencies: + mimic-response "^2.0.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -1975,6 +2079,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + denque@^1.4.1: version "1.5.0" resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" @@ -2000,6 +2109,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -2094,7 +2208,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2248,6 +2362,11 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expect@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" @@ -2260,6 +2379,13 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" +express-fileupload@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/express-fileupload/-/express-fileupload-1.2.1.tgz#73ac798bd14247d510adb1e439af2420c8367ded" + integrity sha512-fWPNAkBj+Azt9Itmcz/Reqdg3LeBfaXptDEev2JM8bCC0yDptglCnlizhf0YZauyU5X/g6v7v4Xxqhg8tmEfEA== + dependencies: + busboy "^0.3.1" + express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -2469,6 +2595,11 @@ fs-capacitor@^2.0.4: resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.4.tgz#5a22e72d40ae5078b4fe64fe4d08c0d3fc88ad3c" integrity sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2489,6 +2620,20 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + gensync@^1.0.0-beta.1: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -2539,6 +2684,11 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= + glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" @@ -2644,6 +2794,11 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +hamming-distance@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hamming-distance/-/hamming-distance-1.0.0.tgz#39bfa46c61f39e87421e4035a1be4f725dd7b931" + integrity sha1-Ob+kbGHznodCHkA1ob5Pcl3XuTE= + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -2672,6 +2827,11 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -2812,11 +2972,26 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= +imagekit@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/imagekit/-/imagekit-3.1.2.tgz#02202fe6aadfea2e2bddbcba2bb8dcf0345c64cd" + integrity sha512-A0KtNb80kW7LU5lOiEklrE+XlcwT51UVr30kjFqIAW50fRCKFksYI6OJ+cg5lsqcW7KklfWcGcatVI0VC11o4A== + dependencies: + hamming-distance "^1.0.0" + lodash "^4.17.15" + request "^2.88.0" + uuid "^3.3.3" + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2851,7 +3026,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2905,6 +3080,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -2995,6 +3175,13 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -3814,6 +4001,11 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" @@ -3968,6 +4160,11 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43" + integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -3975,7 +4172,7 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -3988,6 +4185,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@1.x: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -4061,6 +4263,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4076,6 +4283,18 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-abi@^2.21.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.26.0.tgz#355d5d4bc603e856f74197adbf3f5117a396ba40" + integrity sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ== + dependencies: + semver "^5.4.1" + +node-addon-api@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" + integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== + node-fetch@^2.1.2, node-fetch@^2.2.0: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -4119,6 +4338,11 @@ nodemon@^2.0.6: undefsafe "^2.0.3" update-notifier "^4.1.0" +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -4167,6 +4391,21 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" +npmlog@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" @@ -4177,7 +4416,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4: +object-assign@^4, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4429,6 +4668,26 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +prebuild-install@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-6.1.2.tgz#6ce5fc5978feba5d3cbffedca0682b136a0b5bff" + integrity sha512-PzYWIKZeP+967WuKYXlTOhYBgGOvTRSfaKI89XnfJ0ansRAH7hDU45X+K+FZeI1Wb/7p/NnuctPH3g0IqKUuSQ== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^2.21.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^3.0.3" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -4530,7 +4789,7 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.8: +rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -4564,7 +4823,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.3.5: +readable-stream@^2.0.6, readable-stream@^2.3.5: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -4577,6 +4836,15 @@ readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -4642,7 +4910,7 @@ request-promise-native@^1.0.8: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.2: +request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -4755,7 +5023,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -4835,6 +5103,13 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -4864,7 +5139,7 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -set-blocking@^2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -4897,6 +5172,20 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" +sharp@^0.28.1: + version "0.28.1" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.28.1.tgz#9d7bbce1ca95b2c27482243cd4839c62ef40b0b7" + integrity sha512-4mCGMEN4ntaVuFGwHx7FvkJQkIgbI+S+F9a3bI7ugdvKjPr4sF7/ibvlRKhJyzhoQi+ODM+XYY1de8xs7MHbfA== + dependencies: + color "^3.1.3" + detect-libc "^1.0.3" + node-addon-api "^3.1.0" + prebuild-install "^6.1.1" + semver "^7.3.5" + simple-get "^3.1.0" + tar-fs "^2.1.1" + tunnel-agent "^0.6.0" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -4931,6 +5220,27 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^3.0.3, simple-get@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" + integrity sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA== + dependencies: + decompress-response "^4.2.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -5108,6 +5418,23 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -5142,6 +5469,13 @@ string.prototype.trimstart@^1.0.1: call-bind "^1.0.0" define-properties "^1.1.3" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -5149,6 +5483,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -5226,6 +5574,27 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +tar-fs@^2.0.0, tar-fs@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + term-size@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" @@ -5595,7 +5964,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -5616,7 +5985,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.1.0, uuid@^3.3.2: +uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -5733,6 +6102,13 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"