Files
standardnotes-server/packages/auth/src/Infra/InversifyExpressUtils/Base/BaseSettingsController.ts
T

245 lines
7.2 KiB
TypeScript

import { ControllerContainerInterface, MapperInterface } from '@standardnotes/domain-core'
import { BaseHttpController, results } from 'inversify-express-utils'
import { ErrorTag } from '@standardnotes/responses'
import { Request, Response } from 'express'
import { Logger } from 'winston'
import { DeleteSetting } from '../../../Domain/UseCase/DeleteSetting/DeleteSetting'
import { GetSetting } from '../../../Domain/UseCase/GetSetting/GetSetting'
import { GetAllSettingsForUser } from '../../../Domain/UseCase/GetAllSettingsForUser/GetAllSettingsForUser'
import { SetSettingValue } from '../../../Domain/UseCase/SetSettingValue/SetSettingValue'
import { Setting } from '../../../Domain/Setting/Setting'
import { SubscriptionSetting } from '../../../Domain/Setting/SubscriptionSetting'
import { SubscriptionSettingHttpRepresentation } from '../../../Mapping/Http/SubscriptionSettingHttpRepresentation'
import { SettingHttpRepresentation } from '../../../Mapping/Http/SettingHttpRepresentation'
import { TriggerPostSettingUpdateActions } from '../../../Domain/UseCase/TriggerPostSettingUpdateActions/TriggerPostSettingUpdateActions'
import { ResponseLocals } from '../ResponseLocals'
export class BaseSettingsController extends BaseHttpController {
constructor(
protected doGetSettings: GetAllSettingsForUser,
protected doGetSetting: GetSetting,
protected setSettingValue: SetSettingValue,
protected triggerPostSettingUpdateActions: TriggerPostSettingUpdateActions,
protected doDeleteSetting: DeleteSetting,
protected settingHttMapper: MapperInterface<Setting, SettingHttpRepresentation>,
protected subscriptionSettingHttpMapper: MapperInterface<
SubscriptionSetting,
SubscriptionSettingHttpRepresentation
>,
protected logger: Logger,
private controllerContainer?: ControllerContainerInterface,
) {
super()
if (this.controllerContainer !== undefined) {
this.controllerContainer.register('auth.users.getSettings', this.getSettings.bind(this))
this.controllerContainer.register('auth.users.getSetting', this.getSetting.bind(this))
this.controllerContainer.register('auth.users.updateSetting', this.updateSetting.bind(this))
this.controllerContainer.register('auth.users.deleteSetting', this.deleteSetting.bind(this))
}
}
async getSettings(request: Request, response: Response): Promise<results.JsonResult> {
const locals = response.locals as ResponseLocals
if (request.params.userUuid !== locals.user.uuid) {
return this.json(
{
error: {
message: 'Operation not allowed.',
},
},
401,
)
}
const { userUuid } = request.params
const result = await this.doGetSettings.execute({ userUuid })
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
400,
)
}
const settingsAndSubscriptionSettings = result.getValue()
const settingsHttpRepresentation = settingsAndSubscriptionSettings.settings.map((settingAndValue) => ({
...this.settingHttMapper.toProjection(settingAndValue.setting),
value: settingAndValue.decryptedValue,
}))
const subscriptionSettingsHttpRepresentation = settingsAndSubscriptionSettings.subscriptionSettings.map(
(settingAndValue) => ({
...this.subscriptionSettingHttpMapper.toProjection(settingAndValue.setting),
value: settingAndValue.decryptedValue,
}),
)
const httpRepresentation = settingsHttpRepresentation.concat(subscriptionSettingsHttpRepresentation)
return this.json({
success: true,
settings: httpRepresentation,
})
}
async getSetting(request: Request, response: Response): Promise<results.JsonResult> {
const locals = response.locals as ResponseLocals
if (request.params.userUuid !== locals.user.uuid) {
return this.json(
{
error: {
message: 'Operation not allowed.',
},
},
401,
)
}
const { userUuid, settingName } = request.params
const resultOrError = await this.doGetSetting.execute({
allowSensitiveRetrieval: true,
userUuid,
decrypted: true,
settingName: settingName.toUpperCase(),
})
if (resultOrError.isFailed()) {
return this.json(
{
error: {
message: resultOrError.getError(),
},
},
400,
)
}
const settingAndValue = resultOrError.getValue()
if (settingAndValue.setting.props.sensitive) {
return this.json({
success: true,
})
}
const settingHttpReprepesentation = {
...this.settingHttMapper.toProjection(settingAndValue.setting),
value: settingAndValue.decryptedValue,
}
return this.json({
success: true,
setting: settingHttpReprepesentation,
})
}
async updateSetting(request: Request, response: Response): Promise<results.JsonResult | results.StatusCodeResult> {
const locals = response.locals as ResponseLocals
if (locals.readOnlyAccess) {
return this.json(
{
error: {
tag: ErrorTag.ReadOnlyAccess,
message: 'Session has read-only access.',
},
},
401,
)
}
if (request.params.userUuid !== locals.user.uuid) {
return this.json(
{
error: {
message: 'Operation not allowed.',
},
},
401,
)
}
const { name, value } = request.body
const result = await this.setSettingValue.execute({
settingName: name,
value,
userUuid: locals.user.uuid,
checkUserPermissions: true,
})
if (result.isFailed()) {
return this.json(
{
error: {
message: result.getError(),
},
},
400,
)
}
const setting = result.getValue()
const triggerResult = await this.triggerPostSettingUpdateActions.execute({
updatedSettingName: setting.props.name,
userUuid: locals.user.uuid,
userEmail: locals.user.email,
unencryptedValue: value,
})
if (triggerResult.isFailed()) {
this.logger.error(`Failed to trigger post setting update actions: ${triggerResult.getError()}`)
}
return this.json({
success: true,
setting: setting.props.sensitive ? undefined : this.settingHttMapper.toProjection(setting),
})
}
async deleteSetting(request: Request, response: Response): Promise<results.JsonResult> {
const locals = response.locals as ResponseLocals
if (locals.readOnlyAccess) {
return this.json(
{
error: {
tag: ErrorTag.ReadOnlyAccess,
message: 'Session has read-only access.',
},
},
401,
)
}
if (request.params.userUuid !== locals.user.uuid) {
return this.json(
{
error: {
message: 'Operation not allowed.',
},
},
401,
)
}
const { userUuid, settingName } = request.params
const result = await this.doDeleteSetting.execute({
userUuid,
settingName,
})
if (result.success) {
return this.json(result)
}
return this.json(result, 400)
}
}