mirror of
https://github.com/hcengineering/platform.git
synced 2025-03-24 00:31:50 +00:00
277 lines
8.7 KiB
TypeScript
277 lines
8.7 KiB
TypeScript
import contact, { getName } from '@hcengineering/contact'
|
|
import { Hierarchy, type Class, type Client, type Doc, type Ref } from '@hcengineering/core'
|
|
import { getMetadata } from '@hcengineering/platform'
|
|
import presentation, { getClient } from '@hcengineering/presentation'
|
|
import {
|
|
recruitId,
|
|
type Applicant,
|
|
type Candidate,
|
|
type Review,
|
|
type Vacancy,
|
|
type VacancyList
|
|
} from '@hcengineering/recruit'
|
|
import { getCurrentResolvedLocation, getPanelURI, type Location, type ResolvedLocation } from '@hcengineering/ui'
|
|
import view from '@hcengineering/view'
|
|
import { accessDeniedStore } from '@hcengineering/view-resources'
|
|
import { workbenchId } from '@hcengineering/workbench'
|
|
import recruit from './plugin'
|
|
|
|
type RecruitDocument = Vacancy | Applicant | Review
|
|
|
|
export async function objectLinkProvider (doc: RecruitDocument): Promise<string> {
|
|
const location = getCurrentResolvedLocation()
|
|
const frontUrl = getMetadata(presentation.metadata.FrontUrl) ?? window.location.origin
|
|
const url = `${frontUrl}/${workbenchId}/${location.path[1]}/${recruitId}/${await getSequenceId(doc)}`
|
|
return url
|
|
}
|
|
|
|
function isShortId (shortLink: string): boolean {
|
|
return /^\w+-\d+$/.test(shortLink)
|
|
}
|
|
|
|
export async function resolveLocation (loc: Location): Promise<ResolvedLocation | undefined> {
|
|
if (loc.path[2] !== recruitId) {
|
|
return undefined
|
|
}
|
|
|
|
const shortLink = loc.path[3]
|
|
|
|
// shortlink
|
|
if (isShortId(shortLink)) {
|
|
return await generateLocation(loc, shortLink)
|
|
} else if (shortLink !== undefined) {
|
|
return await generateIdLocation(loc, shortLink)
|
|
}
|
|
}
|
|
|
|
async function generateIdLocation (loc: Location, shortLink: string): Promise<ResolvedLocation | undefined> {
|
|
const tokens = shortLink.split('-')
|
|
if (tokens.length < 2) {
|
|
return undefined
|
|
}
|
|
const client = getClient()
|
|
const hierarchy = client.getHierarchy()
|
|
|
|
const classLabel = tokens[0]
|
|
const _id = tokens.slice(1).join('-')
|
|
const classes = [recruit.mixin.VacancyList, recruit.mixin.Candidate]
|
|
let _class: Ref<Class<Doc>> | undefined
|
|
for (const clazz of classes) {
|
|
if (hierarchy.getClass(clazz).shortLabel === classLabel) {
|
|
_class = clazz
|
|
break
|
|
}
|
|
}
|
|
if (_class === undefined) {
|
|
console.error(`Not found class with short label ${classLabel}`)
|
|
return undefined
|
|
}
|
|
const doc = await client.findOne(_class, { _id: _id as Ref<Doc> })
|
|
if (doc === undefined) {
|
|
accessDeniedStore.set(true)
|
|
console.error(`Could not find ${_class} with id ${_id}.`)
|
|
return undefined
|
|
}
|
|
const appComponent = loc.path[0] ?? ''
|
|
const workspace = loc.path[1] ?? ''
|
|
const objectPanel = hierarchy.classHierarchyMixin(Hierarchy.mixinOrClass(doc), view.mixin.ObjectPanel)
|
|
|
|
const component = objectPanel?.component ?? view.component.EditDoc
|
|
const special = _class === recruit.mixin.Candidate ? 'talents' : 'organizations'
|
|
const defaultPath = [appComponent, workspace, recruitId, special]
|
|
|
|
return {
|
|
loc: {
|
|
path: [appComponent, workspace],
|
|
fragment: getPanelURI(component, doc._id, _class, 'content')
|
|
},
|
|
defaultLocation: {
|
|
path: defaultPath,
|
|
fragment: getPanelURI(component, doc._id, _class, 'content')
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function parseLinkId (id: string): Promise<Ref<Doc> | undefined> {
|
|
if (isShortId(id)) {
|
|
const client = getClient()
|
|
const hierarchy = client.getHierarchy()
|
|
const data = getShortLinkData(hierarchy, id)
|
|
|
|
if (data === undefined) {
|
|
return id as Ref<Doc>
|
|
}
|
|
|
|
const [_class, , number] = data
|
|
|
|
if (_class === undefined) {
|
|
return id as Ref<Doc>
|
|
}
|
|
|
|
const doc = await client.findOne(_class, { number }, { projection: { _id: 1 } })
|
|
|
|
return doc?._id
|
|
}
|
|
|
|
return id as Ref<Doc>
|
|
}
|
|
|
|
function getShortLinkData (
|
|
hierarchy: Hierarchy,
|
|
shortLink: string
|
|
): [Ref<Class<Doc>> | undefined, string, number] | undefined {
|
|
const tokens = shortLink.split('-')
|
|
if (tokens.length < 2) {
|
|
return undefined
|
|
}
|
|
const classLabel = tokens[0]
|
|
const number = Number(tokens[1])
|
|
|
|
const classes = [recruit.class.Applicant, recruit.class.Vacancy, recruit.class.Review]
|
|
let _class: Ref<Class<Doc>> | undefined
|
|
for (const clazz of classes) {
|
|
if (hierarchy.getClass(clazz).shortLabel === classLabel) {
|
|
_class = clazz
|
|
break
|
|
}
|
|
}
|
|
|
|
return [_class, classLabel, number]
|
|
}
|
|
|
|
async function generateLocation (loc: Location, shortLink: string): Promise<ResolvedLocation | undefined> {
|
|
const client = getClient()
|
|
const hierarchy = client.getHierarchy()
|
|
const data = getShortLinkData(hierarchy, shortLink)
|
|
|
|
if (data === undefined) {
|
|
return
|
|
}
|
|
|
|
const [_class, classLabel, number] = data
|
|
|
|
if (_class === undefined) {
|
|
console.error(`Not found class with short label ${classLabel}`)
|
|
return undefined
|
|
}
|
|
const doc = await client.findOne(_class, { number })
|
|
if (doc === undefined) {
|
|
accessDeniedStore.set(true)
|
|
console.error(`Could not find ${_class} with number ${number}.`)
|
|
return undefined
|
|
}
|
|
const appComponent = loc.path[0] ?? ''
|
|
const workspace = loc.path[1] ?? ''
|
|
const objectPanel = hierarchy.classHierarchyMixin(_class, view.mixin.ObjectPanel)
|
|
const component = objectPanel?.component ?? view.component.EditDoc
|
|
const defaultPath = [appComponent, workspace, recruitId]
|
|
if (_class === recruit.class.Vacancy) {
|
|
defaultPath.push('vacancies')
|
|
} else if (_class === recruit.class.Applicant) {
|
|
defaultPath.push('candidates')
|
|
}
|
|
return {
|
|
loc: {
|
|
path: [appComponent, workspace],
|
|
fragment: getPanelURI(component, doc._id, doc._class, 'content')
|
|
},
|
|
defaultLocation: {
|
|
path: defaultPath,
|
|
fragment: getPanelURI(component, doc._id, doc._class, 'content')
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function getSequenceLink (doc: RecruitDocument): Promise<Location> {
|
|
const loc = getCurrentResolvedLocation()
|
|
loc.path.length = 2
|
|
loc.fragment = undefined
|
|
loc.query = undefined
|
|
loc.path[2] = recruitId
|
|
loc.path[3] = await getSequenceId(doc)
|
|
|
|
return loc
|
|
}
|
|
|
|
export async function getObjectLink (doc: Candidate | VacancyList): Promise<Location> {
|
|
const _class = Hierarchy.mixinOrClass(doc)
|
|
const client = getClient()
|
|
const clazz = client.getHierarchy().getClass(_class)
|
|
const loc = getCurrentResolvedLocation()
|
|
loc.path.length = 2
|
|
loc.fragment = undefined
|
|
loc.query = undefined
|
|
loc.path[2] = recruitId
|
|
loc.path[3] = clazz.shortLabel !== undefined ? `${clazz.shortLabel}-${doc._id}` : doc._id
|
|
|
|
return loc
|
|
}
|
|
|
|
export async function getVacTitle (client: Client, ref: Ref<Vacancy>, doc?: Vacancy): Promise<string> {
|
|
const object = doc ?? (await client.findOne(recruit.class.Vacancy, { _id: ref }))
|
|
return object != null ? object.name : ''
|
|
}
|
|
|
|
export async function getAppTitle (client: Client, ref: Ref<Applicant>, doc?: Applicant): Promise<string> {
|
|
const applicant = doc ?? (await client.findOne(recruit.class.Applicant, { _id: ref }))
|
|
if (applicant === undefined) return ''
|
|
const candidate = await client.findOne(contact.class.Contact, { _id: applicant.attachedTo })
|
|
if (candidate === undefined) return ''
|
|
return getName(client.getHierarchy(), candidate)
|
|
}
|
|
|
|
export async function getAppIdentifier (client: Client, ref: Ref<Applicant>, doc?: Applicant): Promise<string> {
|
|
const applicant = doc ?? (await client.findOne(recruit.class.Applicant, { _id: ref }))
|
|
|
|
if (applicant === undefined) {
|
|
return ''
|
|
}
|
|
|
|
return applicant.identifier
|
|
}
|
|
|
|
export async function getRevTitle (client: Client, ref: Ref<Review>, doc?: Review): Promise<string> {
|
|
const object = doc ?? (await client.findOne(recruit.class.Review, { _id: ref }))
|
|
return object != null ? object.title : ''
|
|
}
|
|
|
|
export async function getSequenceId (doc: RecruitDocument): Promise<string> {
|
|
const client = getClient()
|
|
const hierarchy = client.getHierarchy()
|
|
if (hierarchy.isDerived(doc._class, recruit.class.Applicant)) {
|
|
return (doc as Applicant).identifier
|
|
}
|
|
let clazz = hierarchy.getClass(doc._class)
|
|
let label = clazz.shortLabel
|
|
while (label === undefined && clazz.extends !== undefined) {
|
|
clazz = hierarchy.getClass(clazz.extends)
|
|
label = clazz.shortLabel
|
|
}
|
|
|
|
return label !== undefined ? `${label}-${doc.number}` : doc.number.toString()
|
|
}
|
|
|
|
export async function getTalentId (doc: Candidate): Promise<string> {
|
|
return doc._id
|
|
}
|
|
|
|
export async function getVacancyIdentifier (client: Client, ref: Ref<Vacancy>, doc?: Vacancy): Promise<string> {
|
|
const vacancy = doc ?? (await client.findOne(recruit.class.Vacancy, { _id: ref }))
|
|
|
|
if (vacancy === undefined) {
|
|
return ''
|
|
}
|
|
|
|
return await getSequenceId(vacancy)
|
|
}
|
|
|
|
export async function getReviewIdentifier (client: Client, ref: Ref<Review>, doc?: Review): Promise<string> {
|
|
const review = doc ?? (await client.findOne(recruit.class.Review, { _id: ref }))
|
|
|
|
if (review === undefined) {
|
|
return ''
|
|
}
|
|
|
|
return await getSequenceId(review)
|
|
}
|