mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-09-12 16:15:31 +08:00
started with metaData for addresses
This commit is contained in:
parent
89dad94ae3
commit
f2f14ca8fc
4 changed files with 231 additions and 33 deletions
|
@ -243,13 +243,13 @@
|
||||||
|
|
||||||
"user": {
|
"user": {
|
||||||
"addresslisting": {
|
"addresslisting": {
|
||||||
"read:own": ["*"]
|
"read:own": ["*", "!internalData"]
|
||||||
},
|
},
|
||||||
|
|
||||||
"addresses": {
|
"addresses": {
|
||||||
"create:own": ["*"],
|
"create:own": ["*", "!internalData"],
|
||||||
"read:own": ["*"],
|
"read:own": ["*", "!internalData"],
|
||||||
"update:own": ["*"],
|
"update:own": ["*", "!internalData"],
|
||||||
"delete:own": ["*"]
|
"delete:own": ["*"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
* @apiParam {String} [query] Partial match of an address
|
* @apiParam {String} [query] Partial match of an address
|
||||||
* @apiParam {String} [tags] Comma separated list of tags. The Address must have at least one to be set
|
* @apiParam {String} [tags] Comma separated list of tags. The Address must have at least one to be set
|
||||||
* @apiParam {String} [requiredTags] Comma separated list of tags. The Address must have all listed tags to be set
|
* @apiParam {String} [requiredTags] Comma separated list of tags. The Address 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} [limit=20] How many records to return
|
||||||
* @apiParam {Number} [page=1] Current page number. Informational only, page numbers start from 1
|
* @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
|
* @apiParam {Number} [next] Cursor value for next page, retrieved from <code>nextCursor</code> response value
|
||||||
|
@ -86,6 +88,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
query: Joi.string().trim().empty('').max(255),
|
query: Joi.string().trim().empty('').max(255),
|
||||||
tags: Joi.string().trim().empty('').max(1024),
|
tags: Joi.string().trim().empty('').max(1024),
|
||||||
requiredTags: 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),
|
limit: Joi.number().default(20).min(1).max(250),
|
||||||
next: nextPageCursorSchema,
|
next: nextPageCursorSchema,
|
||||||
previous: previousPageCursorSchema,
|
previous: previousPageCursorSchema,
|
||||||
|
@ -202,6 +206,14 @@ module.exports = (db, server, userHandler) => {
|
||||||
sortAscending: true
|
sortAscending: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (result.value.metaData) {
|
||||||
|
opts.fields.projection.metaData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.value.internalData) {
|
||||||
|
opts.fields.projection.internalData = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (pageNext) {
|
if (pageNext) {
|
||||||
opts.next = pageNext;
|
opts.next = pageNext;
|
||||||
} else if ((!page || page > 1) && pagePrevious) {
|
} else if ((!page || page > 1) && pagePrevious) {
|
||||||
|
@ -230,16 +242,28 @@ module.exports = (db, server, userHandler) => {
|
||||||
page,
|
page,
|
||||||
previousCursor: listing.hasPrevious ? listing.previous : false,
|
previousCursor: listing.hasPrevious ? listing.previous : false,
|
||||||
nextCursor: listing.hasNext ? listing.next : false,
|
nextCursor: listing.hasNext ? listing.next : false,
|
||||||
results: (listing.results || []).map(addressData => ({
|
results: (listing.results || []).map(addressData => {
|
||||||
id: addressData._id.toString(),
|
let values = {
|
||||||
name: addressData.name || false,
|
id: addressData._id.toString(),
|
||||||
address: addressData.address,
|
name: addressData.name || false,
|
||||||
user: addressData.user,
|
address: addressData.address,
|
||||||
forwarded: !!addressData.targets,
|
user: addressData.user,
|
||||||
forwardedDisabled: !!(addressData.targets && addressData.forwardedDisabled),
|
forwarded: !!addressData.targets,
|
||||||
targets: addressData.targets && addressData.targets.map(t => t.value),
|
forwardedDisabled: !!(addressData.targets && addressData.forwardedDisabled),
|
||||||
tags: addressData.tags || []
|
targets: addressData.targets && addressData.targets.map(t => t.value),
|
||||||
}))
|
tags: addressData.tags || []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (addressData.metaData) {
|
||||||
|
values.metaData = formatMetaData(addressData.metaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressData.internalData) {
|
||||||
|
values.internalData = formatMetaData(addressData.internalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return permission.filter(values);
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
res.json(response);
|
res.json(response);
|
||||||
|
@ -268,6 +292,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
* @apiParam {String[]} [tags] A list of tags associated with this address
|
* @apiParam {String[]} [tags] A list of tags associated with this address
|
||||||
* @apiParam {Boolean} [main=false] Indicates if this is the default address for the User
|
* @apiParam {Boolean} [main=false] Indicates if this is the default address for the User
|
||||||
* @apiParam {Boolean} [allowWildcard=false] If <code>true</code> then address value can be in the form of <code>\*@example.com</code>, <code>\*suffix@example.com</code> and <code>username@\*</code>, otherwise using \* is not allowed. Static suffix can be up to 32 characters long.
|
* @apiParam {Boolean} [allowWildcard=false] If <code>true</code> then address value can be in the form of <code>\*@example.com</code>, <code>\*suffix@example.com</code> and <code>username@\*</code>, otherwise using \* is not allowed. Static suffix can be up to 32 characters long.
|
||||||
|
* @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
|
||||||
*
|
*
|
||||||
* @apiSuccess {Boolean} success Indicates successful response
|
* @apiSuccess {Boolean} success Indicates successful response
|
||||||
* @apiSuccess {String} id ID of the Address
|
* @apiSuccess {String} id ID of the Address
|
||||||
|
@ -306,6 +332,23 @@ module.exports = (db, server, userHandler) => {
|
||||||
main: booleanSchema,
|
main: booleanSchema,
|
||||||
allowWildcard: booleanSchema,
|
allowWildcard: booleanSchema,
|
||||||
tags: Joi.array().items(Joi.string().trim().max(128)),
|
tags: Joi.array().items(Joi.string().trim().max(128)),
|
||||||
|
|
||||||
|
metaData: Joi.alternatives().try(
|
||||||
|
Joi.string()
|
||||||
|
.empty('')
|
||||||
|
.trim()
|
||||||
|
.max(1024 * 1024),
|
||||||
|
Joi.object()
|
||||||
|
),
|
||||||
|
|
||||||
|
internalData: Joi.alternatives().try(
|
||||||
|
Joi.string()
|
||||||
|
.empty('')
|
||||||
|
.trim()
|
||||||
|
.max(1024 * 1024),
|
||||||
|
Joi.object()
|
||||||
|
),
|
||||||
|
|
||||||
sess: sessSchema,
|
sess: sessSchema,
|
||||||
ip: sessIPSchema
|
ip: sessIPSchema
|
||||||
});
|
});
|
||||||
|
@ -442,6 +485,35 @@ module.exports = (db, server, userHandler) => {
|
||||||
result.value.tagsview = tags.map(tag => tag.toLowerCase());
|
result.value.tagsview = tags.map(tag => tag.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let userData;
|
let userData;
|
||||||
try {
|
try {
|
||||||
userData = await db.users.collection('users').findOne(
|
userData = await db.users.collection('users').findOne(
|
||||||
|
@ -504,6 +576,14 @@ module.exports = (db, server, userHandler) => {
|
||||||
addressData.tagsview = result.value.tags;
|
addressData.tagsview = result.value.tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.value.metaData) {
|
||||||
|
addressData.metaData = result.value.metaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.value.internalData) {
|
||||||
|
addressData.internalData = result.value.internalData;
|
||||||
|
}
|
||||||
|
|
||||||
let r;
|
let r;
|
||||||
// insert alias address to email address registry
|
// insert alias address to email address registry
|
||||||
try {
|
try {
|
||||||
|
@ -555,6 +635,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @apiParam {String} user ID of the User
|
* @apiParam {String} user ID of the User
|
||||||
|
* @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.
|
||||||
*
|
*
|
||||||
* @apiSuccess {Boolean} success Indicates successful response
|
* @apiSuccess {Boolean} success Indicates successful response
|
||||||
* @apiSuccess {Object[]} results Address listing
|
* @apiSuccess {Object[]} results Address listing
|
||||||
|
@ -601,6 +683,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
|
|
||||||
const schema = Joi.object().keys({
|
const schema = Joi.object().keys({
|
||||||
user: Joi.string().hex().lowercase().length(24).required(),
|
user: Joi.string().hex().lowercase().length(24).required(),
|
||||||
|
metaData: booleanSchema,
|
||||||
|
internalData: booleanSchema,
|
||||||
sess: sessSchema,
|
sess: sessSchema,
|
||||||
ip: sessIPSchema
|
ip: sessIPSchema
|
||||||
});
|
});
|
||||||
|
@ -623,12 +707,16 @@ module.exports = (db, server, userHandler) => {
|
||||||
let user = new ObjectID(result.value.user);
|
let user = new ObjectID(result.value.user);
|
||||||
|
|
||||||
// permissions check
|
// permissions check
|
||||||
|
let permission;
|
||||||
if (req.user && req.user === result.value.user) {
|
if (req.user && req.user === result.value.user) {
|
||||||
req.validate(roles.can(req.role).readOwn('addresses'));
|
permission = roles.can(req.role).readOwn('addresses');
|
||||||
} else {
|
} else {
|
||||||
req.validate(roles.can(req.role).readAny('addresses'));
|
permission = roles.can(req.role).readAny('addresses');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// permissions check
|
||||||
|
req.validate(permission);
|
||||||
|
|
||||||
let userData;
|
let userData;
|
||||||
try {
|
try {
|
||||||
userData = await db.users.collection('users').findOne(
|
userData = await db.users.collection('users').findOne(
|
||||||
|
@ -685,14 +773,26 @@ module.exports = (db, server, userHandler) => {
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|
||||||
results: addresses.map(address => ({
|
results: addresses.map(addressData => {
|
||||||
id: address._id,
|
let values = {
|
||||||
name: address.name || false,
|
id: addressData._id.toString(),
|
||||||
address: address.address,
|
name: addressData.name || false,
|
||||||
main: address.address === userData.address,
|
address: addressData.address,
|
||||||
tags: address.tags || [],
|
main: addressData.address === userData.address,
|
||||||
created: address.created
|
tags: addressData.tags || [],
|
||||||
}))
|
created: addressData.created
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result.value.metaData && addressData.metaData) {
|
||||||
|
values.metaData = formatMetaData(addressData.metaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.value.internalData && addressData.internalData) {
|
||||||
|
values.internalData = formatMetaData(addressData.internalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return permission.filter(values);
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
|
@ -770,11 +870,13 @@ module.exports = (db, server, userHandler) => {
|
||||||
let user = new ObjectID(result.value.user);
|
let user = new ObjectID(result.value.user);
|
||||||
|
|
||||||
// permissions check
|
// permissions check
|
||||||
|
let permission;
|
||||||
if (req.user && req.user === result.value.user) {
|
if (req.user && req.user === result.value.user) {
|
||||||
req.validate(roles.can(req.role).readOwn('addresses'));
|
permission = roles.can(req.role).readOwn('addresses');
|
||||||
} else {
|
} else {
|
||||||
req.validate(roles.can(req.role).readAny('addresses'));
|
permission = roles.can(req.role).readAny('addresses');
|
||||||
}
|
}
|
||||||
|
req.validate(permission);
|
||||||
|
|
||||||
let address = new ObjectID(result.value.address);
|
let address = new ObjectID(result.value.address);
|
||||||
|
|
||||||
|
@ -829,14 +931,24 @@ module.exports = (db, server, userHandler) => {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
let value = {
|
||||||
success: true,
|
success: true,
|
||||||
id: addressData._id,
|
id: addressData._id.toString(),
|
||||||
name: addressData.name || false,
|
name: addressData.name || false,
|
||||||
address: addressData.address,
|
address: addressData.address,
|
||||||
main: addressData.address === userData.address,
|
main: addressData.address === userData.address,
|
||||||
created: addressData.created
|
created: addressData.created
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (addressData.metaData) {
|
||||||
|
value.metaData = formatMetaData(addressData.metaData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressData.internalData) {
|
||||||
|
value.internalData = formatMetaData(addressData.internalData);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(permission.filter(value));
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
})
|
})
|
||||||
|
@ -857,6 +969,8 @@ module.exports = (db, server, userHandler) => {
|
||||||
* @apiParam {String} [name] Identity name
|
* @apiParam {String} [name] Identity name
|
||||||
* @apiParam {String} [address] New address if you want to rename existing address. Only affects normal addresses, special addresses that include \* can not be changed
|
* @apiParam {String} [address] New address if you want to rename existing address. Only affects normal addresses, special addresses that include \* can not be changed
|
||||||
* @apiParam {Boolean} main Indicates if this is the default address for the User
|
* @apiParam {Boolean} main Indicates if this is the default address for the User
|
||||||
|
* @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[]} [tags] A list of tags associated with this address
|
* @apiParam {String[]} [tags] A list of tags associated with this address
|
||||||
*
|
*
|
||||||
|
@ -895,6 +1009,23 @@ module.exports = (db, server, userHandler) => {
|
||||||
address: Joi.string().email({ tlds: false }),
|
address: Joi.string().email({ tlds: false }),
|
||||||
main: booleanSchema,
|
main: booleanSchema,
|
||||||
tags: Joi.array().items(Joi.string().trim().max(128)),
|
tags: Joi.array().items(Joi.string().trim().max(128)),
|
||||||
|
|
||||||
|
metaData: Joi.alternatives().try(
|
||||||
|
Joi.string()
|
||||||
|
.empty('')
|
||||||
|
.trim()
|
||||||
|
.max(1024 * 1024),
|
||||||
|
Joi.object()
|
||||||
|
),
|
||||||
|
|
||||||
|
internalData: Joi.alternatives().try(
|
||||||
|
Joi.string()
|
||||||
|
.empty('')
|
||||||
|
.trim()
|
||||||
|
.max(1024 * 1024),
|
||||||
|
Joi.object()
|
||||||
|
),
|
||||||
|
|
||||||
sess: sessSchema,
|
sess: sessSchema,
|
||||||
ip: sessIPSchema
|
ip: sessIPSchema
|
||||||
});
|
});
|
||||||
|
@ -1044,6 +1175,36 @@ module.exports = (db, server, userHandler) => {
|
||||||
addressData.address = result.value.address;
|
addressData.address = result.value.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let key of ['metaData', 'internalData']) {
|
||||||
|
if (result.value[key]) {
|
||||||
|
if (typeof result.value[key] === 'object') {
|
||||||
|
try {
|
||||||
|
updates[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');
|
||||||
|
}
|
||||||
|
updates[key] = result.value[key];
|
||||||
|
} catch (err) {
|
||||||
|
res.json({
|
||||||
|
error: `${key} value must be valid JSON object string`,
|
||||||
|
code: 'InputValidationError'
|
||||||
|
});
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Object.keys(updates).length) {
|
if (Object.keys(updates).length) {
|
||||||
try {
|
try {
|
||||||
await db.users.collection('addresses').updateOne(
|
await db.users.collection('addresses').updateOne(
|
||||||
|
@ -2300,7 +2461,7 @@ module.exports = (db, server, userHandler) => {
|
||||||
if (addressData.user) {
|
if (addressData.user) {
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
id: addressData._id,
|
id: addressData._id.toString(),
|
||||||
address: addressData.address,
|
address: addressData.address,
|
||||||
user: addressData.user,
|
user: addressData.user,
|
||||||
tags: addressData.tags || [],
|
tags: addressData.tags || [],
|
||||||
|
@ -2328,7 +2489,7 @@ module.exports = (db, server, userHandler) => {
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
id: addressData._id,
|
id: addressData._id.toString(),
|
||||||
name: addressData.name || '',
|
name: addressData.name || '',
|
||||||
address: addressData.address,
|
address: addressData.address,
|
||||||
targets: addressData.targets && addressData.targets.map(t => t.value),
|
targets: addressData.targets && addressData.targets.map(t => t.value),
|
||||||
|
@ -2545,3 +2706,14 @@ module.exports = (db, server, userHandler) => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function formatMetaData(metaData) {
|
||||||
|
if (typeof metaData === 'string') {
|
||||||
|
try {
|
||||||
|
metaData = JSON.parse(metaData);
|
||||||
|
} catch (err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metaData || {};
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
"mailparser": "3.0.0",
|
"mailparser": "3.0.0",
|
||||||
"mocha": "8.1.3",
|
"mocha": "8.1.3",
|
||||||
"request": "2.88.2",
|
"request": "2.88.2",
|
||||||
"supertest": "4.0.2"
|
"supertest": "5.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@phc/pbkdf2": "1.1.14",
|
"@phc/pbkdf2": "1.1.14",
|
||||||
|
|
|
@ -191,7 +191,10 @@ describe('API tests', function () {
|
||||||
.post(`/users/${userId}/addresses`)
|
.post(`/users/${userId}/addresses`)
|
||||||
.send({
|
.send({
|
||||||
address: 'alias1@example.com',
|
address: 'alias1@example.com',
|
||||||
main: true
|
main: true,
|
||||||
|
metaData: {
|
||||||
|
tere: 123
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(response1.body.success).to.be.true;
|
expect(response1.body.success).to.be.true;
|
||||||
|
@ -214,8 +217,10 @@ describe('API tests', function () {
|
||||||
|
|
||||||
it('should GET /users/:user/addresses (updated listing)', async () => {
|
it('should GET /users/:user/addresses (updated listing)', async () => {
|
||||||
const response = await server.get(`/users/${userId}/addresses`).expect(200);
|
const response = await server.get(`/users/${userId}/addresses`).expect(200);
|
||||||
|
|
||||||
expect(response.body.success).to.be.true;
|
expect(response.body.success).to.be.true;
|
||||||
expect(response.body.results.length).to.equal(3);
|
expect(response.body.results.length).to.equal(3);
|
||||||
|
|
||||||
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
|
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
|
||||||
|
|
||||||
expect(response.body.results[0].address).to.equal('testuser@example.com');
|
expect(response.body.results[0].address).to.equal('testuser@example.com');
|
||||||
|
@ -223,7 +228,9 @@ describe('API tests', function () {
|
||||||
|
|
||||||
expect(response.body.results[1].address).to.equal('alias1@example.com');
|
expect(response.body.results[1].address).to.equal('alias1@example.com');
|
||||||
expect(response.body.results[1].main).to.be.true;
|
expect(response.body.results[1].main).to.be.true;
|
||||||
|
expect(response.body.results[1].metaData).to.not.exist;
|
||||||
|
|
||||||
|
// no metaData present
|
||||||
expect(response.body.results[2].address).to.equal('alias2@example.com');
|
expect(response.body.results[2].address).to.equal('alias2@example.com');
|
||||||
expect(response.body.results[2].main).to.be.false;
|
expect(response.body.results[2].main).to.be.false;
|
||||||
|
|
||||||
|
@ -235,6 +242,25 @@ describe('API tests', function () {
|
||||||
expect(response.body.success).to.be.true;
|
expect(response.body.success).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should GET /users/:user/addresses (with metaData)', async () => {
|
||||||
|
const response = await server.get(`/users/${userId}/addresses?metaData=true`).expect(200);
|
||||||
|
expect(response.body.success).to.be.true;
|
||||||
|
expect(response.body.results.length).to.equal(2);
|
||||||
|
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
|
||||||
|
|
||||||
|
expect(response.body.results[1].address).to.equal('alias1@example.com');
|
||||||
|
expect(response.body.results[1].main).to.be.true;
|
||||||
|
expect(response.body.results[1].metaData.tere).to.equal(123);
|
||||||
|
|
||||||
|
address = response.body.results[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should GET /users/:user/address/:address', async () => {
|
||||||
|
const response = await server.get(`/users/${userId}/addresses/${address.id}`).expect(200);
|
||||||
|
expect(response.body.success).to.be.true;
|
||||||
|
expect(response.body.metaData.tere).to.equal(123);
|
||||||
|
});
|
||||||
|
|
||||||
it('should GET /users/:user/addresses (after DELETE)', async () => {
|
it('should GET /users/:user/addresses (after DELETE)', async () => {
|
||||||
const response = await server.get(`/users/${userId}/addresses`).expect(200);
|
const response = await server.get(`/users/${userId}/addresses`).expect(200);
|
||||||
expect(response.body.success).to.be.true;
|
expect(response.body.success).to.be.true;
|
||||||
|
|
Loading…
Add table
Reference in a new issue