mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-12-27 02:10:52 +08:00
made metaData visible for user, added new property internalData
This commit is contained in:
parent
2fdf9ec2e4
commit
6fafcaa957
3 changed files with 86 additions and 51 deletions
|
@ -237,12 +237,12 @@
|
|||
},
|
||||
|
||||
"userlisting": {
|
||||
"read:own": ["*", "!tags", "!metaData", "!disabledScopes"]
|
||||
"read:own": ["*", "!tags", "!disabledScopes", "!internalData"]
|
||||
},
|
||||
|
||||
"users": {
|
||||
"read:own": ["*", "!tags", "!metaData", "!disabledScopes"],
|
||||
"update:own": ["*", "!tags", "!metaData", "!disabledScopes"]
|
||||
"read:own": ["*", "!tags", "!disabledScopes", "!internalData"],
|
||||
"update:own": ["*", "!tags", "!disabledScopes", "!internalData"]
|
||||
},
|
||||
|
||||
"asps": {
|
||||
|
|
123
lib/api/users.js
123
lib/api/users.js
|
@ -31,6 +31,7 @@ module.exports = (db, server, userHandler) => {
|
|||
* @apiParam {String} [tags] Comma separated list of tags. The User must have at least one to be set
|
||||
* @apiParam {String} [requiredTags] Comma separated list of tags. The User must have all listed tags to be set
|
||||
* @apiParam {Boolean} [metaData] If true, then includes <code>metaData</code> in the response
|
||||
* @apiParam {Boolean} [internalData] If true, then includes <code>internalData</code> in the response. Not shown for user-role tokens.
|
||||
* @apiParam {Number} [limit=20] How many records to return
|
||||
* @apiParam {Number} [page=1] Current page number. Informational only, page numbers start from 1
|
||||
* @apiParam {Number} [next] Cursor value for next page, retrieved from <code>nextCursor</code> response value
|
||||
|
@ -54,6 +55,7 @@ module.exports = (db, server, userHandler) => {
|
|||
* @apiSuccess {Boolean} results.encryptForwarded If <code>true</code> then forwarded messages are encrypted
|
||||
* @apiSuccess {Object} results.quota Quota usage limits
|
||||
* @apiSuccess {Object} [results.metaData] Custom metadata value. Included if <code>metaData</code> query argument was true
|
||||
* @apiSuccess {Object} [results.internalData] Custom metadata value for internal use. Included if <code>internalData</code> query argument was true and request was not made using user-role token
|
||||
* @apiSuccess {Number} results.quota.allowed Allowed quota of the user in bytes
|
||||
* @apiSuccess {Number} results.quota.used Space used in bytes
|
||||
* @apiSuccess {Boolean} results.hasPasswordSet If <code>true</code> then the User has a password set and can authenticate
|
||||
|
@ -114,6 +116,7 @@ module.exports = (db, server, userHandler) => {
|
|||
tags: Joi.string().trim().empty('').max(1024),
|
||||
requiredTags: Joi.string().trim().empty('').max(1024),
|
||||
metaData: booleanSchema,
|
||||
internalData: booleanSchema,
|
||||
limit: Joi.number().default(20).min(1).max(250),
|
||||
next: nextPageCursorSchema,
|
||||
previous: previousPageCursorSchema,
|
||||
|
@ -253,6 +256,10 @@ module.exports = (db, server, userHandler) => {
|
|||
opts.fields.projection.metaData = true;
|
||||
}
|
||||
|
||||
if (result.value.internalData) {
|
||||
opts.fields.projection.internalData = true;
|
||||
}
|
||||
|
||||
if (pageNext) {
|
||||
opts.next = pageNext;
|
||||
} else if ((!page || page > 1) && pagePrevious) {
|
||||
|
@ -307,6 +314,10 @@ module.exports = (db, server, userHandler) => {
|
|||
values.metaData = formatMetaData(userData.metaData);
|
||||
}
|
||||
|
||||
if (userData.internalData) {
|
||||
values.internalData = formatMetaData(userData.internalData);
|
||||
}
|
||||
|
||||
return permission.filter(values);
|
||||
})
|
||||
};
|
||||
|
@ -342,6 +353,7 @@ module.exports = (db, server, userHandler) => {
|
|||
* @apiParam {Boolean} [encryptForwarded] If <code>true</code> then forwarded messages are encrypted
|
||||
* @apiParam {String} [pubKey] Public PGP key for the User that is used for encryption. Use empty string to remove the key
|
||||
* @apiParam {Object|String} [metaData] Optional metadata, must be an object or JSON formatted string of an object
|
||||
* @apiParam {Object|String} [internalData] Optional metadata for internal use, must be an object or JSON formatted string of an object. Not available for user-role tokens
|
||||
* @apiParam {String} [language] Language code for the User
|
||||
* @apiParam {String[]} [targets] An array of forwarding targets. The value could either be an email address or a relay url to next MX server ("smtp://mx2.zone.eu:25") or an URL where mail contents are POSTed to
|
||||
* @apiParam {Number} [spamLevel=50] Relative scale for detecting spam. 0 means that everything is spam, 100 means that nothing is spam
|
||||
|
@ -493,6 +505,14 @@ module.exports = (db, server, userHandler) => {
|
|||
Joi.object()
|
||||
),
|
||||
|
||||
internalData: Joi.alternatives().try(
|
||||
Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(1024 * 1024),
|
||||
Joi.object()
|
||||
),
|
||||
|
||||
pubKey: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
|
@ -659,29 +679,31 @@ module.exports = (db, server, userHandler) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
if (result.value.metaData) {
|
||||
if (typeof result.value.metaData === 'object') {
|
||||
try {
|
||||
result.value.metaData = JSON.stringify(result.value.metaData);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'metaData value must be serializable to JSON',
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let value = JSON.parse(result.value.metaData);
|
||||
if (!value || typeof value !== 'object') {
|
||||
throw new Error('Not an object');
|
||||
for (let key of ['metaData', 'internalData']) {
|
||||
if (result.value[key]) {
|
||||
if (typeof result.value[key] === 'object') {
|
||||
try {
|
||||
result.value[key] = JSON.stringify(result.value[key]);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: `${key} value must be serializable to JSON`,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let value = JSON.parse(result.value[key]);
|
||||
if (!value || typeof value !== 'object') {
|
||||
throw new Error('Not an object');
|
||||
}
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: `${key} value must be valid JSON object string`,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'metaData value must be valid JSON object string',
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -842,6 +864,7 @@ module.exports = (db, server, userHandler) => {
|
|||
* @apiSuccess {String} keyInfo.address E-mail address listed in public key
|
||||
* @apiSuccess {String} keyInfo.fingerprint Fingerprint of the public key
|
||||
* @apiSuccess {Object} metaData Custom metadata object set for this user
|
||||
* @apiSuccess {Object} internalData Custom interna metadata object set for this user. Not available for user-role tokens
|
||||
* @apiSuccess {String[]} targets List of forwarding targets
|
||||
* @apiSuccess {Number} spamLevel Relative scale for detecting spam. 0 means that everything is spam, 100 means that nothing is spam
|
||||
* @apiSuccess {Object} limits Account limits and usage
|
||||
|
@ -1088,6 +1111,7 @@ module.exports = (db, server, userHandler) => {
|
|||
keyInfo,
|
||||
|
||||
metaData: formatMetaData(userData.metaData),
|
||||
internalData: formatMetaData(userData.internalData),
|
||||
|
||||
targets: [].concat(userData.targets || []).map(targetData => targetData.value),
|
||||
|
||||
|
@ -1183,6 +1207,7 @@ module.exports = (db, server, userHandler) => {
|
|||
* @apiParam {Boolean} [encryptForwarded] If <code>true</code> then forwarded messages are encrypted
|
||||
* @apiParam {String} [pubKey] Public PGP key for the User that is used for encryption. Use empty string to remove the key
|
||||
* @apiParam {Object|String} [metaData] Optional metadata, must be an object or JSON formatted string of an object
|
||||
* @apiParam {Object|String} [internalData] Optional internal metadata, must be an object or JSON formatted string of an object. Not available for user-role tokens
|
||||
* @apiParam {String} [language] Language code for the User
|
||||
* @apiParam {String[]} [targets] An array of forwarding targets. The value could either be an email address or a relay url to next MX server ("smtp://mx2.zone.eu:25") or an URL where mail contents are POSTed to
|
||||
* @apiParam {Number} [spamLevel] Relative scale for detecting spam. 0 means that everything is spam, 100 means that nothing is spam
|
||||
|
@ -1266,6 +1291,14 @@ module.exports = (db, server, userHandler) => {
|
|||
Joi.object()
|
||||
),
|
||||
|
||||
internalData: Joi.alternatives().try(
|
||||
Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
.max(1024 * 1024),
|
||||
Joi.object()
|
||||
),
|
||||
|
||||
pubKey: Joi.string()
|
||||
.empty('')
|
||||
.trim()
|
||||
|
@ -1417,29 +1450,31 @@ module.exports = (db, server, userHandler) => {
|
|||
return next();
|
||||
}
|
||||
|
||||
if (result.value.metaData) {
|
||||
if (typeof result.value.metaData === 'object') {
|
||||
try {
|
||||
result.value.metaData = JSON.stringify(result.value.metaData);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'metaData value must be serializable to JSON',
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let value = JSON.parse(result.value.metaData);
|
||||
if (!value || typeof value !== 'object') {
|
||||
throw new Error('Not an object');
|
||||
for (let key of ['metaData', 'internalData']) {
|
||||
if (result.value[key]) {
|
||||
if (typeof result.value[key] === 'object') {
|
||||
try {
|
||||
result.value[key] = JSON.stringify(result.value[key]);
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: `${key} value must be serializable to JSON`,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let value = JSON.parse(result.value[key]);
|
||||
if (!value || typeof value !== 'object') {
|
||||
throw new Error('Not an object');
|
||||
}
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: `${key} value must be valid JSON object string`,
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
} catch (err) {
|
||||
res.json({
|
||||
error: 'metaData value must be valid JSON object string',
|
||||
code: 'InputValidationError'
|
||||
});
|
||||
return next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
"author": "Andris Reinman",
|
||||
"license": "EUPL-1.1+",
|
||||
"devDependencies": {
|
||||
"ajv": "6.12.4",
|
||||
"ajv": "6.12.5",
|
||||
"apidoc": "0.25.0",
|
||||
"chai": "4.2.0",
|
||||
"docsify-cli": "4.4.1",
|
||||
"eslint": "7.8.1",
|
||||
"eslint": "7.9.0",
|
||||
"eslint-config-nodemailer": "1.2.0",
|
||||
"eslint-config-prettier": "6.11.0",
|
||||
"grunt": "1.3.0",
|
||||
|
@ -57,7 +57,7 @@
|
|||
"mailsplit": "5.0.0",
|
||||
"mobileconfig": "2.3.1",
|
||||
"mongo-cursor-pagination": "7.3.1",
|
||||
"mongodb": "3.6.1",
|
||||
"mongodb": "3.6.2",
|
||||
"mongodb-extended-json": "1.11.0",
|
||||
"node-forge": "0.10.0",
|
||||
"nodemailer": "6.4.11",
|
||||
|
@ -76,7 +76,7 @@
|
|||
"unixcrypt": "1.0.11",
|
||||
"uuid": "8.3.0",
|
||||
"wild-config": "1.5.1",
|
||||
"yargs": "16.0.0"
|
||||
"yargs": "16.0.3"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
Loading…
Reference in a new issue