@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
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const winston = require("winston");
|
|
2
|
+
const config = require("config");
|
|
3
|
+
|
|
4
|
+
const colorizer = winston.format.colorize();
|
|
5
|
+
|
|
6
|
+
const createConsoleLogger = () => {
|
|
7
|
+
// eslint-disable-next-line new-cap
|
|
8
|
+
const logger = new winston.createLogger({
|
|
9
|
+
exitOnError: false,
|
|
10
|
+
level: config.isDev ? "debug" : "info",
|
|
11
|
+
format: winston.format.combine(
|
|
12
|
+
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
13
|
+
config.isDev
|
|
14
|
+
? winston.format.printf((msg) =>
|
|
15
|
+
colorizer.colorize(
|
|
16
|
+
msg.level,
|
|
17
|
+
`${msg.timestamp} - ${msg.level}: ${JSON.stringify(msg.message)}`
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
: winston.format.json()
|
|
21
|
+
),
|
|
22
|
+
transports: [new winston.transports.Console()],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
logger.debug("[logger] Configured console based logger");
|
|
26
|
+
|
|
27
|
+
return logger;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
module.exports = createConsoleLogger();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const storeTokenToState = async (ctx, next) => {
|
|
2
|
+
let accessToken = ctx.cookies.get("ship_access_token");
|
|
3
|
+
|
|
4
|
+
const { authorization } = ctx.headers;
|
|
5
|
+
|
|
6
|
+
if (!accessToken && authorization) {
|
|
7
|
+
accessToken = authorization.replace("Bearer", "").trim();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
ctx.state.accessToken = accessToken;
|
|
11
|
+
|
|
12
|
+
await next();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports = storeTokenToState;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const userService = require("db").services.users;
|
|
2
|
+
const tokenService = require("db").services.tokens;
|
|
3
|
+
|
|
4
|
+
const storeTokenToState = async (ctx) => {
|
|
5
|
+
let accessToken = ctx.cookies.get("access_token");
|
|
6
|
+
|
|
7
|
+
const { authorization } = ctx.headers;
|
|
8
|
+
|
|
9
|
+
if (!accessToken && authorization) {
|
|
10
|
+
accessToken = authorization.replace("Bearer", "").trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
ctx.state.accessToken = accessToken;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const tryToAttachUser = async (ctx, next) => {
|
|
17
|
+
storeTokenToState(ctx);
|
|
18
|
+
|
|
19
|
+
// let token;
|
|
20
|
+
|
|
21
|
+
// if (ctx.state.accessToken) {
|
|
22
|
+
// token = await tokenService.findOne({ token: ctx.state.accessToken });
|
|
23
|
+
// }
|
|
24
|
+
|
|
25
|
+
// if (token) {
|
|
26
|
+
// ctx.state.user = await userService.findOne({ _id: token.user._id });
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
return next();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = tryToAttachUser;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const db = require("db");
|
|
2
|
+
|
|
3
|
+
module.exports = (
|
|
4
|
+
resourceName,
|
|
5
|
+
{ criteria = (ctx) => ({ _id: ctx.params[`${resourceName}Id`] }) } = {}
|
|
6
|
+
) => {
|
|
7
|
+
return async (ctx, next) => {
|
|
8
|
+
const doc = await db.services[resourceName].findOne(criteria(ctx));
|
|
9
|
+
ctx.state[resourceName] = doc;
|
|
10
|
+
|
|
11
|
+
if (!doc) {
|
|
12
|
+
ctx.throw(404, { message: `${resourceName} not found` });
|
|
13
|
+
} else {
|
|
14
|
+
await next();
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const _ = require("lodash");
|
|
2
|
+
const db = require("db");
|
|
3
|
+
|
|
4
|
+
module.exports = (
|
|
5
|
+
resourceName,
|
|
6
|
+
{ criteria = (ctx) => ({ name: ctx.validatedData.name }) } = {}
|
|
7
|
+
) => {
|
|
8
|
+
return async (ctx, next) => {
|
|
9
|
+
const doc = await db.services[resourceName].findOne(criteria(ctx));
|
|
10
|
+
|
|
11
|
+
if (doc) {
|
|
12
|
+
ctx.throw(400, {
|
|
13
|
+
message: `${_.capitalize(resourceName)} already exists`,
|
|
14
|
+
});
|
|
15
|
+
} else {
|
|
16
|
+
await next();
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const Joi = require("joi");
|
|
2
|
+
|
|
3
|
+
function formatError(joiError) {
|
|
4
|
+
const errors = {};
|
|
5
|
+
|
|
6
|
+
joiError.details.forEach((error) => {
|
|
7
|
+
const key = error.path.join(".");
|
|
8
|
+
errors[key] = errors[key] || [];
|
|
9
|
+
errors[key].push(error.message);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return errors;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function validate(schema) {
|
|
16
|
+
return async (ctx, next) => {
|
|
17
|
+
if (!schema.validate) {
|
|
18
|
+
schema = Joi.object(schema);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { value, error } = await schema.validate(
|
|
22
|
+
{
|
|
23
|
+
...ctx.request.body,
|
|
24
|
+
...ctx.query,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
abortEarly: false,
|
|
28
|
+
allowUnknown: true,
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (error) ctx.throw(400, { errors: formatError(error) });
|
|
33
|
+
|
|
34
|
+
ctx.validatedData = value;
|
|
35
|
+
await next();
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = validate;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const db = require("db");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const _ = require("lodash");
|
|
5
|
+
const validateSchema = require("./migrations.schema");
|
|
6
|
+
|
|
7
|
+
const service = db.createService("__migrationVersion", {
|
|
8
|
+
validate: validateSchema,
|
|
9
|
+
});
|
|
10
|
+
const migrationsPath = path.join(__dirname, "migrations");
|
|
11
|
+
const _id = "migration_version";
|
|
12
|
+
|
|
13
|
+
const getMigrationNames = () =>
|
|
14
|
+
new Promise((resolve, reject) => {
|
|
15
|
+
fs.readdir(migrationsPath, (err, files) => {
|
|
16
|
+
if (err) {
|
|
17
|
+
reject(err);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
resolve(files);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
service.getCurrentMigrationVersion = () =>
|
|
25
|
+
service.findOne({ _id }).then((doc) => {
|
|
26
|
+
if (!doc) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return doc.version;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
service.getMigrations = () => {
|
|
34
|
+
let migrations = null;
|
|
35
|
+
|
|
36
|
+
return getMigrationNames()
|
|
37
|
+
.then((names) => {
|
|
38
|
+
migrations = names.map((name) => {
|
|
39
|
+
const migrationPath = path.join(migrationsPath, name);
|
|
40
|
+
// eslint-disable-next-line import/no-dynamic-require, global-require
|
|
41
|
+
return require(migrationPath);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return migrations;
|
|
45
|
+
})
|
|
46
|
+
.catch((err) => {
|
|
47
|
+
throw err;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
service.setNewMigrationVersion = (version) =>
|
|
52
|
+
service.atomic.findOneAndUpdate(
|
|
53
|
+
{ _id },
|
|
54
|
+
{
|
|
55
|
+
$set: {
|
|
56
|
+
version,
|
|
57
|
+
},
|
|
58
|
+
$setOnInsert: {
|
|
59
|
+
_id,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{ upsert: true }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
service.promiseLimit = (documents = [], limit, operator) => {
|
|
66
|
+
const chunks = _.chunk(documents, limit);
|
|
67
|
+
|
|
68
|
+
return chunks.reduce((init, chunk) => {
|
|
69
|
+
return init.then(() => {
|
|
70
|
+
return Promise.all(chunk.map((c) => operator(c)));
|
|
71
|
+
});
|
|
72
|
+
}, Promise.resolve());
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports = service;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const Migration = require("migrations/migration");
|
|
2
|
+
// const migrationService = require('migrations/migration.service');
|
|
3
|
+
//
|
|
4
|
+
// const userService = require('resources/user/user.service');
|
|
5
|
+
|
|
6
|
+
const migration = new Migration(1, "Example");
|
|
7
|
+
|
|
8
|
+
migration.migrate = async () => {
|
|
9
|
+
// const userIds = await userService.distinct('_id', {
|
|
10
|
+
// isEmailVerified: true,
|
|
11
|
+
// });
|
|
12
|
+
//
|
|
13
|
+
// await migrationService.promiseLimit(userIds, 50, (userId) => userService.updateOne(
|
|
14
|
+
// { _id: userId },
|
|
15
|
+
// (old) => ({
|
|
16
|
+
// ...old,
|
|
17
|
+
// isEmailVerified: false,
|
|
18
|
+
// }),
|
|
19
|
+
// ));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
module.exports = migration;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const Joi = require("joi");
|
|
2
|
+
|
|
3
|
+
const schema = Joi.object({
|
|
4
|
+
_id: Joi.string(),
|
|
5
|
+
createdOn: Joi.date(),
|
|
6
|
+
updatedOn: Joi.date(),
|
|
7
|
+
startTime: Joi.date().required(),
|
|
8
|
+
finishTime: Joi.date(),
|
|
9
|
+
status: Joi.string().required(),
|
|
10
|
+
error: Joi.string(),
|
|
11
|
+
errorStack: Joi.string(),
|
|
12
|
+
duration: Joi.string(),
|
|
13
|
+
migrationVersion: Joi.number().required(),
|
|
14
|
+
});
|
|
15
|
+
module.exports = schema;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const db = require("db");
|
|
2
|
+
|
|
3
|
+
const validateSchema = require("./migration-log.schema.js");
|
|
4
|
+
|
|
5
|
+
const service = db.createService("__migrationLog", {
|
|
6
|
+
validate: validateSchema,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
service.startMigrationLog = (_id, startTime, migrationVersion) => {
|
|
10
|
+
return service.atomic.findOneAndUpdate(
|
|
11
|
+
{ _id },
|
|
12
|
+
{
|
|
13
|
+
$set: {
|
|
14
|
+
migrationVersion,
|
|
15
|
+
startTime,
|
|
16
|
+
status: "running",
|
|
17
|
+
},
|
|
18
|
+
$setOnInsert: {
|
|
19
|
+
_id,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{ upsert: true }
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
service.failMigrationLog = (_id, finishTime, err) =>
|
|
27
|
+
service.atomic.update(
|
|
28
|
+
{ _id },
|
|
29
|
+
{
|
|
30
|
+
$set: {
|
|
31
|
+
finishTime,
|
|
32
|
+
status: "failed",
|
|
33
|
+
error: err.message,
|
|
34
|
+
errorStack: err.stack,
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
service.finishMigrationLog = (_id, finishTime, duration) =>
|
|
40
|
+
service.atomic.update(
|
|
41
|
+
{ _id },
|
|
42
|
+
{
|
|
43
|
+
$set: {
|
|
44
|
+
finishTime,
|
|
45
|
+
status: "completed",
|
|
46
|
+
duration,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
module.exports = service;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require("moment-duration-format");
|
|
2
|
+
const moment = require("moment");
|
|
3
|
+
|
|
4
|
+
const logger = require("logger");
|
|
5
|
+
|
|
6
|
+
const migrationLogService = require("./migrations-log/migration-log.service");
|
|
7
|
+
const migrationService = require("./migration.service");
|
|
8
|
+
|
|
9
|
+
const migrator = {};
|
|
10
|
+
|
|
11
|
+
const run = async (migrations, curVersion) => {
|
|
12
|
+
const newMigrations = migrations
|
|
13
|
+
.filter((migration) => migration.version > curVersion)
|
|
14
|
+
.sort((a, b) => a.version - b.version);
|
|
15
|
+
|
|
16
|
+
if (!newMigrations.length) {
|
|
17
|
+
logger.info(`No new migrations found, stopping the process.
|
|
18
|
+
Current database version is ${curVersion}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let migrationLogId;
|
|
23
|
+
let migration;
|
|
24
|
+
let lastMigrationVersion;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
for (migration of newMigrations) {
|
|
28
|
+
//eslint-disable-line
|
|
29
|
+
migrationLogId = migrationService.generateId();
|
|
30
|
+
const startTime = new Date();
|
|
31
|
+
await migrationLogService.startMigrationLog(
|
|
32
|
+
migrationLogId,
|
|
33
|
+
startTime,
|
|
34
|
+
migration.version
|
|
35
|
+
); //eslint-disable-line
|
|
36
|
+
logger.info(
|
|
37
|
+
`Migration #${migration.version} is running: ${migration.description}`
|
|
38
|
+
);
|
|
39
|
+
await migration.migrate(); //eslint-disable-line
|
|
40
|
+
|
|
41
|
+
lastMigrationVersion = migration.version;
|
|
42
|
+
await migrationService.setNewMigrationVersion(migration.version); //eslint-disable-line
|
|
43
|
+
const finishTime = new Date();
|
|
44
|
+
const duration = moment
|
|
45
|
+
.duration(finishTime - startTime)
|
|
46
|
+
.format("h [hrs], m [min], s [sec], S [ms]");
|
|
47
|
+
|
|
48
|
+
await migrationLogService.finishMigrationLog(
|
|
49
|
+
migrationLogId,
|
|
50
|
+
finishTime,
|
|
51
|
+
duration
|
|
52
|
+
); //eslint-disable-line
|
|
53
|
+
logger.info(
|
|
54
|
+
`Database has been updated to the version #${migration.version}`
|
|
55
|
+
);
|
|
56
|
+
logger.info(`Time of migration #${migration.version}: ${duration}`);
|
|
57
|
+
}
|
|
58
|
+
logger.info(`All migrations has been finished, stopping the process.
|
|
59
|
+
Current database version is: ${lastMigrationVersion}`);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
logger.error(`Failed to update migration to version ${migration.version}`);
|
|
62
|
+
logger.error(err);
|
|
63
|
+
await migrationLogService.failMigrationLog(migrationLogId, new Date(), err);
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
migrator.exec = async () => {
|
|
69
|
+
const [migrations, currentVersion] = await Promise.all([
|
|
70
|
+
migrationService.getMigrations(),
|
|
71
|
+
migrationService.getCurrentMigrationVersion(),
|
|
72
|
+
]);
|
|
73
|
+
await run(migrations, currentVersion);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
module.exports = migrator;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const Joi = require("joi");
|
|
2
|
+
|
|
3
|
+
module.exports.endpoint = {
|
|
4
|
+
method: "put",
|
|
5
|
+
url: "/trigger-scheduler-handler",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
module.exports.requestSchema = {
|
|
9
|
+
name: Joi.string().required(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports.handler = async (ctx) => {
|
|
13
|
+
const { name } = ctx.validatedData;
|
|
14
|
+
|
|
15
|
+
const schedulerHandler = require(`scheduler/handlers/${name}`);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const data = await schedulerHandler.handler();
|
|
19
|
+
|
|
20
|
+
ctx.body = {
|
|
21
|
+
ok: true,
|
|
22
|
+
data,
|
|
23
|
+
};
|
|
24
|
+
} catch (err) {
|
|
25
|
+
ctx.body = {
|
|
26
|
+
ok: false,
|
|
27
|
+
err: err.message,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module.exports.handler = async (ctx) => {
|
|
2
|
+
const user = await userService.findOne({ _id: ctx.state.user._id });
|
|
3
|
+
ctx.body = user;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
const Joi = require("joi");
|
|
7
|
+
|
|
8
|
+
module.exports.requestSchema = Joi.object({});
|
|
9
|
+
|
|
10
|
+
module.exports.endpoint = {
|
|
11
|
+
method: "GET",
|
|
12
|
+
url: "/me",
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module.exports.handler = async (ctx) => {
|
|
2
|
+
const { userId } = ctx.params;
|
|
3
|
+
const user = await userService.findOne({ _id: userId });
|
|
4
|
+
ctx.body = user;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
const Joi = require("joi");
|
|
8
|
+
|
|
9
|
+
module.exports.requestSchema = Joi.object({
|
|
10
|
+
userId: Joi.string().required(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
module.exports.endpoint = {
|
|
14
|
+
method: "GET",
|
|
15
|
+
url: "/profile/:userId",
|
|
16
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const Joi = require("joi");
|
|
2
|
+
|
|
3
|
+
const users = Joi.object({
|
|
4
|
+
username: Joi.string().required(),
|
|
5
|
+
email: Joi.string().email().required(),
|
|
6
|
+
password: Joi.string().required(),
|
|
7
|
+
bio: Joi.string(),
|
|
8
|
+
avatarUrl: Joi.string().uri(),
|
|
9
|
+
_id: Joi.string(),
|
|
10
|
+
createdOn: Joi.date(),
|
|
11
|
+
updatedOn: Joi.date(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
module.exports = users;
|