templating api
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type HasNoArgsConstructor<T> = T extends { new (): any } ? true : false
|
||||
|
||||
type CleanConstructorParameters<T extends typeof BaseService> =
|
||||
HasNoArgsConstructor<T> extends true ? [] : ConstructorParameters<T>
|
||||
|
||||
export class BaseService {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
||||
constructor(...args: any[]) {}
|
||||
|
||||
static perform<T extends typeof BaseService>(
|
||||
this: T,
|
||||
...args: CleanConstructorParameters<T>
|
||||
): ReturnType<InstanceType<T>["perform"]> {
|
||||
const instance = new this(...args)
|
||||
return instance.perform()
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
perform(): any {
|
||||
throw new Error("Not Implemented")
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseService
|
||||
|
||||
// Type Testing - keeping until I have real tests implemented
|
||||
// class AsyncService extends BaseService {
|
||||
// private param1: number
|
||||
|
||||
// constructor(param1: number) {
|
||||
// super()
|
||||
// this.param1 = param1
|
||||
// }
|
||||
|
||||
// async perform(): Promise<string[]> {
|
||||
// return ["async-string1", "async-string2"]
|
||||
// }
|
||||
// }
|
||||
|
||||
// class NonAsyncService extends BaseService {
|
||||
// perform(): string {
|
||||
// return "non-async-string"
|
||||
// }
|
||||
// }
|
||||
|
||||
// const param1 = 77
|
||||
// AsyncService.perform(param1).then((result: string[]) => {
|
||||
// logger.log(result)
|
||||
// })
|
||||
|
||||
// const result = NonAsyncService.perform()
|
||||
// logger.log(result)
|
||||
@@ -0,0 +1 @@
|
||||
export * as Users from "./users"
|
||||
@@ -0,0 +1,53 @@
|
||||
import { CreationAttributes } from "@sequelize/core"
|
||||
import { isNil, random } from "lodash"
|
||||
|
||||
import { User } from "@/models"
|
||||
import BaseService from "@/services/base-service"
|
||||
|
||||
export type UserCreationAttributes = Partial<CreationAttributes<User>>
|
||||
|
||||
export class CreateService extends BaseService {
|
||||
constructor(private attributes: UserCreationAttributes) {
|
||||
super()
|
||||
}
|
||||
|
||||
async perform(): Promise<User> {
|
||||
const { email, auth0Subject, roles, ...optionalAttributes } = this.attributes
|
||||
|
||||
if (isNil(email)) {
|
||||
throw new Error("Email is required")
|
||||
}
|
||||
|
||||
if (isNil(auth0Subject)) {
|
||||
throw new Error("Auth0 Subject is required")
|
||||
}
|
||||
|
||||
const [emailLocalPart] = email.split("@")
|
||||
/**
|
||||
* Yep, if we don't have enough data, your name becomes your email split randomly.
|
||||
* This way we can at least have a first name and last name,
|
||||
* and the first and last name are likely to be distinct.
|
||||
*/
|
||||
const randomSplit = random(1, emailLocalPart.length - 2)
|
||||
const [firstNameFallback, lastNameFallback] = emailLocalPart.includes(".")
|
||||
? emailLocalPart.split(".")
|
||||
: [emailLocalPart.slice(0, randomSplit), emailLocalPart.slice(randomSplit)]
|
||||
const { firstName, lastName } = optionalAttributes
|
||||
const firstNameOrFallback = firstName || firstNameFallback
|
||||
const lastNameOrFallback = lastName || lastNameFallback
|
||||
|
||||
const user = await User.create({
|
||||
...optionalAttributes,
|
||||
email,
|
||||
auth0Subject: auth0Subject,
|
||||
firstName: firstNameOrFallback,
|
||||
lastName: lastNameOrFallback,
|
||||
displayName: `${firstNameOrFallback} ${lastNameOrFallback}`,
|
||||
roles: roles ?? [User.Roles.USER],
|
||||
})
|
||||
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
export default CreateService
|
||||
@@ -0,0 +1,14 @@
|
||||
import { User } from "@/models"
|
||||
import BaseService from "@/services/base-service"
|
||||
|
||||
export class DestroyService extends BaseService {
|
||||
constructor(private user: User) {
|
||||
super()
|
||||
}
|
||||
|
||||
async perform() {
|
||||
throw new Error("Not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
export default DestroyService
|
||||
@@ -0,0 +1,35 @@
|
||||
import { auth0Integration } from "@/integrations"
|
||||
import { User } from "@/models"
|
||||
import { Op } from "@sequelize/core"
|
||||
import BaseService from "@/services/base-service"
|
||||
|
||||
export class FindFromAuth0TokenService extends BaseService {
|
||||
constructor(private token: string) {
|
||||
super()
|
||||
}
|
||||
|
||||
async perform(): Promise<User> {
|
||||
const { auth0Subject, email } = await auth0Integration.getUserInfo(this.token)
|
||||
|
||||
const existingUser = await User.withScope(["asCurrentUser"]).findOne({
|
||||
where: { auth0Subject },
|
||||
})
|
||||
|
||||
if (existingUser) {
|
||||
return existingUser
|
||||
}
|
||||
|
||||
const firstTimeUser = await User.withScope(["asCurrentUser"]).findOne({
|
||||
where: { [Op.or]: [{ auth0Subject: email }, { email: email }] },
|
||||
})
|
||||
|
||||
if (firstTimeUser) {
|
||||
await firstTimeUser.update({ auth0Subject })
|
||||
return firstTimeUser
|
||||
}
|
||||
|
||||
throw new Error("No user found for this token.")
|
||||
}
|
||||
}
|
||||
|
||||
export default FindFromAuth0TokenService
|
||||
@@ -0,0 +1,6 @@
|
||||
export { CreateService } from "./create-service"
|
||||
export { UpdateService } from "./update-service"
|
||||
export { DestroyService } from "./destroy-service"
|
||||
|
||||
// Special Services
|
||||
export { FindFromAuth0TokenService } from "./find-from-auth0-token-service"
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Attributes } from "@sequelize/core"
|
||||
|
||||
import { User } from "@/models"
|
||||
import BaseService from "@/services/base-service"
|
||||
|
||||
export type UserUpdateAttributes = Partial<Attributes<User>>
|
||||
|
||||
export class UpdateService extends BaseService {
|
||||
constructor(
|
||||
private user: User,
|
||||
private attributes: UserUpdateAttributes
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
async perform(): Promise<User> {
|
||||
return this.user.update(this.attributes)
|
||||
}
|
||||
}
|
||||
|
||||
export default UpdateService
|
||||
Reference in New Issue
Block a user