feat(model): ✨ add user
model
This commit is contained in:
parent
3f37648dfd
commit
f7f3b48ad1
184
src/models/src/user.ts
Normal file
184
src/models/src/user.ts
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
import { Login, MailAddress, Posix, ToJson } from '@/types.ts'
|
||||||
|
import { regex, toLogin } from '@/utils.ts'
|
||||||
|
import { Credential } from '@models/credential.ts'
|
||||||
|
import { Group } from '@models/group.ts'
|
||||||
|
import { Ressource } from '@models/ressource.ts'
|
||||||
|
import { Ref } from '@/src/models/utils/ref.ts'
|
||||||
|
|
||||||
|
export class User extends Ressource {
|
||||||
|
static fromJSON(
|
||||||
|
json: ToJson<User>,
|
||||||
|
): User {
|
||||||
|
if (json.type !== 'user') {
|
||||||
|
throw new TypeError(`type is "${json.type}" but "user" is required`)
|
||||||
|
}
|
||||||
|
if (typeof json.lastname !== 'string') {
|
||||||
|
throw new TypeError(
|
||||||
|
`lastname type is "${typeof json.lastname}" but "string" is required`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (typeof json.firstname !== 'string') {
|
||||||
|
throw new TypeError(
|
||||||
|
`firstname type is "${typeof json.firstname}" but "string" is required`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (typeof json.login !== 'string' && /(\w|_)+\.(\w|_)+/.test(json.login)) {
|
||||||
|
throw new TypeError(
|
||||||
|
`login is "${json.login}" but "\${string}.\${string}" is required`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (typeof json.mail !== 'string' && /\S+@\S+\.\S+/.test(json.mail)) {
|
||||||
|
throw new TypeError(
|
||||||
|
`mail is "${json.mail}" but "\${string}@\${string}.\${string}" is required`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const credentials = Object.freeze(
|
||||||
|
json.credentials.map((credential) =>
|
||||||
|
Ref.fromString<Credential>(credential)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
const groups = Object.freeze(
|
||||||
|
json.groups.map((group) => Ref.fromString<Group>(group)),
|
||||||
|
)
|
||||||
|
const avatar = new URL(json.avatar)
|
||||||
|
const posix = json.posix ?? undefined
|
||||||
|
|
||||||
|
return new User({ ...json, posix, credentials, groups, avatar })
|
||||||
|
}
|
||||||
|
|
||||||
|
static create({
|
||||||
|
name,
|
||||||
|
...props
|
||||||
|
}: Pick<
|
||||||
|
User,
|
||||||
|
| 'name'
|
||||||
|
| 'lastname'
|
||||||
|
| 'firstname'
|
||||||
|
| 'mail'
|
||||||
|
| 'groups'
|
||||||
|
| 'posix'
|
||||||
|
| 'avatar'
|
||||||
|
| 'credentials'
|
||||||
|
>): User {
|
||||||
|
const { uuid, createdAt, updatedAt } = super.create({ name })
|
||||||
|
return new User({ name, uuid, createdAt, updatedAt, ...props })
|
||||||
|
}
|
||||||
|
|
||||||
|
#lastname: string
|
||||||
|
#firstname: string
|
||||||
|
#login: Login
|
||||||
|
#mail: MailAddress
|
||||||
|
#groups: readonly Ref<Group>[]
|
||||||
|
#posix?: Posix
|
||||||
|
#avatar: URL
|
||||||
|
#credentials: readonly Ref<Credential>[]
|
||||||
|
|
||||||
|
private constructor({
|
||||||
|
lastname,
|
||||||
|
firstname,
|
||||||
|
mail,
|
||||||
|
groups,
|
||||||
|
posix,
|
||||||
|
avatar,
|
||||||
|
credentials,
|
||||||
|
...ressource
|
||||||
|
}: Pick<
|
||||||
|
User,
|
||||||
|
| 'uuid'
|
||||||
|
| 'createdAt'
|
||||||
|
| 'updatedAt'
|
||||||
|
| 'name'
|
||||||
|
| 'lastname'
|
||||||
|
| 'firstname'
|
||||||
|
| 'mail'
|
||||||
|
| 'groups'
|
||||||
|
| 'posix'
|
||||||
|
| 'avatar'
|
||||||
|
| 'credentials'
|
||||||
|
>) {
|
||||||
|
super(ressource)
|
||||||
|
this.#lastname = lastname
|
||||||
|
this.#firstname = firstname
|
||||||
|
if (!regex.mailAddress) {
|
||||||
|
throw new TypeError(`"${mail}" is not a valid mail address`)
|
||||||
|
}
|
||||||
|
this.#mail = mail
|
||||||
|
this.#groups = Object.freeze(groups)
|
||||||
|
if (posix) {
|
||||||
|
if (!Number.isInteger(posix?.id) && posix.id < 0) {
|
||||||
|
throw new TypeError(
|
||||||
|
`posix.id must be a positive integer, received ${posix.id}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.#posix = posix
|
||||||
|
this.#avatar = avatar
|
||||||
|
this.#login = toLogin({ firstname, lastname })
|
||||||
|
this.#credentials = Object.freeze(credentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
get type(): 'user' {
|
||||||
|
return 'user'
|
||||||
|
}
|
||||||
|
get firstname() {
|
||||||
|
return this.#firstname
|
||||||
|
}
|
||||||
|
get lastname() {
|
||||||
|
return this.#lastname
|
||||||
|
}
|
||||||
|
get login() {
|
||||||
|
return this.#login
|
||||||
|
}
|
||||||
|
get mail() {
|
||||||
|
return this.#mail
|
||||||
|
}
|
||||||
|
get groups() {
|
||||||
|
return this.#groups
|
||||||
|
}
|
||||||
|
get posix() {
|
||||||
|
return this.#posix
|
||||||
|
}
|
||||||
|
get avatar() {
|
||||||
|
return this.#avatar
|
||||||
|
}
|
||||||
|
get credentials() {
|
||||||
|
return this.#credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
update(props: Partial<Omit<User, 'type' | 'uuid' | 'createdAt'>>): User {
|
||||||
|
const { updatedAt } = super.update(props)
|
||||||
|
const user = new User({ ...this, ...props, updatedAt })
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
...super.toJSON(),
|
||||||
|
lastname: this.lastname,
|
||||||
|
firstname: this.firstname,
|
||||||
|
login: this.login,
|
||||||
|
mail: this.mail,
|
||||||
|
groups: this.groups.map((group) => group.toJSON()),
|
||||||
|
posix: this.posix ?? null,
|
||||||
|
avatar: this.avatar.toJSON(),
|
||||||
|
credentials: this.credentials.map((credential) => credential.toJSON()),
|
||||||
|
} as const
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `User (${JSON.stringify(this)})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface User extends Ressource {
|
||||||
|
type: 'user'
|
||||||
|
lastname: string
|
||||||
|
firstname: string
|
||||||
|
login: Login
|
||||||
|
mail: MailAddress
|
||||||
|
groups: readonly Ref<Group>[]
|
||||||
|
posix: Posix | undefined
|
||||||
|
avatar: URL
|
||||||
|
credentials: readonly Ref<Credential>[]
|
||||||
|
}
|
Loading…
Reference in a new issue