Skip to content

Commit

Permalink
Feature/change plan service (#481)
Browse files Browse the repository at this point in the history
* Add available plan service in configuration `availablePlans`
* Create and register service `user-request-change-plan`
* Upgrade after npm audit fix
  • Loading branch information
danieleguido authored Jan 4, 2025
1 parent cace5cb commit 54ac3d7
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 9 deletions.
20 changes: 11 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface Configuration extends Config {
celeryClient?: CeleryClient
cacheManager: Cache
openApiValidatorMiddlewares: any[]
availablePlans: string[]
}

const configurationValidator = getValidator(configurationSchema, ajv)
Expand Down
69 changes: 69 additions & 0 deletions src/models/user-change-plan-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { Sequelize } from 'sequelize'
import { DataTypes, Model, InferAttributes, InferCreationAttributes, CreationOptional } from 'sequelize'
import Group from './groups.model'

export default class UserChangePlanRequest extends Model<
InferAttributes<UserChangePlanRequest>,
InferCreationAttributes<UserChangePlanRequest>
> {
declare id: CreationOptional<string>
declare dateCreated: Date
declare dateLastModified: Date
declare status: string
declare notes: string
declare changelog: object
declare planId: number
declare userId: number

static initModel(client: Sequelize) {
const groupModel = Group.initModel(client)
const model = UserChangePlanRequest.init(
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
unique: true,
},
dateCreated: {
type: DataTypes.DATE,
allowNull: false,
field: 'date_created',
},
dateLastModified: {
type: DataTypes.DATE,
allowNull: false,
field: 'date_last_modified',
},
status: {
type: DataTypes.STRING,
allowNull: false,
},
changelog: {
type: DataTypes.JSON,
allowNull: false,
},
notes: {
type: DataTypes.STRING,
allowNull: true,
},
planId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'plan_id',
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'user_id',
},
},
{
sequelize: client,
tableName: 'impresso_userchangeplanrequest',
}
)
model.hasOne(groupModel, { foreignKey: 'id', sourceKey: 'planId', as: 'plan' })
return model
}
}
7 changes: 7 additions & 0 deletions src/schema/common/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
"type": "boolean",
"description": "If `true`, the app serves a public API"
},
"availablePlans": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of available plans"
},
"allowedCorsOrigins": {
"type": "array",
"items": {
Expand Down
1 change: 1 addition & 0 deletions src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const internalApiServices = [
'password-reset',
'change-password',
'terms-of-use',
'user-change-plan-request',
'user-requests',
'user-requests-reviews',
'newspapers',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { Sequelize } from 'sequelize'
import initDebug from 'debug'
import type { ImpressoApplication } from '../../types'
import User from '../../models/users.model'
import { NotFound } from '@feathersjs/errors'
import UserChangePlanRequest from '../../models/user-change-plan-request'

const debug = initDebug('impresso:services/change-plan')

export interface ServiceOptions {
app: ImpressoApplication
name: string
}

export class Service {
app: ImpressoApplication
name: string
sequelizeClient?: Sequelize
constructor({ app, name }: ServiceOptions) {
this.app = app
this.name = name
this.sequelizeClient = app.get('sequelizeClient')
debug('Service initialized.')
}

async find(params: { user: { id: number } }) {
if (!this.sequelizeClient) {
throw new Error('Sequelize client not available')
}
debug('[find] plan request for user.pk', params.user.id, params.user)
const userChangePlanRequestModel = UserChangePlanRequest.initModel(this.sequelizeClient)
const userChangePlanRequest = await userChangePlanRequestModel.findOne({
where: {
userId: params.user.id,
},
include: ['plan'],
})
if (!userChangePlanRequest) {
throw new NotFound()
}
return userChangePlanRequest?.get()
}

async create(data: any, params: { user: { id: number } }) {
const client = this.app.get('celeryClient')
if (!client) {
throw new Error('Celery client not available')
}

debug('[create] plan request for user.pk', params.user.id, 'plan:', data.plan, params.user)

return client
.run({
task: 'impresso.tasks.email_plan_change',
// email_plan_change(self, user_id: int, plan: str = None)
args: [params.user.id, data.plan],
})
.catch((error: Error) => {
debug('[create] error:', error)
throw error
})
.then(() => ({
response: 'ok',
}))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Service } from './user-change-plan-request.class'
import { ImpressoApplication } from '../../types'
import { HookContext, ServiceOptions } from '@feathersjs/feathers'
import { authenticateAround } from '../../hooks/authenticate'
import { BadRequest } from '@feathersjs/errors'

export default (app: ImpressoApplication) => {
app.use(
'/user-change-plan-request',
new Service({
app,
name: 'user-change-plan-request',
}),
{
events: [],
} as ServiceOptions
)
const service = app.service('user-change-plan-request')
service.hooks({
around: {
all: [authenticateAround()],
},
before: {
create: [
(context: HookContext) => {
const { plan } = context.data
if (!plan || typeof plan !== 'string') {
throw new BadRequest('`plan` param is required')
}
const availablePlans = context.app.get('availablePlans')

if (!availablePlans.includes(plan)) {
throw new BadRequest('Invalid plan, should be one of:', availablePlans)
}
return context
},
],
},
})
}

0 comments on commit 54ac3d7

Please sign in to comment.