mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 00:43:59 +03:00
Fake data generator (#594)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
ed9bcfa943
commit
36f2353878
18
.vscode/launch.json
vendored
18
.vscode/launch.json
vendored
@ -28,6 +28,22 @@
|
||||
"console": "integratedTerminal",
|
||||
"sourceMaps": true,
|
||||
"protocol": "inspector"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug generator",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"args": ["src/index.ts", "gen-recruit", "ws1", "20"],
|
||||
"env": {
|
||||
"TRANSACTOR_URL":"ws:/localhost:3333",
|
||||
"MINIO_ACCESS_KEY":"minioadmin",
|
||||
"MINIO_SECRET_KEY":"minioadmin",
|
||||
"MINIO_ENDPOINT":"localhost"
|
||||
},
|
||||
"runtimeArgs": ["--nolazy", "-r", "ts-node/register" ],
|
||||
"sourceMaps": true,
|
||||
"cwd": "${workspaceRoot}/dev/generator",
|
||||
"protocol": "inspector"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
7
dev/generator/.eslintrc.js
Normal file
7
dev/generator/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: ['./node_modules/@anticrm/platform-rig/profiles/default/config/eslint.config.json'],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
}
|
4
dev/generator/.npmignore
Normal file
4
dev/generator/.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!/lib/**
|
||||
!CHANGELOG.md
|
||||
/lib/**/__tests__/
|
7
dev/generator/Dockerfile
Normal file
7
dev/generator/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM node
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY bundle.js ./
|
||||
|
||||
CMD [ "bash" ]
|
20
dev/generator/build.sh
Executable file
20
dev/generator/build.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
# Copyright © 2021 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.
|
||||
#
|
||||
|
||||
rushx bundle
|
||||
rushx docker:build
|
||||
rushx docker:push
|
18
dev/generator/config/rig.json
Normal file
18
dev/generator/config/rig.json
Normal file
@ -0,0 +1,18 @@
|
||||
// The "rig.json" file directs tools to look for their config files in an external package.
|
||||
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
||||
|
||||
/**
|
||||
* (Required) The name of the rig package to inherit from.
|
||||
* It should be an NPM package name with the "-rig" suffix.
|
||||
*/
|
||||
"rigPackageName": "@anticrm/platform-rig"
|
||||
|
||||
/**
|
||||
* (Optional) Selects a config profile from the rig package. The name must consist of
|
||||
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
||||
* If omitted, then the "default" profile will be used."
|
||||
*/
|
||||
// "rigProfile": "your-profile-name"
|
||||
}
|
64
dev/generator/package.json
Normal file
64
dev/generator/package.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "@anticrm/generator",
|
||||
"version": "0.6.0",
|
||||
"main": "lib/index.js",
|
||||
"author": "Anticrm Platform Contributors",
|
||||
"license": "EPL-2.0",
|
||||
"scripts": {
|
||||
"build": "heft build",
|
||||
"build:watch": "tsc",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"start": "ts-node src/index.ts",
|
||||
"bundle": "esbuild src/index.ts --bundle --minify --platform=node > bundle.js",
|
||||
"docker:build": "docker build -t anticrm/tool .",
|
||||
"docker:push": "docker push anticrm/tool",
|
||||
"run-local": "TRANSACTOR_URL=ws:/localhost:3333 MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost ts-node ./src/index.ts",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier --write src && eslint --fix src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anticrm/platform-rig": "~0.6.0",
|
||||
"@types/heft-jest": "^1.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint": "^7.32.0",
|
||||
"ts-node": "^10.2.1",
|
||||
"esbuild": "^0.12.26",
|
||||
"@types/node": "~16.11.12",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint-config-standard-with-typescript": "^21.0.1",
|
||||
"prettier": "^2.4.1",
|
||||
"@rushstack/heft": "^0.41.1",
|
||||
"typescript": "^4.3.5",
|
||||
"@types/ws": "^8.2.1",
|
||||
"@types/faker": "~5.5.9",
|
||||
"@types/minio": "^7.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "^8.1.0",
|
||||
"@anticrm/account": "~0.6.0",
|
||||
"jwt-simple": "^0.5.6",
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/contact": "~0.6.2",
|
||||
"@anticrm/model-all": "~0.6.0",
|
||||
"@anticrm/model-telegram": "~0.6.0",
|
||||
"@anticrm/telegram": "~0.6.0",
|
||||
"@anticrm/client-resources": "~0.6.4",
|
||||
"ws": "^8.2.0",
|
||||
"@anticrm/client": "~0.6.1",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/model": "~0.6.0",
|
||||
"@anticrm/recruit": "~0.6.2",
|
||||
"faker": "~5.5.3",
|
||||
"@anticrm/model-recruit": "~0.6.0",
|
||||
"@anticrm/chunter": "~0.6.1",
|
||||
"pdfkit": "~0.13.0",
|
||||
"@anticrm/attachment": "~0.6.1",
|
||||
"minio": "^7.0.19",
|
||||
"@types/pdfkit": "~0.12.3",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"jpeg-js": "~0.4.3"
|
||||
}
|
||||
}
|
12
dev/generator/readme.md
Normal file
12
dev/generator/readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Overview
|
||||
|
||||
Random data generator
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd ./dev/generator
|
||||
rushx run-local gen-recruit workspace 20
|
||||
```
|
||||
|
||||
Will generate 20 candidate cards.
|
25
dev/generator/run.sh
Executable file
25
dev/generator/run.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
# Copyright © 2021 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.
|
||||
#
|
||||
|
||||
export MINIO_ENDPOINT=$(kubectl get secret minio -o jsonpath="{.data.endpoint}" | base64 --decode)
|
||||
export MINIO_ACCESS_KEY=$(kubectl get secret minio -o jsonpath="{.data.accessKey}" | base64 --decode)
|
||||
export MINIO_SECRET_KEY=$(kubectl get secret minio -o jsonpath="{.data.secretKey}" | base64 --decode)
|
||||
|
||||
kubectl run anticrm-tool --rm --tty -i --restart='Never' \
|
||||
--env="TRANSACTOR_URL=ws://transactor/" \
|
||||
--env="MINIO_ENDPOINT=$MINIO_ENDPOINT" \
|
||||
--env="MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" \
|
||||
--env="MINIO_SECRET_KEY=$MINIO_SECRET_KEY" --image anticrm/tool --command -- bash
|
46
dev/generator/src/attachments.ts
Normal file
46
dev/generator/src/attachments.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import attachment, { Attachment } from '@anticrm/attachment'
|
||||
import { Class, Doc, generateId, Ref, Space, TxOperations } from '@anticrm/core'
|
||||
import faker from 'faker'
|
||||
import { Client } from 'minio'
|
||||
import PDFDocument from 'pdfkit'
|
||||
|
||||
export interface AttachmentOptions {
|
||||
min: number
|
||||
max: number
|
||||
deleteFactor: number // 0-100 value, will delete just added attachment, below min with rate
|
||||
}
|
||||
|
||||
export async function addAttachments<T extends Doc> (options: AttachmentOptions, client: TxOperations, minio: Client, dbName: string, space: Ref<Space>, objectId: Ref<T>, _class: Ref<Class<T>>, collection: string): Promise<void> {
|
||||
const attachmentCount = options.min + faker.datatype.number(options.max)
|
||||
for (let i = 0; i < attachmentCount; i++) {
|
||||
const attachmentId = `candidate-attachment-${generateId()}-${i}` as Ref<Attachment>
|
||||
|
||||
const needDelete = i >= options.min && (faker.datatype.number(100) > options.deleteFactor)
|
||||
|
||||
let bufLen = 0
|
||||
if (!needDelete) {
|
||||
const doc = new PDFDocument()
|
||||
doc
|
||||
.fontSize(16)
|
||||
.text(faker.lorem.paragraph(faker.datatype.number(50)))
|
||||
|
||||
doc.end()
|
||||
|
||||
const buf = doc.read()
|
||||
bufLen = buf.length
|
||||
await minio.putObject(dbName, attachmentId, buf, bufLen, { 'Content-Type': 'application/pdf' })
|
||||
}
|
||||
|
||||
await client.addCollection(attachment.class.Attachment, space, objectId, _class, 'attachments', {
|
||||
name: faker.system.commonFileName('pdf'),
|
||||
file: attachmentId,
|
||||
type: 'application/pdf',
|
||||
size: bufLen,
|
||||
lastModified: faker.date.past().getTime()
|
||||
}, attachmentId)
|
||||
|
||||
if (needDelete) {
|
||||
await client.removeCollection(attachment.class.Attachment, space, attachmentId, objectId, _class, 'attachments')
|
||||
}
|
||||
}
|
||||
}
|
29
dev/generator/src/comments.ts
Normal file
29
dev/generator/src/comments.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import chunter, { Comment } from '@anticrm/chunter'
|
||||
import { AttachedData, Class, Doc, generateId, Ref, Space, TxOperations } from '@anticrm/core'
|
||||
import faker from 'faker'
|
||||
|
||||
export interface CommentOptions {
|
||||
min: number
|
||||
max: number
|
||||
paragraphMin: number
|
||||
paragraphMax: number
|
||||
updateFactor: number // 0-100 value, will generate random value and if value is less updateFactor it will be updated.
|
||||
}
|
||||
|
||||
export async function addComments<T extends Doc> (options: CommentOptions, client: TxOperations, space: Ref<Space>, objectId: Ref<T>, _class: Ref<Class<T>>, collection: string): Promise<void> {
|
||||
const commentsCount = options.min + faker.datatype.number(options.max)
|
||||
for (let i = 0; i < commentsCount; i++) {
|
||||
const commentId = `candidate-comment-${generateId()}-${i}` as Ref<Comment>
|
||||
|
||||
const commentData: AttachedData<Comment> = {
|
||||
message: faker.lorem.paragraphs(options.paragraphMin + faker.datatype.number(options.paragraphMax))
|
||||
}
|
||||
await client.addCollection(chunter.class.Comment, space, objectId, _class, collection, commentData, commentId)
|
||||
|
||||
if (faker.datatype.number(100) > options.updateFactor) {
|
||||
const updateMsg = faker.lorem.paragraphs(options.paragraphMin + faker.datatype.number(options.paragraphMax))
|
||||
|
||||
await client.updateCollection(chunter.class.Comment, space, commentId, objectId, _class, collection, { message: updateMsg })
|
||||
}
|
||||
}
|
||||
}
|
18
dev/generator/src/connect.ts
Normal file
18
dev/generator/src/connect.ts
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
import client from '@anticrm/client'
|
||||
import clientResources from '@anticrm/client-resources'
|
||||
import { Client } from '@anticrm/core'
|
||||
import { setMetadata } from '@anticrm/platform'
|
||||
import { encode } from 'jwt-simple'
|
||||
|
||||
// eslint-disable-next-line
|
||||
const WebSocket = require('ws')
|
||||
|
||||
export async function connect (transactorUrl: string, workspace: string): Promise<Client> {
|
||||
console.log('connecting to transactor...')
|
||||
const token = encode({ email: 'anticrm@hc.engineering', workspace }, 'secret')
|
||||
|
||||
// We need to override default factory with 'ws' one.
|
||||
setMetadata(client.metadata.ClientSocketFactory, (url) => new WebSocket(url))
|
||||
return await (await clientResources()).function.GetClient(token, transactorUrl)
|
||||
}
|
72
dev/generator/src/index.ts
Normal file
72
dev/generator/src/index.ts
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 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 { program } from 'commander'
|
||||
import { Client } from 'minio'
|
||||
import { generateContacts } from './recruit'
|
||||
|
||||
const transactorUrl = process.env.TRANSACTOR_URL
|
||||
if (transactorUrl === undefined) {
|
||||
console.error('please provide transactor url.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const minioEndpoint = process.env.MINIO_ENDPOINT
|
||||
if (minioEndpoint === undefined) {
|
||||
console.error('please provide minio endpoint')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const minioAccessKey = process.env.MINIO_ACCESS_KEY
|
||||
if (minioAccessKey === undefined) {
|
||||
console.error('please provide minio access key')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const minioSecretKey = process.env.MINIO_SECRET_KEY
|
||||
if (minioSecretKey === undefined) {
|
||||
console.error('please provide minio secret key')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const minio = new Client({
|
||||
endPoint: minioEndpoint,
|
||||
port: 9000,
|
||||
useSSL: false,
|
||||
accessKey: minioAccessKey,
|
||||
secretKey: minioSecretKey
|
||||
})
|
||||
|
||||
program.version('0.0.1')
|
||||
|
||||
program
|
||||
.command('gen-recruit <workspace> <count>')
|
||||
.description('generate a bunch of random candidates with attachemnts and comments.')
|
||||
.option('-r, --random', 'generate random ids. So every call will add count <count> more candidates.', false)
|
||||
.action(async (workspace: string, count: number, cmd) => {
|
||||
return await generateContacts(transactorUrl, workspace, {
|
||||
contacts: count,
|
||||
random: (cmd.random as boolean),
|
||||
comments: { min: 1, max: 10, paragraphMin: 1, paragraphMax: 20, updateFactor: 30 },
|
||||
attachments: {
|
||||
min: 1, max: 3, deleteFactor: 20
|
||||
},
|
||||
vacancy: 3,
|
||||
applicantUpdateFactor: 70
|
||||
}, minio)
|
||||
})
|
||||
|
||||
program.parse(process.argv)
|
36
dev/generator/src/kanban.ts
Normal file
36
dev/generator/src/kanban.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import core, { Ref, SpaceWithStates, State, TxOperations } from '@anticrm/core'
|
||||
import { findOrUpdate } from './utils'
|
||||
import view, { Kanban } from '@anticrm/view'
|
||||
|
||||
export async function createUpdateSpaceKanban (spaceId: Ref<SpaceWithStates>, client: TxOperations): Promise<Ref<State>[]> {
|
||||
const states = [
|
||||
{ color: '#7C6FCD', name: 'Initial' },
|
||||
{ color: '#6F7BC5', name: 'Intermidiate' },
|
||||
{ color: '#77C07B', name: 'OverIntermidiate' },
|
||||
{ color: '#A5D179', name: 'Done' },
|
||||
{ color: '#F28469', name: 'Invalid' }
|
||||
]
|
||||
const ids: Array<Ref<State>> = []
|
||||
for (const st of states) {
|
||||
const sid = ('generated-' + spaceId + '.state.' + st.name.toLowerCase().replace(' ', '_')) as Ref<State>
|
||||
await findOrUpdate(client, spaceId, core.class.State,
|
||||
sid,
|
||||
{
|
||||
title: st.name,
|
||||
color: st.color
|
||||
}
|
||||
)
|
||||
ids.push(sid)
|
||||
}
|
||||
|
||||
await findOrUpdate(client, spaceId,
|
||||
view.class.Kanban,
|
||||
('generated-' + spaceId + '.kanban') as Ref<Kanban>,
|
||||
{
|
||||
attachedTo: spaceId,
|
||||
states: ids,
|
||||
order: []
|
||||
}
|
||||
)
|
||||
return ids
|
||||
}
|
146
dev/generator/src/recruit.ts
Normal file
146
dev/generator/src/recruit.ts
Normal file
@ -0,0 +1,146 @@
|
||||
import contact from '@anticrm/contact'
|
||||
import core, { AttachedData, Data, generateId, Ref, TxOperations } from '@anticrm/core'
|
||||
import recruit from '@anticrm/model-recruit'
|
||||
import { Applicant, Candidate, Vacancy } from '@anticrm/recruit'
|
||||
import faker from 'faker'
|
||||
import jpeg, { BufferRet } from 'jpeg-js'
|
||||
import { Client } from 'minio'
|
||||
import { addAttachments, AttachmentOptions } from './attachments'
|
||||
import { addComments, CommentOptions } from './comments'
|
||||
import { connect } from './connect'
|
||||
import { createUpdateSpaceKanban } from './kanban'
|
||||
import { findOrUpdate, findOrUpdateAttached } from './utils'
|
||||
|
||||
export interface RecruitOptions {
|
||||
random: boolean // random id prefix.
|
||||
contacts: number // how many contacts to add
|
||||
vacancy: number // Will add number of vacancies with applications.
|
||||
// Comment generation control
|
||||
comments: CommentOptions
|
||||
// Attachment generation control
|
||||
attachments: AttachmentOptions
|
||||
|
||||
applicantUpdateFactor: number
|
||||
}
|
||||
|
||||
export async function generateContacts (transactorUrl: string, dbName: string, options: RecruitOptions, minio: Client): Promise<void> {
|
||||
const connection = await connect(transactorUrl, dbName)
|
||||
|
||||
const accounts = await connection.findAll(contact.class.EmployeeAccount, {})
|
||||
const accountIds = accounts.map(a => a._id)
|
||||
const emoloyeeIds = accounts.map(a => a.employee)
|
||||
|
||||
const account = faker.random.arrayElement(accounts)
|
||||
|
||||
const client = new TxOperations(connection, account._id)
|
||||
|
||||
const candidates: Ref<Candidate>[] = []
|
||||
|
||||
for (let i = 0; i < options.contacts; i++) {
|
||||
const fName = faker.name.firstName()
|
||||
const lName = faker.name.lastName()
|
||||
|
||||
const { imgId, jpegImageData } = generateAvatar(i)
|
||||
await minio.putObject(dbName, imgId, jpegImageData.data, jpegImageData.data.length, { 'Content-Type': 'image/jpeg' })
|
||||
const candidate: Data<Candidate> = {
|
||||
name: fName + ',' + lName,
|
||||
city: faker.address.city(),
|
||||
title: faker.name.title(),
|
||||
channels: [
|
||||
{ provider: contact.channelProvider.Email, value: faker.internet.email(fName, lName) }
|
||||
],
|
||||
onsite: faker.datatype.boolean(),
|
||||
remote: faker.datatype.boolean(),
|
||||
avatar: imgId,
|
||||
source: faker.lorem.lines(1)
|
||||
}
|
||||
const candidateId = (options.random ? `candidate-${generateId()}-${i}` : `candidate-genid-${i}`) as Ref<Candidate>
|
||||
candidates.push(candidateId)
|
||||
|
||||
// Update or create candidate
|
||||
await findOrUpdate(client, recruit.space.CandidatesPublic, recruit.class.Candidate, candidateId, candidate)
|
||||
|
||||
await addComments(options.comments, client, recruit.space.CandidatesPublic, candidateId, recruit.class.Candidate, 'comments')
|
||||
|
||||
await addAttachments(options.attachments, client, minio, dbName, recruit.space.CandidatesPublic, candidateId, recruit.class.Candidate, 'attachments')
|
||||
|
||||
console.log('Candidate', fName, lName, ' generated')
|
||||
}
|
||||
// Work on Vacancy/Applications.
|
||||
for (let i = 0; i < options.vacancy; i++) {
|
||||
const vacancy: Data<Vacancy> = {
|
||||
name: faker.company.companyName(),
|
||||
description: faker.lorem.sentences(2),
|
||||
fullDescription: faker.lorem.sentences(10),
|
||||
location: faker.address.city(),
|
||||
company: faker.company.companyName(),
|
||||
members: accountIds,
|
||||
private: false
|
||||
}
|
||||
const vacancyId = (options.random ? `vacancy-${generateId()}-${i}` : `vacancy-genid-${i}`) as Ref<Vacancy>
|
||||
|
||||
console.log('Creating vacandy', vacancy.name)
|
||||
// Update or create candidate
|
||||
await findOrUpdate(client, core.space.Model, recruit.class.Vacancy, vacancyId, vacancy)
|
||||
|
||||
console.log('Vacandy generated', vacancy.name)
|
||||
|
||||
await addAttachments(options.attachments, client, minio, dbName, vacancyId, vacancyId, recruit.class.Vacancy, 'attachments')
|
||||
|
||||
console.log('Vacandy attachments generated', vacancy.name)
|
||||
|
||||
const states = await createUpdateSpaceKanban(vacancyId, client)
|
||||
|
||||
console.log('States generated', vacancy.name)
|
||||
|
||||
for (const candidateId of candidates) {
|
||||
const applicantId = `vacancy-${vacancyId}-${candidateId}` as Ref<Applicant>
|
||||
|
||||
const applicant: AttachedData<Applicant> = {
|
||||
number: faker.datatype.number(),
|
||||
employee: faker.random.arrayElement(emoloyeeIds),
|
||||
state: faker.random.arrayElement(states)
|
||||
}
|
||||
|
||||
// Update or create candidate
|
||||
await findOrUpdateAttached(client, vacancyId, recruit.class.Applicant, applicantId, applicant, { attachedTo: candidateId, attachedClass: recruit.class.Candidate, collection: 'applications' })
|
||||
|
||||
await addComments(options.comments, client, vacancyId, applicantId, recruit.class.Vacancy, 'comments')
|
||||
|
||||
await addAttachments(options.attachments, client, minio, dbName, vacancyId, applicantId, recruit.class.Applicant, 'attachments')
|
||||
|
||||
if (faker.datatype.number(100) > options.applicantUpdateFactor) {
|
||||
await client.updateCollection(recruit.class.Applicant, vacancyId, applicantId, candidateId, recruit.class.Applicant, 'applications', {
|
||||
state: faker.random.arrayElement(states)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await connection.close()
|
||||
}
|
||||
function generateAvatar (pos: number): {imgId: string, jpegImageData: BufferRet } {
|
||||
const imgId = generateId()
|
||||
const width = 128
|
||||
const height = 128
|
||||
const frameData = Buffer.alloc(width * height * 4)
|
||||
let i = 0
|
||||
|
||||
const baseR = faker.datatype.number(255)
|
||||
const baseG = faker.datatype.number(255)
|
||||
const baseB = faker.datatype.number(255)
|
||||
|
||||
while (i < frameData.length) {
|
||||
frameData[i++] = (baseR + faker.datatype.number(100)) % 255 // red
|
||||
frameData[i++] = (baseG + faker.datatype.number(100)) % 255 // green
|
||||
frameData[i++] = (baseB + faker.datatype.number(100)) % 255 // blue
|
||||
frameData[i++] = 0xff // alpha - ignored in JPEGs
|
||||
}
|
||||
const rawImageData = {
|
||||
data: frameData,
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
const jpegImageData = jpeg.encode(rawImageData, 50)
|
||||
return { imgId, jpegImageData }
|
||||
}
|
18
dev/generator/src/utils.ts
Normal file
18
dev/generator/src/utils.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { AttachedData, AttachedDoc, Class, Data, Doc, DocumentUpdate, Ref, Space, TxOperations } from '@anticrm/core'
|
||||
|
||||
export async function findOrUpdate<T extends Doc> (client: TxOperations, space: Ref<Space>, _class: Ref<Class<T>>, objectId: Ref<T>, data: Data<T>): Promise<void> {
|
||||
const existingObj = await client.findOne<Doc>(_class, { _id: objectId, space })
|
||||
if (existingObj !== undefined) {
|
||||
await client.updateDoc(_class, space, objectId, data)
|
||||
} else {
|
||||
await client.createDoc(_class, space, data, objectId)
|
||||
}
|
||||
}
|
||||
export async function findOrUpdateAttached<T extends AttachedDoc> (client: TxOperations, space: Ref<Space>, _class: Ref<Class<T>>, objectId: Ref<T>, data: AttachedData<T>, attached: {attachedTo: Ref<Doc>, attachedClass: Ref<Class<Doc>>, collection: string}): Promise<void> {
|
||||
const existingObj = await client.findOne<Doc>(_class, { _id: objectId, space })
|
||||
if (existingObj !== undefined) {
|
||||
await client.updateCollection(_class, space, objectId, attached.attachedTo, attached.attachedClass, attached.collection, data as unknown as DocumentUpdate<T>)
|
||||
} else {
|
||||
await client.addCollection(_class, space, attached.attachedTo, attached.attachedClass, attached.collection, data, objectId)
|
||||
}
|
||||
}
|
10
dev/generator/tsconfig.json
Normal file
10
dev/generator/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./node_modules/@anticrm/platform-rig/profiles/default/tsconfig.json",
|
||||
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"esModuleInterop": true,
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
"bundle": "esbuild src/index.ts --bundle --minify --platform=node > bundle.js",
|
||||
"docker:build": "docker build -t anticrm/tool .",
|
||||
"docker:push": "docker push anticrm/tool",
|
||||
"run-local": "cross-env MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MONGO_URL=mongodb://localhost:27017 TRANSACTOR_URL=ws:/localhost:3333 MINIO_ENDPOINT=localhost TELEGRAM_DATABASE=telegram-service ts-node ./src/index.ts",
|
||||
"run-local": "cross-env MINIO_ACCESS_KEY=minioadmin MINIO_SECRET_KEY=minioadmin MINIO_ENDPOINT=localhost MONGO_URL=mongodb://localhost:27017 TRANSACTOR_URL=ws:/localhost:3333 TELEGRAM_DATABASE=telegram-service ts-node ./src/index.ts",
|
||||
"lint": "eslint src",
|
||||
"format": "prettier --write src && eslint --fix src"
|
||||
},
|
||||
|
@ -91,7 +91,6 @@ class ClientImpl implements Client {
|
||||
}
|
||||
|
||||
async updateFromRemote (tx: Tx): Promise<void> {
|
||||
console.log('UPDATE FROM REMOTE')
|
||||
if (tx.objectSpace === core.space.Model) {
|
||||
this.hierarchy.tx(tx)
|
||||
await this.model.tx(tx)
|
||||
|
@ -66,7 +66,6 @@ class Connection implements ClientConnection {
|
||||
promise.resolve(resp.result)
|
||||
}
|
||||
} else {
|
||||
console.log('handle', resp)
|
||||
this.handler(resp.result as Tx)
|
||||
}
|
||||
}
|
||||
|
@ -900,6 +900,11 @@
|
||||
"packageName": "@anticrm/model-lead",
|
||||
"projectFolder": "models/lead",
|
||||
"shouldPublish": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"packageName": "@anticrm/generator",
|
||||
"projectFolder": "dev/generator",
|
||||
"shouldPublish": false
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -14,8 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage, TxBulkWrite, TxResult, TxCollectionCUD, AttachedDoc } from '@anticrm/core'
|
||||
import core, { Hierarchy, DOMAIN_TX, ModelDb, TxFactory } from '@anticrm/core'
|
||||
import core, { ServerStorage, Domain, Tx, TxCUD, Doc, Ref, Class, DocumentQuery, FindResult, FindOptions, Storage, TxBulkWrite, TxResult, TxCollectionCUD, AttachedDoc, DOMAIN_MODEL, Hierarchy, DOMAIN_TX, ModelDb, TxFactory } from '@anticrm/core'
|
||||
import type { FullTextAdapterFactory, FullTextAdapter } from './types'
|
||||
import { FullTextIndex } from './fulltext'
|
||||
import { Triggers } from './triggers'
|
||||
@ -112,6 +111,13 @@ class TServerStorage implements ServerStorage {
|
||||
const _id = colTx.objectId
|
||||
const _class = colTx.objectClass
|
||||
let attachedTo: Doc | undefined
|
||||
|
||||
// Skip model operations
|
||||
if (this.hierarchy.getDomain(_class) === DOMAIN_MODEL) {
|
||||
// We could not update increments for model classes
|
||||
return []
|
||||
}
|
||||
|
||||
if (colTx.tx._class === core.class.TxCreateDoc) {
|
||||
attachedTo = (await this.findAll(_class, { _id }))[0]
|
||||
const txFactory = new TxFactory(tx.modifiedBy)
|
||||
|
Loading…
Reference in New Issue
Block a user