Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZQMS-1069: Fix request model #6131

Merged
merged 3 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions models/all/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { questionsOperation } from '@hcengineering/model-questions'
import { trainingOperation } from '@hcengineering/model-training'
import { documentsOperation } from '@hcengineering/model-controlled-documents'
import { productsOperation } from '@hcengineering/model-products'
import { requestOperation } from '@hcengineering/model-request'

export const migrateOperations: [string, MigrateOperation][] = [
['core', coreOperation],
Expand All @@ -71,6 +72,7 @@ export const migrateOperations: [string, MigrateOperation][] = [
['documents', documentsOperation],
['questions', questionsOperation],
['training', trainingOperation],
['request', requestOperation],
['products', productsOperation],
['board', boardOperation],
['hr', hrOperation],
Expand Down
15 changes: 8 additions & 7 deletions models/request/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//

import activity from '@hcengineering/activity'
import type { PersonAccount } from '@hcengineering/contact'
import type { Person } from '@hcengineering/contact'
import contact from '@hcengineering/contact'
import { type Timestamp, type Domain, type Ref, type Tx } from '@hcengineering/core'
import {
Expand Down Expand Up @@ -43,6 +43,7 @@ import {
import { type AnyComponent } from '@hcengineering/ui/src/types'
import request from './plugin'

export { requestOperation } from './migration'
export { requestId } from '@hcengineering/request'
export { default } from './plugin'

Expand All @@ -51,13 +52,13 @@ export const DOMAIN_REQUEST = 'request' as Domain
@Model(request.class.Request, core.class.AttachedDoc, DOMAIN_REQUEST)
@UX(request.string.Request, request.icon.Requests)
export class TRequest extends TAttachedDoc implements Request {
@Prop(ArrOf(TypeRef(contact.class.PersonAccount)), request.string.Requested)
@Prop(ArrOf(TypeRef(contact.class.Person)), request.string.Requested)
// @Index(IndexKind.Indexed)
requested!: Ref<PersonAccount>[]
requested!: Ref<Person>[]

@Prop(ArrOf(TypeRef(contact.class.PersonAccount)), request.string.Approved)
@Prop(ArrOf(TypeRef(contact.class.Person)), request.string.Approved)
@ReadOnly()
approved!: Ref<PersonAccount>[]
approved!: Ref<Person>[]

approvedDates?: Timestamp[]

Expand All @@ -70,9 +71,9 @@ export class TRequest extends TAttachedDoc implements Request {
tx!: Tx
rejectedTx?: Tx

@Prop(TypeRef(contact.class.PersonAccount), request.string.Rejected)
@Prop(TypeRef(contact.class.Person), request.string.Rejected)
@ReadOnly()
rejected?: Ref<PersonAccount>
rejected?: Ref<Person>

@Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments)
comments?: number
Expand Down
99 changes: 99 additions & 0 deletions models/request/src/migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import core, { DOMAIN_TX, type Ref, type TxCreateDoc } from '@hcengineering/core'
import request, { requestId, type Request } from '@hcengineering/request'
import {
type MigrateUpdate,
type MigrationDocumentQuery,
tryMigrate,
type MigrateOperation,
type MigrationClient,
type MigrationUpgradeClient,
type ModelLogger
} from '@hcengineering/model'
import contact, { type Person, type PersonAccount } from '@hcengineering/contact'

import { DOMAIN_REQUEST } from '.'

async function migrateRequestPersonAccounts (client: MigrationClient): Promise<void> {
const descendants = client.hierarchy.getDescendants(request.class.Request)
const requests = await client.find<Request>(DOMAIN_REQUEST, {
_class: { $in: descendants }
})
const personAccountsCreateTxes = await client.find(DOMAIN_TX, {
_class: core.class.TxCreateDoc,
objectClass: contact.class.PersonAccount
})
const personAccountToPersonMap = personAccountsCreateTxes.reduce<Record<Ref<PersonAccount>, Ref<Person>>>(
(map, tx) => {
const ctx = tx as TxCreateDoc<PersonAccount>

map[ctx.objectId] = ctx.attributes.person

return map
},
{}
)
const operations: { filter: MigrationDocumentQuery<Request>, update: MigrateUpdate<Request> }[] = []
for (const request of requests) {
const newRequestedPersons = request.requested
.map((paId) => personAccountToPersonMap[paId as unknown as Ref<PersonAccount>])
.filter((p) => p != null)
const newApprovedPersons = request.approved
.map((paId) => personAccountToPersonMap[paId as unknown as Ref<PersonAccount>])
.filter((p) => p != null)
const newRejectedPerson =
request.rejected != null ? personAccountToPersonMap[request.rejected as unknown as Ref<PersonAccount>] : undefined

if (newRequestedPersons.length > 0) {
operations.push({
filter: {
_id: request._id
},
update: {
requested: newRequestedPersons,
approved: newApprovedPersons
}
})
}

if (newRejectedPerson !== undefined) {
operations.push({
filter: {
_id: request._id
},
update: {
rejected: newRejectedPerson
}
})
}
}

if (operations.length > 0) {
await client.bulk(DOMAIN_REQUEST, operations)
}
}

export const requestOperation: MigrateOperation = {
async migrate (client: MigrationClient, logger: ModelLogger): Promise<void> {
await tryMigrate(client, requestId, [
{
state: 'migrateRequestPersonAccounts',
func: migrateRequestPersonAccounts
}
])
},
async upgrade (state: Map<string, Set<string>>, client: () => Promise<MigrationUpgradeClient>): Promise<void> {}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
// Copyright © 2023, 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
Expand All @@ -17,7 +17,7 @@
import { Label, Scroller } from '@hcengineering/ui'
import { createQuery } from '@hcengineering/presentation'
import documents, { DocumentApprovalRequest, DocumentReviewRequest } from '@hcengineering/controlled-documents'
import { employeeByIdStore, personAccountByIdStore } from '@hcengineering/contact-resources'
import { employeeByIdStore } from '@hcengineering/contact-resources'
import { Employee, Person, formatName } from '@hcengineering/contact'
import { IntlString } from '@hcengineering/platform'

Expand Down Expand Up @@ -98,27 +98,25 @@

if (reviewRequest !== undefined) {
reviewRequest.approved.forEach((reviewer, idx) => {
const rAcc = $personAccountByIdStore.get(reviewer)
const date = reviewRequest.approvedDates?.[idx]

signers.push({
id: rAcc?.person,
id: reviewer,
role: 'reviewer',
name: getNameByEmployeeId(rAcc?.person),
name: getNameByEmployeeId(reviewer),
date: formatSignatureDate(date ?? reviewRequest.modifiedOn)
})
})
}

if (approvalRequest !== undefined) {
approvalRequest.approved.forEach((approver, idx) => {
const aAcc = $personAccountByIdStore.get(approver)
const date = approvalRequest.approvedDates?.[idx]

signers.push({
id: aAcc?.person,
id: approver,
role: 'approver',
name: getNameByEmployeeId(aAcc?.person),
name: getNameByEmployeeId(approver),
date: formatSignatureDate(date ?? approvalRequest.modifiedOn)
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import { slide } from 'svelte/transition'
import documents, { DocumentRequest } from '@hcengineering/controlled-documents'
import chunter from '@hcengineering/chunter'
import { type Person, type PersonAccount } from '@hcengineering/contact'
import { PersonAccountRefPresenter, personAccountByIdStore } from '@hcengineering/contact-resources'
import { type Person } from '@hcengineering/contact'
import { PersonRefPresenter, personAccountByIdStore } from '@hcengineering/contact-resources'
import { Ref } from '@hcengineering/core'
import { getClient } from '@hcengineering/presentation'
import { Chevron, Label, tooltip } from '@hcengineering/ui'
Expand All @@ -20,7 +20,6 @@
export let initiallyExpanded: boolean = false

interface PersonalApproval {
account: Ref<PersonAccount>
person?: Ref<Person>
approved: 'approved' | 'rejected' | 'cancelled' | 'waiting'
timestamp?: number
Expand Down Expand Up @@ -61,16 +60,14 @@
req.rejected !== undefined
? [
{
account: req.rejected,
person: accountById.get(req.rejected)?.person,
person: req.rejected,
approved: 'rejected',
timestamp: req.modifiedOn
}
]
: []
const approvedBy: PersonalApproval[] = req.approved.map((id, idx) => ({
account: id,
person: accountById.get(id)?.person,
person: id,
approved: 'approved',
timestamp: req.approvedDates?.[idx] ?? req.modifiedOn
}))
Expand All @@ -79,8 +76,7 @@
.filter((p) => !(req?.approved as string[]).includes(p))
.map(
(id): PersonalApproval => ({
account: id,
person: accountById.get(id)?.person,
person: id,
approved: req?.rejected !== undefined ? 'cancelled' : 'waiting'
})
)
Expand Down Expand Up @@ -125,7 +121,7 @@
<div class="section" transition:slide|local>
{#each approvals as approver}
<div class="approver">
<PersonAccountRefPresenter value={approver.account} avatarSize="x-small" />
<PersonRefPresenter value={approver.person} avatarSize="x-small" />
{#key approver.timestamp}
<!-- For some reason tooltip is not interactive w/o remount -->
<span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ export const $documentStateForCurrentUser = combine($controlledDocument, $review
return ControlledDocumentState.InReview
}

const currentAccount = getCurrentAccount()._id as Ref<PersonAccount>
if (reviewRequest.approved?.includes(currentAccount)) {
const currentPerson = (getCurrentAccount() as PersonAccount).person
if (reviewRequest.approved?.includes(currentPerson)) {
return ControlledDocumentState.Reviewed
}
}
Expand All @@ -228,7 +228,7 @@ export const $documentState = $controlledDocument.map((doc) => {
})

export const $documentReviewIsActive = combine($reviewRequest, $documentStateForCurrentUser, (reviewReq, state) => {
const me = getCurrentAccount()._id as Ref<PersonAccount>
const me = (getCurrentAccount() as PersonAccount).person

if (reviewReq == null) {
return false
Expand All @@ -244,7 +244,7 @@ export const $documentApprovalIsActive = combine(
$approvalRequest,
$documentStateForCurrentUser,
(doc, approvalReq, state) => {
const me = getCurrentAccount()._id as Ref<PersonAccount>
const me = (getCurrentAccount() as PersonAccount).person

if (approvalReq == null) {
return false
Expand Down
4 changes: 2 additions & 2 deletions plugins/controlled-documents-resources/src/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ async function getDocumentStateForCurrentUser (
return ControlledDocumentState.InReview
}

const currentAccount = getCurrentAccount()._id as Ref<PersonAccount>
if (reviewRequest.approved?.includes(currentAccount)) {
const me = (getCurrentAccount() as PersonAccount).person
if (reviewRequest.approved?.includes(me)) {
return ControlledDocumentState.Reviewed
}
}
Expand Down
32 changes: 6 additions & 26 deletions plugins/controlled-documents-resources/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import core, {
} from '@hcengineering/core'
import { type IntlString, getMetadata, getResource, translate } from '@hcengineering/platform'
import presentation, { copyDocumentContent, getClient } from '@hcengineering/presentation'
import contact, { type Employee, type PersonAccount } from '@hcengineering/contact'
import { type Person, type Employee, type PersonAccount } from '@hcengineering/contact'
import request, { RequestStatus } from '@hcengineering/request'
import textEditor from '@hcengineering/text-editor'
import { isEmptyMarkup } from '@hcengineering/text'
Expand Down Expand Up @@ -313,16 +313,6 @@ export async function sendReviewRequest (
controlledDoc: ControlledDocument,
reviewers: Array<Ref<Employee>>
): Promise<void> {
const reviewersAccounts = await client.findAll(contact.class.PersonAccount, { person: { $in: reviewers } })

if (reviewersAccounts.length === 0) {
return
}

if (reviewersAccounts.length < reviewers.length) {
console.warn('Number of user accounts is less than requested for document review request')
}

const approveTx = client.txFactory.createTxUpdateDoc(controlledDoc._class, controlledDoc.space, controlledDoc._id, {
controlledState: ControlledDocumentState.Reviewed
})
Expand All @@ -338,7 +328,7 @@ export async function sendReviewRequest (
controlledDoc._class,
documents.class.DocumentReviewRequest,
controlledDoc.space,
reviewersAccounts.map((u) => u._id),
reviewers,
approveTx,
undefined,
true
Expand All @@ -350,16 +340,6 @@ export async function sendApprovalRequest (
controlledDoc: ControlledDocument,
approvers: Array<Ref<Employee>>
): Promise<void> {
const approversAccounts = await client.findAll(contact.class.PersonAccount, { person: { $in: approvers } })

if (approversAccounts.length === 0) {
return
}

if (approversAccounts.length < approvers.length) {
console.warn('Number of user accounts is less than requested for document approval request')
}

const approveTx = client.txFactory.createTxUpdateDoc(controlledDoc._class, controlledDoc.space, controlledDoc._id, {
controlledState: ControlledDocumentState.Approved
})
Expand All @@ -379,7 +359,7 @@ export async function sendApprovalRequest (
controlledDoc._class,
documents.class.DocumentApprovalRequest,
controlledDoc.space,
approversAccounts.map((u) => u._id),
approvers,
approveTx,
rejectTx,
true
Expand All @@ -392,7 +372,7 @@ async function createRequest<T extends Doc> (
attachedToClass: Ref<Class<T>>,
reqClass: Ref<Class<Request>>,
space: Ref<DocumentSpace>,
users: Array<Ref<PersonAccount>>,
users: Array<Ref<Person>>,
approveTx: Tx,
rejectedTx?: Tx,
areAllApprovesRequired = true
Expand Down Expand Up @@ -429,7 +409,7 @@ export async function completeRequest (
): Promise<void> {
const req = await getActiveRequest(client, reqClass, controlledDoc)

const me = getCurrentAccount()._id as Ref<PersonAccount>
const me = (getCurrentAccount() as PersonAccount).person

if (req == null || !req.requested.includes(me) || req.approved.includes(me)) {
return
Expand Down Expand Up @@ -465,7 +445,7 @@ export async function rejectRequest (
return
}

const me = getCurrentAccount()._id as Ref<PersonAccount>
const me = (getCurrentAccount() as PersonAccount).person

await saveComment(rejectionNote, req)

Expand Down
Loading