@paralect/hive 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/cli.js +10 -0
- package/package.json +60 -0
- package/starter/Dockerfile +13 -0
- package/starter/Dockerfile.dev +33 -0
- package/starter/Dockerfile.prod +29 -0
- package/starter/README.md +11 -0
- package/starter/bin/init-project.sh +22 -0
- package/starter/bin/start.sh +2 -0
- package/starter/bootstrap-hive.js +118 -0
- package/starter/initial-data.json +176 -0
- package/starter/mongodb-ca-certificate.cer +32 -0
- package/starter/package-lock.json +6711 -0
- package/starter/package.json +84 -0
- package/starter/ship_logo.png +0 -0
- package/starter/src/app.js +61 -0
- package/starter/src/assets/emails/components/header.mjml +13 -0
- package/starter/src/assets/emails/dist/.gitkeep +0 -0
- package/starter/src/assets/emails/signup-welcome.mjml +34 -0
- package/starter/src/assets/emails/styles/index.mjml +77 -0
- package/starter/src/autoMap/addHandlers.js +167 -0
- package/starter/src/autoMap/mapSchema.js +112 -0
- package/starter/src/autoMap/schemaMappings.js +7 -0
- package/starter/src/config/app.js +3 -0
- package/starter/src/config/index.js +24 -0
- package/starter/src/db.js +48 -0
- package/starter/src/helpers/db/ifUpdated.js +22 -0
- package/starter/src/helpers/getResourceEndpoints.js +26 -0
- package/starter/src/helpers/getResources.js +25 -0
- package/starter/src/helpers/getSchemas.js +25 -0
- package/starter/src/helpers/prettierFormat.js +8 -0
- package/starter/src/ioEmitter.js +10 -0
- package/starter/src/jsconfig.json +5 -0
- package/starter/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
- package/starter/src/lib/node-mongo/API.md +654 -0
- package/starter/src/lib/node-mongo/CHANGELOG.md +98 -0
- package/starter/src/lib/node-mongo/README.md +97 -0
- package/starter/src/lib/node-mongo/package.json +74 -0
- package/starter/src/lib/node-mongo/src/index.js +67 -0
- package/starter/src/lib/node-mongo/src/mongo-query-service.js +72 -0
- package/starter/src/lib/node-mongo/src/mongo-service-error.js +15 -0
- package/starter/src/lib/node-mongo/src/mongo-service.js +279 -0
- package/starter/src/logger.js +30 -0
- package/starter/src/middlewares/global/extractUserTokens.js +15 -0
- package/starter/src/middlewares/global/tryToAttachUser.js +32 -0
- package/starter/src/middlewares/isAuthorized.js +9 -0
- package/starter/src/middlewares/shouldExist.js +17 -0
- package/starter/src/middlewares/shouldNotExist.js +19 -0
- package/starter/src/middlewares/uploadFile.js +5 -0
- package/starter/src/middlewares/validate.js +39 -0
- package/starter/src/migrations/migration.js +8 -0
- package/starter/src/migrations/migration.service.js +75 -0
- package/starter/src/migrations/migrations/1.js +22 -0
- package/starter/src/migrations/migrations-log/migration-log.schema.js +15 -0
- package/starter/src/migrations/migrations-log/migration-log.service.js +51 -0
- package/starter/src/migrations/migrations.schema.js +9 -0
- package/starter/src/migrations/migrator.js +77 -0
- package/starter/src/migrator.js +5 -0
- package/starter/src/resources/_dev/endpoints/triggerSchedulerHandler.js +30 -0
- package/starter/src/resources/health/endpoints/get.js +10 -0
- package/starter/src/resources/schemaMappings/schemaMappings.schema.js +9 -0
- package/starter/src/resources/users/endpoints/getCurrentUser.js +13 -0
- package/starter/src/resources/users/endpoints/getUserProfile.js +16 -0
- package/starter/src/resources/users/users.schema.js +14 -0
- package/starter/src/routes/index.js +151 -0
- package/starter/src/routes/middlewares/attachCustomErrors.js +28 -0
- package/starter/src/routes/middlewares/routeErrorHandler.js +27 -0
- package/starter/src/scheduler/handlers/sendDailyReport.example.js +7 -0
- package/starter/src/scheduler.js +21 -0
- package/starter/src/security.util.js +38 -0
- package/starter/src/services/globalTest.js +0 -0
- package/starter/src/socketIo.js +91 -0
package/cli/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
// Get the routes directory from the command line arguments
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
|
|
8
|
+
process.env.HIVE_SRC = path.resolve(process.cwd(), args[0]);
|
|
9
|
+
|
|
10
|
+
require('./../starter/src/app.js');
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@paralect/hive",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"hive": "cli/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@koa/cors": "3.1.0",
|
|
14
|
+
"@koa/multer": "3.0.0",
|
|
15
|
+
"@koa/router": "10.1.1",
|
|
16
|
+
"@paralect/node-mongo": "2.1.1",
|
|
17
|
+
"@sendgrid/mail": "7.6.1",
|
|
18
|
+
"@socket.io/redis-adapter": "7.1.0",
|
|
19
|
+
"@socket.io/redis-emitter": "4.1.1",
|
|
20
|
+
"app-module-path": "2.2.0",
|
|
21
|
+
"aws-sdk": "2.1080.0",
|
|
22
|
+
"bcryptjs": "2.4.3",
|
|
23
|
+
"dotenv": "16.0.0",
|
|
24
|
+
"eslint-config-prettier": "8.5.0",
|
|
25
|
+
"handlebars": "4.7.7",
|
|
26
|
+
"joi": "17.6.0",
|
|
27
|
+
"koa": "2.13.4",
|
|
28
|
+
"koa-bodyparser": "4.3.0",
|
|
29
|
+
"koa-helmet": "6.1.0",
|
|
30
|
+
"koa-logger": "3.2.1",
|
|
31
|
+
"koa-mount": "4.0.0",
|
|
32
|
+
"koa-qs": "3.0.0",
|
|
33
|
+
"lodash": "4.17.21",
|
|
34
|
+
"mjml": "4.12.0",
|
|
35
|
+
"mkdirp": "1.0.4",
|
|
36
|
+
"moment": "2.29.1",
|
|
37
|
+
"moment-duration-format": "2.3.2",
|
|
38
|
+
"multer": "1.4.4",
|
|
39
|
+
"node-schedule": "2.1.0",
|
|
40
|
+
"nodemon": "2.0.15",
|
|
41
|
+
"prettier": "2.6.2",
|
|
42
|
+
"psl": "1.8.0",
|
|
43
|
+
"redis": "3.1.2",
|
|
44
|
+
"require-dir": "1.2.0",
|
|
45
|
+
"socket.io": "4.4.1",
|
|
46
|
+
"socket.io-emitter": "3.2.0",
|
|
47
|
+
"tail": "2.2.4",
|
|
48
|
+
"winston": "3.6.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"eslint": "8.9.0",
|
|
52
|
+
"eslint-config-airbnb-base": "15.0.0",
|
|
53
|
+
"eslint-plugin-import": "2.25.4",
|
|
54
|
+
"husky": "7.0.4",
|
|
55
|
+
"lint-staged": "12.3.4"
|
|
56
|
+
},
|
|
57
|
+
"keywords": [],
|
|
58
|
+
"author": "",
|
|
59
|
+
"license": "MIT"
|
|
60
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
FROM --platform=linux/amd64 node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
# On staging containers running in development mode
|
|
5
|
+
ARG NODE_ENV=development
|
|
6
|
+
|
|
7
|
+
ARG APP_ENV
|
|
8
|
+
ENV NODE_ENV=$NODE_ENV
|
|
9
|
+
ENV APP_ENV=$APP_ENV
|
|
10
|
+
|
|
11
|
+
WORKDIR /project
|
|
12
|
+
|
|
13
|
+
CMD npm run dev 2>&1 | tee /project/logs/log.txt
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
FROM node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
ARG NODE_ENV=development
|
|
5
|
+
ARG APP_ENV
|
|
6
|
+
ARG PROJECT_SRC=/project
|
|
7
|
+
|
|
8
|
+
ENV NODE_ENV=$NODE_ENV
|
|
9
|
+
ENV APP_ENV=$APP_ENV
|
|
10
|
+
ENV PROJECT_SRC=$PROJECT_SRC
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY ["./package*.json", "/app/"]
|
|
14
|
+
# Disable husky
|
|
15
|
+
RUN npm set-script prepare ""
|
|
16
|
+
|
|
17
|
+
RUN npm ci --quiet
|
|
18
|
+
COPY . ./
|
|
19
|
+
|
|
20
|
+
RUN npm run build-assets
|
|
21
|
+
|
|
22
|
+
FROM base as migrator
|
|
23
|
+
CMD npm run migrate
|
|
24
|
+
|
|
25
|
+
FROM base as scheduler
|
|
26
|
+
CMD npm run schedule-dev
|
|
27
|
+
|
|
28
|
+
FROM base as api
|
|
29
|
+
|
|
30
|
+
EXPOSE 3001
|
|
31
|
+
EXPOSE 3012
|
|
32
|
+
|
|
33
|
+
CMD npm run dev 2>&1 | tee /logs/log.txt
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
FROM node:16.13.1-alpine3.13 as base
|
|
2
|
+
RUN apk add --no-cache python3 py3-pip
|
|
3
|
+
|
|
4
|
+
ENV NODE_ENV=production
|
|
5
|
+
ENV APP_ENV=production
|
|
6
|
+
|
|
7
|
+
WORKDIR /app
|
|
8
|
+
EXPOSE 3001
|
|
9
|
+
COPY ["./package*.json", "./.eslintrc.js", "/app/"]
|
|
10
|
+
|
|
11
|
+
RUN npm set progress=false && npm config set depth 0
|
|
12
|
+
|
|
13
|
+
RUN npm set-script prepare ""
|
|
14
|
+
|
|
15
|
+
RUN npm ci --only=production --quiet
|
|
16
|
+
|
|
17
|
+
COPY ./ ./
|
|
18
|
+
|
|
19
|
+
RUN ls /app/src/config/.env
|
|
20
|
+
|
|
21
|
+
RUN rm /app/src/config/.env
|
|
22
|
+
RUN mv /app/src/config/.env.production /app/src/config/.env
|
|
23
|
+
|
|
24
|
+
RUN cat /app/src/config/.env
|
|
25
|
+
|
|
26
|
+
RUN mkdir -p /project/logs
|
|
27
|
+
RUN touch /project/logs/log.txt
|
|
28
|
+
|
|
29
|
+
CMD npm start 2>&1 | tee /project/logs/log.txt
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
DIR=$PROJECT_SRC
|
|
3
|
+
echo CHECKING $DIR
|
|
4
|
+
|
|
5
|
+
if [ -f "$DIR/package.json" ]; then
|
|
6
|
+
echo "Project already initialized"
|
|
7
|
+
else
|
|
8
|
+
### Control will jump here if $DIR does NOT exists ###
|
|
9
|
+
echo "Configuring project..."
|
|
10
|
+
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
|
11
|
+
cd ..
|
|
12
|
+
pwd
|
|
13
|
+
mkdir -p $PROJECT_SRC
|
|
14
|
+
|
|
15
|
+
echo Unzipping project starter to $DIR
|
|
16
|
+
unzip ./project-api-starter.zip -d $DIR
|
|
17
|
+
|
|
18
|
+
echo dir before script
|
|
19
|
+
ls $PROJECT_SRC
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
exit 1
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
// Function to create directories recursively
|
|
5
|
+
function mkdirRecursive(dir) {
|
|
6
|
+
if (!fs.existsSync(dir)) {
|
|
7
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Function to convert JSON schema to JavaScript code
|
|
12
|
+
function convertJsonToJs(schema) {
|
|
13
|
+
let jsCode = "const Joi = require('joi');\n\n";
|
|
14
|
+
jsCode += `const ${schema.name} = Joi.object({\n`;
|
|
15
|
+
for (const [key, value] of Object.entries(schema.schema)) {
|
|
16
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
17
|
+
jsCode += ` ${key}: Joi.object({\n`;
|
|
18
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
19
|
+
jsCode += ` ${subKey}: ${subValue},\n`;
|
|
20
|
+
}
|
|
21
|
+
jsCode += ` }),\n`;
|
|
22
|
+
} else {
|
|
23
|
+
jsCode += ` ${key}: ${value},\n`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
jsCode += "});\n\n";
|
|
27
|
+
jsCode += `module.exports = ${schema.name};\n`;
|
|
28
|
+
return jsCode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Function to generate endpoint code
|
|
32
|
+
function createEndpointCode(endpoint) {
|
|
33
|
+
let requestSchema = "const Joi = require('joi');\n\n";
|
|
34
|
+
requestSchema += "module.exports.requestSchema = Joi.object({\n";
|
|
35
|
+
for (const [key, value] of Object.entries(endpoint.requestSchema)) {
|
|
36
|
+
requestSchema += ` ${key}: ${value},\n`;
|
|
37
|
+
}
|
|
38
|
+
requestSchema += "});\n\n";
|
|
39
|
+
|
|
40
|
+
return `
|
|
41
|
+
${endpoint.handler}
|
|
42
|
+
|
|
43
|
+
${requestSchema}
|
|
44
|
+
module.exports.endpoint = ${JSON.stringify(endpoint.endpoint, null, 2)};
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Main function to generate the project structure
|
|
49
|
+
function generateProjectStructure(resources) {
|
|
50
|
+
resources.forEach((resource) => {
|
|
51
|
+
const resourceDir = path.join(__dirname, "src", "resources", resource.name);
|
|
52
|
+
mkdirRecursive(resourceDir);
|
|
53
|
+
|
|
54
|
+
// Create schemas directory and files
|
|
55
|
+
if (resource.schemas) {
|
|
56
|
+
const schemaDir = path.join(resourceDir);
|
|
57
|
+
mkdirRecursive(schemaDir);
|
|
58
|
+
resource.schemas.forEach((schema) => {
|
|
59
|
+
const schemaCode = convertJsonToJs(schema);
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(schemaDir, `${schema.name.toLowerCase()}.schema.js`),
|
|
62
|
+
schemaCode
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Create endpoints directory and files
|
|
68
|
+
if (resource.endpoints) {
|
|
69
|
+
const endpointDir = path.join(resourceDir, "endpoints");
|
|
70
|
+
mkdirRecursive(endpointDir);
|
|
71
|
+
resource.endpoints.forEach((endpoint) => {
|
|
72
|
+
const endpointCode = createEndpointCode(endpoint);
|
|
73
|
+
fs.writeFileSync(
|
|
74
|
+
path.join(endpointDir, `${endpoint.name}.js`),
|
|
75
|
+
endpointCode
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Create handlers directory and files
|
|
81
|
+
if (resource.handlers) {
|
|
82
|
+
const handlerDir = path.join(resourceDir, "handlers");
|
|
83
|
+
mkdirRecursive(handlerDir);
|
|
84
|
+
resource.handlers.forEach((handler) => {
|
|
85
|
+
const handlerCode = handler.handler;
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
path.join(handlerDir, `${handler.name}.js`),
|
|
88
|
+
handlerCode
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create methods directory and files
|
|
94
|
+
if (resource.methods) {
|
|
95
|
+
const methodDir = path.join(resourceDir, "methods");
|
|
96
|
+
mkdirRecursive(methodDir);
|
|
97
|
+
resource.methods.forEach((method) => {
|
|
98
|
+
const methodCode = method.handler;
|
|
99
|
+
fs.writeFileSync(path.join(methodDir, `${method.name}.js`), methodCode);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Main entry point
|
|
106
|
+
const [, , jsonFilePath] = process.argv;
|
|
107
|
+
|
|
108
|
+
if (!jsonFilePath) {
|
|
109
|
+
console.error("Please provide the path to the JSON file.");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const rawData = fs.readFileSync(jsonFilePath, "utf8");
|
|
114
|
+
const { resources } = JSON.parse(rawData);
|
|
115
|
+
|
|
116
|
+
generateProjectStructure(resources);
|
|
117
|
+
|
|
118
|
+
console.log("Hive-based project structure generated successfully.");
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
{
|
|
2
|
+
"resources": [
|
|
3
|
+
{
|
|
4
|
+
"name": "users",
|
|
5
|
+
"endpoints": [
|
|
6
|
+
{
|
|
7
|
+
"name": "getCurrentUser",
|
|
8
|
+
"endpoint": { "method": "GET", "url": "/me" },
|
|
9
|
+
"requestSchema": {},
|
|
10
|
+
"handler": "module.exports.handler = async (ctx) => { const user = await userService.findOne({ _id: ctx.state.user._id }); ctx.body = user; }"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "getUserProfile",
|
|
14
|
+
"endpoint": { "method": "GET", "url": "/profile/:userId" },
|
|
15
|
+
"requestSchema": {
|
|
16
|
+
"userId": "Joi.string().required()"
|
|
17
|
+
},
|
|
18
|
+
"handler": "module.exports.handler = async (ctx) => { const { userId } = ctx.params; const user = await userService.findOne({ _id: userId }); ctx.body = user; }"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"handlers": [],
|
|
22
|
+
"methods": [],
|
|
23
|
+
"schemas": [
|
|
24
|
+
{
|
|
25
|
+
"name": "users",
|
|
26
|
+
"schema": {
|
|
27
|
+
"username": "Joi.string().required()",
|
|
28
|
+
"email": "Joi.string().email().required()",
|
|
29
|
+
"password": "Joi.string().required()",
|
|
30
|
+
"bio": "Joi.string()",
|
|
31
|
+
"avatarUrl": "Joi.string().uri()",
|
|
32
|
+
"_id": "Joi.string()",
|
|
33
|
+
"createdOn": "Joi.date()",
|
|
34
|
+
"updatedOn": "Joi.date()"
|
|
35
|
+
},
|
|
36
|
+
"_schemaMappings": {}
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "follows",
|
|
42
|
+
"endpoints": [
|
|
43
|
+
{
|
|
44
|
+
"name": "followUser",
|
|
45
|
+
"endpoint": { "method": "POST", "url": "/" },
|
|
46
|
+
"requestSchema": {
|
|
47
|
+
"followingId": "Joi.string().required()"
|
|
48
|
+
},
|
|
49
|
+
"handler": "module.exports.handler = async (ctx) => { const { followingId } = ctx.validatedData; const followerId = ctx.state.user._id; const newFollow = await followService.create({ follower: { _id: followerId }, following: { _id: followingId } }); ctx.body = newFollow; }"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "unfollowUser",
|
|
53
|
+
"endpoint": { "method": "DELETE", "url": "/" },
|
|
54
|
+
"requestSchema": {
|
|
55
|
+
"followingId": "Joi.string().required()"
|
|
56
|
+
},
|
|
57
|
+
"handler": "module.exports.handler = async (ctx) => { const { followingId } = ctx.validatedData; const followerId = ctx.state.user._id; await followService.remove({ follower: { _id: followerId }, following: { _id: followingId } }); ctx.body = { message: 'Unfollowed successfully' }; }"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"handlers": [
|
|
61
|
+
{
|
|
62
|
+
"name": "updateFollowersCount",
|
|
63
|
+
"handler": "const userService = require('../../../db').services.users; const followService = require('../../../db').services.follows; followService.on('created', async ({ doc: follow }) => { const { followingId } = follow; await userService.atomic.update({ _id: followingId }, { $inc: { followersCount: 1 } }); }); followService.on('removed', async ({ doc: follow }) => { const { followingId } = follow; await userService.atomic.update({ _id: followingId }, { $inc: { followersCount: -1 } }); });"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"methods": [],
|
|
67
|
+
"schemas": [
|
|
68
|
+
{
|
|
69
|
+
"name": "follows",
|
|
70
|
+
"schema": {
|
|
71
|
+
"follower": { "_id": "Joi.string().required()" },
|
|
72
|
+
"following": { "_id": "Joi.string().required()" },
|
|
73
|
+
"_id": "Joi.string()",
|
|
74
|
+
"createdOn": "Joi.date()",
|
|
75
|
+
"updatedOn": "Joi.date()"
|
|
76
|
+
},
|
|
77
|
+
"_schemaMappings": {}
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "posts",
|
|
83
|
+
"endpoints": [
|
|
84
|
+
{
|
|
85
|
+
"name": "createPost",
|
|
86
|
+
"endpoint": { "method": "POST", "url": "/" },
|
|
87
|
+
"requestSchema": {
|
|
88
|
+
"content": "Joi.string().max(280).required()",
|
|
89
|
+
"fileUrl": "Joi.string().allow(null, '')"
|
|
90
|
+
},
|
|
91
|
+
"handler": "module.exports.handler = async (ctx) => { const { content, fileUrl } = ctx.validatedData; const userId = ctx.state.user._id; const username = ctx.state.user.username; const newPost = await postService.create({ content, fileUrl, creator: { _id: userId, username: username } }); ctx.body = newPost; }"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "getFeed",
|
|
95
|
+
"endpoint": { "method": "GET", "url": "/feed" },
|
|
96
|
+
"requestSchema": {},
|
|
97
|
+
"handler": "module.exports.handler = async (ctx) => { const posts = await postService.find({}, { sort: { createdOn: -1 } }); ctx.body = posts; }"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "likePost",
|
|
101
|
+
"endpoint": { "method": "POST", "url": "/:postId/like" },
|
|
102
|
+
"requestSchema": {},
|
|
103
|
+
"handler": "module.exports.handler = async (ctx) => { const { postId } = ctx.params; const userId = ctx.state.user._id; await likeService.create({ post: { _id: postId }, user: { _id: userId } }); await postService.atomic.update({ _id: postId }, { $inc: { likesCount: 1 } }); ctx.body = { message: 'Post liked' }; }"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "commentOnPost",
|
|
107
|
+
"endpoint": { "method": "POST", "url": "/:postId/comment" },
|
|
108
|
+
"requestSchema": {
|
|
109
|
+
"content": "Joi.string().required()"
|
|
110
|
+
},
|
|
111
|
+
"handler": "module.exports.handler = async (ctx) => { const { postId } = ctx.params; const { content } = ctx.validatedData; const userId = ctx.state.user._id; const username = ctx.state.user.username; const newComment = await commentService.create({ post: { _id: postId }, content, creator: { _id: userId, username: username }, createdOn: new Date() }); await postService.atomic.update({ _id: postId }, { $inc: { commentsCount: 1 } }); ctx.body = newComment; }"
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"handlers": [
|
|
115
|
+
{
|
|
116
|
+
"name": "updateCommentsCount",
|
|
117
|
+
"handler": "const postService = require('../../../db').services.posts; const commentService = require('../../../db').services.comments; commentService.on('created', async ({ doc: comment }) => { const { post } = comment; await postService.atomic.update({ _id: post._id }, { $inc: { commentsCount: 1 } }); }); commentService.on('removed', async ({ doc: comment }) => { const { post } = comment; await postService.atomic.update({ _id: post._id }, { $inc: { commentsCount: -1 } }); });"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "updateLikesCount",
|
|
121
|
+
"handler": "const postService = require('../../../db').services.posts; const likeService = require('../../../db').services.likes; likeService.on('created', async ({ doc: like }) => { const { postId } = like; await postService.atomic.update({ _id: postId }, { $inc: { likesCount: 1 } }); }); likeService.on('removed', async ({ doc: like }) => { const { postId } = like; await postService.atomic.update({ _id: postId }, { $inc: { likesCount: -1 } }); });"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "notifyUserOnComment",
|
|
125
|
+
"handler": ""
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"methods": [],
|
|
129
|
+
"schemas": [
|
|
130
|
+
{
|
|
131
|
+
"name": "posts",
|
|
132
|
+
"schema": {
|
|
133
|
+
"content": "Joi.string().max(280).required()",
|
|
134
|
+
"fileUrl": "Joi.string().allow(null, '')",
|
|
135
|
+
"creator": {
|
|
136
|
+
"_id": "Joi.string().required()",
|
|
137
|
+
"username": "Joi.string()"
|
|
138
|
+
},
|
|
139
|
+
"likesCount": "Joi.number().default(0)",
|
|
140
|
+
"commentsCount": "Joi.number().default(0)",
|
|
141
|
+
"parentPost": {
|
|
142
|
+
"_id": "Joi.string()",
|
|
143
|
+
"content": "Joi.string()",
|
|
144
|
+
"creator": "Joi.object()",
|
|
145
|
+
"likesCount": "Joi.number().default(0)",
|
|
146
|
+
"commentsCount": "Joi.number().default(0)"
|
|
147
|
+
},
|
|
148
|
+
"_id": "Joi.string()",
|
|
149
|
+
"createdOn": "Joi.date()",
|
|
150
|
+
"updatedOn": "Joi.date()"
|
|
151
|
+
},
|
|
152
|
+
"_schemaMappings": {}
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "likes",
|
|
158
|
+
"endpoints": [],
|
|
159
|
+
"handlers": [],
|
|
160
|
+
"methods": [],
|
|
161
|
+
"schemas": [
|
|
162
|
+
{
|
|
163
|
+
"name": "likes",
|
|
164
|
+
"schema": {
|
|
165
|
+
"post": { "_id": "Joi.string().required()" },
|
|
166
|
+
"user": { "_id": "Joi.string().required()" },
|
|
167
|
+
"_id": "Joi.string()",
|
|
168
|
+
"createdOn": "Joi.date()",
|
|
169
|
+
"updatedOn": "Joi.date()"
|
|
170
|
+
},
|
|
171
|
+
"_schemaMappings": {}
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIFgjCCA2qgAwIBAgIRAJgporgNYE10qopO4ueSLR8wDQYJKoZIhvcNAQELBQAw
|
|
3
|
+
WTEVMBMGA1UEChMMRGlnaXRhbE9jZWFuMUAwPgYDVQQDEzdtb25nb2RiIENsdXN0
|
|
4
|
+
ZXIgQ0E6OTgyOWEyYjgtMGQ2MC00ZDc0LWFhOGEtNGVlMmU3OTIyZDFmMB4XDTIy
|
|
5
|
+
MDQyODE1MDI1NloXDTQyMDQyODE1MDI1NlowWTEVMBMGA1UEChMMRGlnaXRhbE9j
|
|
6
|
+
ZWFuMUAwPgYDVQQDEzdtb25nb2RiIENsdXN0ZXIgQ0E6OTgyOWEyYjgtMGQ2MC00
|
|
7
|
+
ZDc0LWFhOGEtNGVlMmU3OTIyZDFmMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
|
8
|
+
CgKCAgEAvfroNWnTm6ycVLh5Ra/miiLe1ol0ZCzixbCvf8zxdCrg0scp51XL5eFR
|
|
9
|
+
40hncT4bzV0AUCu97QGviNAxHsLUUxNCd5zZwKYx6BvbZNXrb9NtFlXf9XHPW4DT
|
|
10
|
+
cV4KTQMvce6p7KjknL4pazqr3AmV6Nm2p4CHdmOtlMcspw76/DunRAgKMw8pOV0e
|
|
11
|
+
VZu+mV9f7UMFnXaA0tPhPqTd2ZWTt47nsFnEZEiCnePYDNf+BtWvGyxefjw1mHxr
|
|
12
|
+
h/9sm5YNsNnhQiUT71GGHIFgiYM8y47t6jGCEqjhD3pXnkaAuoyyoMZYing+1CXN
|
|
13
|
+
rd6s1Ca7w+F+aNxTOSMZdYeBAokNYyQhvzeGbHEpuRsl10Vx48zIA5ej6UrlADzc
|
|
14
|
+
Ch0arO+LGSpz59UZ3Inr6O+a+CNKCcD5J7ZA0Qrp9vqJaR5wEHd7MTR2zIp8OaN3
|
|
15
|
+
beE/n+dohpVDClpRO4j2ACUBS2YMk6bsVKwlwU7uJ2l/pucNMrZaleJAZoGEJ/8I
|
|
16
|
+
EMv5WfiZz504zSgIxGzGpDt8+0D36FW8tz1uYlLmy9IdvHr5dshsfDVvMpqyiphU
|
|
17
|
+
NTkO3jRnP5IDbn9w7CXohNPFvfqelx6e3gWtjINN/K+XMansqCqZWtMNuEbsX+oK
|
|
18
|
+
6T4j8LOQB0NYFhzLthFGxEDiaeHHi2tRRRX54dv9ogfxFBpUlbkCAwEAAaNFMEMw
|
|
19
|
+
DgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFD+P
|
|
20
|
+
ZtQ9wxLE6gLewtQC3U/jQIEiMA0GCSqGSIb3DQEBCwUAA4ICAQAsbuX1SBWMvWJR
|
|
21
|
+
hesLsIpwG7KhIsrvhOIE9G8cumJW3jssWFBdyt7HH+/IpSG7SVkuSz+/NAcd0q6K
|
|
22
|
+
p7UWnp8MW+rfzET671S6hNSv4h/zgLA3r0fSqSRMU7rZ+qSvIrQpxav7o/3wPtj+
|
|
23
|
+
gkc2/x5wTUfAYnV2liqj0LfWI5bXsWgupdyDa8VA8T026e70QctpdqwIVLUIUDQz
|
|
24
|
+
gS0aF8UZymDsajETKJLxdtAAyhfnqCoQ5qNfroNhioisYDa9QsYyZ8cw9nJAAWPm
|
|
25
|
+
SQfGEf4/m8ookTPRDlI8KaTR2TbM0QJThWxjeiJoZS4gA34ao+4a1uyVgaxU0Ygd
|
|
26
|
+
73NcQYEWfSH9N1Lhnaw5pQNBfjta04GO26p+/c+9t1kMFFz2ZfTxpN6xjn9ZJJYZ
|
|
27
|
+
nnafp6nqWADgnbD3cWbTsHLGm6Rqbh18oy4jPrxCYQQQCCn1eba75KAVxf70GI32
|
|
28
|
+
VhyPBBV4rHBi4gmKmBueSzb5gjzXgn8R0kxKPhhmLmZ1XK7gF/EbD9B1JGUQLp7S
|
|
29
|
+
ITv+WZMHuErZt61cnZ0XM6jJYg3QAejY9V0UIp8j2ud83H1Np7fQlWyOZYxa+czK
|
|
30
|
+
x6ZyNLojjJmUEwpn/pjieFI73n7nmITxvkl78c7ga11xbrJEXiN5GOQh5Wr+lBAF
|
|
31
|
+
lNQexy8hyosbG0wXXPHX5wwu5eXVeA==
|
|
32
|
+
-----END CERTIFICATE-----
|