Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions app/controllers/api/v1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
* SPDX-License-Identifier: BUSL-1.1
*/

const aliases = require('./aliases');
const aliasAuth = require('./alias-auth');
const aliases = require('./aliases');
const apple = require('./apple');
const calendars = require('./calendars');
const calendarEvents = require('./calendar-events');
const calendars = require('./calendars');
const contacts = require('./contacts');
const domains = require('./domains');
const emails = require('./emails');
const enforcePaidPlan = require('./enforce-paid-plan');
const folders = require('./folders');
const inquiries = require('./inquiries');
Expand All @@ -24,18 +25,18 @@ const selfTest = require('./self-test');
const settings = require('./settings');
const stripe = require('./stripe');
const test = require('./test');
const users = require('./users');
const upgrade = require('./upgrade');
const emails = require('./emails');
const users = require('./users');

module.exports = {
aliases,
aliasAuth,
aliases,
apple,
calendars,
calendarEvents,
calendars,
contacts,
domains,
emails,
enforcePaidPlan,
folders,
inquiries,
Expand All @@ -50,7 +51,6 @@ module.exports = {
settings,
stripe,
test,
users,
upgrade,
emails
users
};
119 changes: 114 additions & 5 deletions app/controllers/api/v1/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,87 @@
*/

const Boom = require('@hapi/boom');
const mongoose = require('mongoose');
const isSANB = require('is-string-and-not-blank');
const _ = require('#helpers/lodash');

const sendVerificationEmail = require('#helpers/send-verification-email');
const config = require('#config');
const { Users, Aliases } = require('#models');

const ALIAS_SETTINGS_FIELDS = [
'appearance_theme',
'appearance_layout_mode',
'compose_plain_default',
'mail_messages_per_page',
'mail_archive_folder',
'search_body_indexing',
'search_saved_searches',
'prefetch_enabled',
'prefetch_folders',
'prefetch_mode',
'shortcuts',
'label_settings',
'security_remember_passphrase',
'aliases_defaults'
];

function serializeAliasSettings(alias) {
const settings = _.pick(alias, ALIAS_SETTINGS_FIELDS);
if (!settings.shortcuts) settings.shortcuts = {};
if (!settings.label_settings) settings.label_settings = {};
if (!settings.aliases_defaults) settings.aliases_defaults = {};
return settings;
}

function getAliasContext(ctx) {
const user = ctx.state?.user;
if (!user || !user.alias_id)
throw Boom.unauthorized(ctx.translateError('SETTINGS_ALIAS_AUTH_REQUIRED'));

if (!mongoose.isValidObjectId(user.alias_id))
throw Boom.unauthorized(ctx.translateError('SETTINGS_INVALID_ALIAS_ID'));

return {
aliasId: user.alias_id,
domainName: user.domain_name,
aliasEmail: user.username
};
}

async function updateAliasSettingsForContext(ctx, body) {
const aliasContext = getAliasContext(ctx);

if (body && typeof body !== 'object')
throw Boom.badRequest(ctx.translateError('INVALID_REQUEST_BODY'));

const alias = await Aliases.findById(aliasContext.aliasId)
.populate('domain', 'id name plan max_quota_per_alias')
.exec();
if (!alias)
throw Boom.unauthorized(ctx.translateError('SETTINGS_INVALID_ALIAS_ID'));

const updates = _.pick(body, ALIAS_SETTINGS_FIELDS);
if (
Object.prototype.hasOwnProperty.call(updates, 'mail_archive_folder') &&
updates.mail_archive_folder !== null &&
updates.mail_archive_folder !== undefined &&
typeof updates.mail_archive_folder !== 'string'
) {
throw Boom.badRequest(
ctx.translateError('SETTINGS_ARCHIVE_FOLDER_INVALID')
);
}

for (const [key, value] of Object.entries(updates)) {
if (value === undefined) continue;
alias.set(key, value);
}

await alias.save();
return alias;
}

async function create(ctx) {
const { body } = ctx.request;

Expand Down Expand Up @@ -50,12 +124,11 @@ async function retrieve(ctx) {

if (!alias) throw Boom.notFound(ctx.translateError('ALIAS_DOES_NOT_EXIST'));

// Get storage information
const storageUsed = alias.storage_used || 0;
const maxQuotaPerAlias =
alias.domain.max_quota_per_alias || config.maxQuotaPerAlias;
(alias.domain && alias.domain.max_quota_per_alias) ||
config.maxQuotaPerAlias;

// Return alias account information
ctx.body = {
id: alias.id,
object: 'alias',
Expand All @@ -70,7 +143,8 @@ async function retrieve(ctx) {
public_key: alias.public_key,
locale: alias.locale || ctx.locale,
created_at: alias.created_at,
updated_at: alias.updated_at
updated_at: alias.updated_at,
...serializeAliasSettings(alias)
};
} else {
// User authentication - return user account information
Expand All @@ -81,6 +155,36 @@ async function retrieve(ctx) {
async function update(ctx) {
const { body } = ctx.request;

if (ctx.state?.session?.db) {
const alias = await updateAliasSettingsForContext(ctx, body);

if (!alias) throw Boom.notFound(ctx.translateError('ALIAS_DOES_NOT_EXIST'));

const storageUsed = alias.storage_used || 0;
const maxQuotaPerAlias =
(alias.domain && alias.domain.max_quota_per_alias) ||
config.maxQuotaPerAlias;

ctx.body = {
id: alias.id,
object: 'alias',
name: alias.name,
email: `${alias.name}@${alias.domain.name}`,
domain_id: alias.domain.id,
domain_name: alias.domain.name,
storage_used: storageUsed,
storage_quota: maxQuotaPerAlias,
has_imap: alias.has_imap,
has_pgp: alias.has_pgp,
public_key: alias.public_key,
locale: alias.locale || ctx.locale,
created_at: alias.created_at,
updated_at: alias.updated_at,
...serializeAliasSettings(alias)
};
return;
}

if (_.isString(body.email)) ctx.state.user.email = body.email;

if (_.isString(body[config.passport.fields.givenName]))
Expand All @@ -97,4 +201,9 @@ async function update(ctx) {
ctx.body = ctx.state.user.toObject();
}

module.exports = { create, retrieve, update };
module.exports = {
create,
retrieve,
update,
updateAliasSettingsForContext
};
Loading
Loading