mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-23 05:53:09 +03:00
Bitrix import fixes (#2722)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
78aa090ef5
commit
626fb36e7a
6
dev/prod/public/config-dev.json
Normal file
6
dev/prod/public/config-dev.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"ACCOUNTS_URL":"https://account.hc.engineering",
|
||||||
|
"COLLABORATOR_URL": "wss://collaborator.hc.engineering",
|
||||||
|
"UPLOAD_URL":"/files",
|
||||||
|
"MODEL_VERSION": null
|
||||||
|
}
|
@ -398,6 +398,7 @@ export function createModel (builder: Builder): void {
|
|||||||
key: '@applications',
|
key: '@applications',
|
||||||
label: recruit.string.Applications
|
label: recruit.string.Applications
|
||||||
},
|
},
|
||||||
|
'comments',
|
||||||
'$lookup.company',
|
'$lookup.company',
|
||||||
'$lookup.company.$lookup.channels',
|
'$lookup.company.$lookup.channels',
|
||||||
'location',
|
'location',
|
||||||
@ -427,6 +428,7 @@ export function createModel (builder: Builder): void {
|
|||||||
key: '@applications',
|
key: '@applications',
|
||||||
label: recruit.string.Applications
|
label: recruit.string.Applications
|
||||||
},
|
},
|
||||||
|
'comments',
|
||||||
'$lookup.channels',
|
'$lookup.channels',
|
||||||
{
|
{
|
||||||
key: '@applications.modifiedOn',
|
key: '@applications.modifiedOn',
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
import { getResource, IntlString } from '@hcengineering/platform'
|
import { getResource, IntlString } from '@hcengineering/platform'
|
||||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import { Component, Grid, IconActivity, Label, Scroller, Button, showPopup } from '@hcengineering/ui'
|
import { Component, Grid, IconActivity, Label, Scroller, Button, showPopup, Spinner } from '@hcengineering/ui'
|
||||||
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
|
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
|
||||||
import TxView from './TxView.svelte'
|
import TxView from './TxView.svelte'
|
||||||
import { filterCollectionTxes } from '../utils'
|
import { filterCollectionTxes } from '../utils'
|
||||||
@ -78,11 +78,18 @@
|
|||||||
|
|
||||||
$: viewlets = new Map(allViewlets.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
$: viewlets = new Map(allViewlets.map((r) => [activityKey(r.objectClass, r.txClass), r]))
|
||||||
|
|
||||||
|
let loading = false
|
||||||
|
|
||||||
function updateTxes (object: Doc): void {
|
function updateTxes (object: Doc): void {
|
||||||
|
loading = true
|
||||||
activityQuery.update(
|
activityQuery.update(
|
||||||
object,
|
object,
|
||||||
(result) => {
|
(result) => {
|
||||||
txes = filterCollectionTxes(result)
|
txes = filterCollectionTxes(result)
|
||||||
|
|
||||||
|
if (txes.length > 0) {
|
||||||
|
loading = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SortingOrder.Descending,
|
SortingOrder.Descending,
|
||||||
editableMap ?? new Map()
|
editableMap ?? new Map()
|
||||||
@ -141,7 +148,14 @@
|
|||||||
<div class="ac-header short mirror-tool highlight">
|
<div class="ac-header short mirror-tool highlight">
|
||||||
<div class="ac-header__wrap-title">
|
<div class="ac-header__wrap-title">
|
||||||
<div class="flex-center icon"><IconActivity size={'small'} /></div>
|
<div class="flex-center icon"><IconActivity size={'small'} /></div>
|
||||||
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>
|
<span class="ac-header__title flex-row-center">
|
||||||
|
<Label label={activity.string.Activity} />
|
||||||
|
{#if loading}
|
||||||
|
<div class="ml-1">
|
||||||
|
<Spinner size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -173,7 +187,14 @@
|
|||||||
<!-- <div class="antiDivider" style:margin={'1rem -1.5rem'} /> -->
|
<!-- <div class="antiDivider" style:margin={'1rem -1.5rem'} /> -->
|
||||||
<div class="antiSection-header mt-6">
|
<div class="antiSection-header mt-6">
|
||||||
<div class="antiSection-header__icon"><IconActivity size={'small'} /></div>
|
<div class="antiSection-header__icon"><IconActivity size={'small'} /></div>
|
||||||
<span class="antiSection-header__title"><Label label={activity.string.Activity} /></span>
|
<span class="antiSection-header__title flex-row-center">
|
||||||
|
<Label label={activity.string.Activity} />
|
||||||
|
{#if loading}
|
||||||
|
<div class="ml-1">
|
||||||
|
<Spinner size={'small'} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
{#if selectedFilter === 'All'}
|
{#if selectedFilter === 'All'}
|
||||||
<span class="antiSection-header__tag highlight"><Label label={activityPlg.string.All} /></span>
|
<span class="antiSection-header__tag highlight"><Label label={activityPlg.string.All} /></span>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hcengineering/bitrix",
|
"name": "@hcengineering/bitrix",
|
||||||
"version": "0.6.24",
|
"version": "0.6.26",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"author": "Anticrm Platform Contributors",
|
"author": "Anticrm Platform Contributors",
|
||||||
"license": "EPL-2.0",
|
"license": "EPL-2.0",
|
||||||
|
@ -115,7 +115,6 @@ export async function syncDocument (
|
|||||||
mixins[bitrix.mixin.BitrixSyncDoc] = {
|
mixins[bitrix.mixin.BitrixSyncDoc] = {
|
||||||
type: resultDoc.document.type,
|
type: resultDoc.document.type,
|
||||||
bitrixId: resultDoc.document.bitrixId,
|
bitrixId: resultDoc.document.bitrixId,
|
||||||
rawData: resultDoc.rawData,
|
|
||||||
syncTime: Date.now()
|
syncTime: Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,13 +155,18 @@ export async function syncDocument (
|
|||||||
await syncClass(applyOp, gmail.class.Message, resultDoc.gmailDocuments, idMapping, emailReadId)
|
await syncClass(applyOp, gmail.class.Message, resultDoc.gmailDocuments, idMapping, emailReadId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const attachIds = Array.from(
|
||||||
|
new Set(resultDoc.blobs.map((it) => idMapping.get(it[0].attachedTo) ?? it[0].attachedTo)).values()
|
||||||
|
)
|
||||||
|
|
||||||
const existingBlobs = await client.findAll(attachment.class.Attachment, {
|
const existingBlobs = await client.findAll(attachment.class.Attachment, {
|
||||||
attachedTo: resultDoc.document._id
|
attachedTo: { $in: [resultDoc.document._id, ...attachIds] }
|
||||||
})
|
})
|
||||||
for (const [ed, op, upd] of resultDoc.blobs) {
|
for (const [ed, op, upd] of resultDoc.blobs) {
|
||||||
const existing = existingBlobs.find(
|
const existing = existingBlobs.find((it) => {
|
||||||
(it) => hierarchy.as<Doc, BitrixSyncDoc>(it, bitrix.mixin.BitrixSyncDoc).bitrixId === ed.bitrixId
|
const bdoc = hierarchy.as<Doc, BitrixSyncDoc>(it, bitrix.mixin.BitrixSyncDoc)
|
||||||
)
|
return bdoc.bitrixId === ed.bitrixId
|
||||||
|
})
|
||||||
// For Attachments, just do it once per attachment and assume it is not changed.
|
// For Attachments, just do it once per attachment and assume it is not changed.
|
||||||
if (existing === undefined) {
|
if (existing === undefined) {
|
||||||
const attachmentId: Ref<Attachment> = generateId()
|
const attachmentId: Ref<Attachment> = generateId()
|
||||||
@ -243,9 +247,10 @@ export async function syncDocument (
|
|||||||
// Update document id, for existing document.
|
// Update document id, for existing document.
|
||||||
valValue.attachedTo = resultDoc.document._id
|
valValue.attachedTo = resultDoc.document._id
|
||||||
}
|
}
|
||||||
const existingIdx = existingByClass.findIndex(
|
const existingIdx = existingByClass.findIndex((it) => {
|
||||||
(it) => hierarchy.as<Doc, BitrixSyncDoc>(it, bitrix.mixin.BitrixSyncDoc).bitrixId === valValue.bitrixId
|
const bdoc = hierarchy.as<Doc, BitrixSyncDoc>(it, bitrix.mixin.BitrixSyncDoc)
|
||||||
)
|
return bdoc.bitrixId === valValue.bitrixId && bdoc.type === valValue.type
|
||||||
|
})
|
||||||
let existing: Doc | undefined
|
let existing: Doc | undefined
|
||||||
if (existingIdx >= 0) {
|
if (existingIdx >= 0) {
|
||||||
existing = existingByClass.splice(existingIdx, 1).shift()
|
existing = existingByClass.splice(existingIdx, 1).shift()
|
||||||
@ -277,15 +282,14 @@ export async function syncDocument (
|
|||||||
existingM,
|
existingM,
|
||||||
{
|
{
|
||||||
type: valValue.type,
|
type: valValue.type,
|
||||||
bitrixId: valValue.bitrixId,
|
bitrixId: valValue.bitrixId
|
||||||
rawData: valValue.rawData
|
|
||||||
},
|
},
|
||||||
bitrix.mixin.BitrixSyncDoc,
|
bitrix.mixin.BitrixSyncDoc,
|
||||||
valValue.modifiedBy,
|
valValue.modifiedBy,
|
||||||
valValue.modifiedOn
|
valValue.modifiedOn
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
const { bitrixId, rawData, ...data } = valValue
|
const { bitrixId, ...data } = valValue
|
||||||
await applyOp.addCollection<Doc, AttachedDoc>(
|
await applyOp.addCollection<Doc, AttachedDoc>(
|
||||||
valValue._class,
|
valValue._class,
|
||||||
valValue.space,
|
valValue.space,
|
||||||
@ -305,8 +309,7 @@ export async function syncDocument (
|
|||||||
bitrix.mixin.BitrixSyncDoc,
|
bitrix.mixin.BitrixSyncDoc,
|
||||||
{
|
{
|
||||||
type: valValue.type,
|
type: valValue.type,
|
||||||
bitrixId: valValue.bitrixId,
|
bitrixId: valValue.bitrixId
|
||||||
rawData: valValue.rawData
|
|
||||||
},
|
},
|
||||||
valValue.modifiedOn,
|
valValue.modifiedOn,
|
||||||
valValue.modifiedBy
|
valValue.modifiedBy
|
||||||
@ -322,7 +325,7 @@ export async function syncDocument (
|
|||||||
return (await updateDoc(applyOp, existing, resultDoc.document, resultDoc.document.modifiedOn)) as BitrixSyncDoc
|
return (await updateDoc(applyOp, existing, resultDoc.document, resultDoc.document.modifiedOn)) as BitrixSyncDoc
|
||||||
// Go over extra documents.
|
// Go over extra documents.
|
||||||
} else {
|
} else {
|
||||||
const { bitrixId, rawData, ...data } = resultDoc.document
|
const { bitrixId, ...data } = resultDoc.document
|
||||||
const id = await applyOp.createDoc<Doc>(
|
const id = await applyOp.createDoc<Doc>(
|
||||||
resultDoc.document._class,
|
resultDoc.document._class,
|
||||||
resultDoc.document.space,
|
resultDoc.document.space,
|
||||||
@ -499,7 +502,7 @@ async function doPerformSync (ops: SyncOptions & SyncOptionsExtra): Promise<Bitr
|
|||||||
|
|
||||||
let added = 0
|
let added = 0
|
||||||
|
|
||||||
const sel = ['*', 'UF_*', 'EMAIL', 'IM']
|
const sel = ['*', 'UF_*', 'EMAIL', 'IM', 'WEB']
|
||||||
|
|
||||||
const allTagElements = await ops.client.findAll<TagElement>(tags.class.TagElement, {})
|
const allTagElements = await ops.client.findAll<TagElement>(tags.class.TagElement, {})
|
||||||
|
|
||||||
@ -520,7 +523,8 @@ async function doPerformSync (ops: SyncOptions & SyncOptionsExtra): Promise<Bitr
|
|||||||
const syncTime = Date.now()
|
const syncTime = Date.now()
|
||||||
|
|
||||||
const existingDocuments = await ops.client.findAll<Doc>(ops.mapping.ofClass, {
|
const existingDocuments = await ops.client.findAll<Doc>(ops.mapping.ofClass, {
|
||||||
[bitrix.mixin.BitrixSyncDoc + '.bitrixId']: { $in: toProcess.map((it) => `${it.ID as string}`) }
|
[bitrix.mixin.BitrixSyncDoc + '.bitrixId']: { $in: toProcess.map((it) => `${it.ID as string}`) },
|
||||||
|
[bitrix.mixin.BitrixSyncDoc + '.type']: ops.mapping.type
|
||||||
})
|
})
|
||||||
const defaultCategories = await ops.client.findAll(tags.class.TagCategory, {
|
const defaultCategories = await ops.client.findAll(tags.class.TagCategory, {
|
||||||
default: true
|
default: true
|
||||||
@ -537,7 +541,7 @@ async function doPerformSync (ops: SyncOptions & SyncOptionsExtra): Promise<Bitr
|
|||||||
if (existingDoc !== undefined) {
|
if (existingDoc !== undefined) {
|
||||||
const bd = ops.client.getHierarchy().as(existingDoc, bitrix.mixin.BitrixSyncDoc)
|
const bd = ops.client.getHierarchy().as(existingDoc, bitrix.mixin.BitrixSyncDoc)
|
||||||
if (bd.syncTime !== undefined && bd.syncTime + (ops.syncPeriod ?? defaultSyncPeriod) > syncTime) {
|
if (bd.syncTime !== undefined && bd.syncTime + (ops.syncPeriod ?? defaultSyncPeriod) > syncTime) {
|
||||||
// No need to sync, sime sync time is not yet arrived.
|
// No need to sync, same sync time is not yet arrived.
|
||||||
toProcess.splice(0, 1)
|
toProcess.splice(0, 1)
|
||||||
added++
|
added++
|
||||||
ops.monitor?.(result.total)
|
ops.monitor?.(result.total)
|
||||||
@ -657,13 +661,12 @@ async function performOrganizationContactSynchronization (
|
|||||||
console.log('total', total)
|
console.log('total', total)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const existingContacts = await ops.client.findAll(contact.class.Member, {
|
const existingMembers = await ops.client.findAll(contact.class.Member, {
|
||||||
attachedTo: extra.res.document._id,
|
attachedTo: extra.res.document._id
|
||||||
contact: { $in: contacts.map((it) => it._id as unknown as Ref<Contact>) }
|
|
||||||
})
|
})
|
||||||
for (const c of contacts) {
|
for (const c of contacts) {
|
||||||
const ex = existingContacts.find((e) => e.contact === (c._id as unknown as Ref<Contact>))
|
const ex = existingMembers.findIndex((e) => e.contact === (c._id as unknown as Ref<Contact>))
|
||||||
if (ex === undefined) {
|
if (ex === -1) {
|
||||||
await ops.client.addCollection(
|
await ops.client.addCollection(
|
||||||
contact.class.Member,
|
contact.class.Member,
|
||||||
extra.res.document.space,
|
extra.res.document.space,
|
||||||
@ -674,8 +677,15 @@ async function performOrganizationContactSynchronization (
|
|||||||
contact: c._id as unknown as Ref<Contact>
|
contact: c._id as unknown as Ref<Contact>
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
// remove from list
|
||||||
|
existingMembers.splice(ex, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove not expected members
|
||||||
|
for (const ex of existingMembers) {
|
||||||
|
await ops.client.remove(ex)
|
||||||
|
}
|
||||||
|
|
||||||
// We need to create Member's for organization contacts.
|
// We need to create Member's for organization contacts.
|
||||||
}
|
}
|
||||||
@ -718,7 +728,6 @@ async function downloadComments (
|
|||||||
message: processComment(it.COMMENT as string),
|
message: processComment(it.COMMENT as string),
|
||||||
bitrixId: `${it.ID as string}`,
|
bitrixId: `${it.ID as string}`,
|
||||||
type: it.ENTITY_TYPE,
|
type: it.ENTITY_TYPE,
|
||||||
rawData: it,
|
|
||||||
attachedTo: res.document._id,
|
attachedTo: res.document._id,
|
||||||
attachedToClass: res.document._class,
|
attachedToClass: res.document._class,
|
||||||
collection: 'comments',
|
collection: 'comments',
|
||||||
@ -796,7 +805,6 @@ async function downloadComments (
|
|||||||
sendOn: new Date(comm.CREATED ?? new Date().toString()).getTime(),
|
sendOn: new Date(comm.CREATED ?? new Date().toString()).getTime(),
|
||||||
subject: comm.SUBJECT,
|
subject: comm.SUBJECT,
|
||||||
bitrixId: `${comm.ID}`,
|
bitrixId: `${comm.ID}`,
|
||||||
rawData: comm,
|
|
||||||
from: comm.SETTINGS?.EMAIL_META?.from ?? '',
|
from: comm.SETTINGS?.EMAIL_META?.from ?? '',
|
||||||
to: comm.SETTINGS?.EMAIL_META?.to ?? '',
|
to: comm.SETTINGS?.EMAIL_META?.to ?? '',
|
||||||
replyTo: comm.SETTINGS?.EMAIL_META?.replyTo ?? comm.SETTINGS?.MESSAGE_HEADERS?.['Reply-To'] ?? '',
|
replyTo: comm.SETTINGS?.EMAIL_META?.replyTo ?? comm.SETTINGS?.MESSAGE_HEADERS?.['Reply-To'] ?? '',
|
||||||
|
@ -89,8 +89,6 @@ export interface BitrixSyncDoc extends Doc {
|
|||||||
type?: string
|
type?: string
|
||||||
bitrixId: string
|
bitrixId: string
|
||||||
syncTime?: number
|
syncTime?: number
|
||||||
// raw bitrix document data.
|
|
||||||
rawData?: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +65,6 @@ export interface BitrixSyncRequest {
|
|||||||
*/
|
*/
|
||||||
export interface ConvertResult {
|
export interface ConvertResult {
|
||||||
document: BitrixSyncDoc // Document we should sync
|
document: BitrixSyncDoc // Document we should sync
|
||||||
rawData: any
|
|
||||||
mixins: Record<Ref<Mixin<Doc>>, Data<Doc>> // Mixins of document we will sync
|
mixins: Record<Ref<Mixin<Doc>>, Data<Doc>> // Mixins of document we will sync
|
||||||
extraDocs: Doc[] // Extra documents we will sync, etc.
|
extraDocs: Doc[] // Extra documents we will sync, etc.
|
||||||
extraSync: (AttachedDoc & BitrixSyncDoc)[] // Extra documents we will sync, etc.
|
extraSync: (AttachedDoc & BitrixSyncDoc)[] // Extra documents we will sync, etc.
|
||||||
@ -278,20 +277,26 @@ export async function convert (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const c: Channel & BitrixSyncDoc = {
|
const existingC = newExtraSyncDocs
|
||||||
_id: generateId(),
|
.filter((it) => it._class === contact.class.Channel)
|
||||||
_class: contact.class.Channel,
|
.map((it) => it as unknown as Channel)
|
||||||
attachedTo: document._id,
|
.find((it) => it.value === svalue)
|
||||||
attachedToClass: attr.attributeOf,
|
if (existingC === undefined) {
|
||||||
collection: attr.name,
|
const c: Channel & BitrixSyncDoc = {
|
||||||
modifiedBy: document.modifiedBy,
|
_id: generateId(),
|
||||||
value: svalue,
|
_class: contact.class.Channel,
|
||||||
provider: f.provider,
|
attachedTo: document._id,
|
||||||
space: document.space,
|
attachedToClass: attr.attributeOf,
|
||||||
modifiedOn: document.modifiedOn,
|
collection: attr.name,
|
||||||
bitrixId: svalue
|
modifiedBy: document.modifiedBy,
|
||||||
|
value: svalue,
|
||||||
|
provider: f.provider,
|
||||||
|
space: document.space,
|
||||||
|
modifiedOn: document.modifiedOn,
|
||||||
|
bitrixId: svalue
|
||||||
|
}
|
||||||
|
newExtraSyncDocs.push(c)
|
||||||
}
|
}
|
||||||
newExtraSyncDocs.push(c)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -484,7 +489,6 @@ export async function convert (
|
|||||||
extraSync: newExtraSyncDocs,
|
extraSync: newExtraSyncDocs,
|
||||||
extraDocs: newExtraDocs,
|
extraDocs: newExtraDocs,
|
||||||
blobs,
|
blobs,
|
||||||
rawData: rawDocument,
|
|
||||||
syncRequests,
|
syncRequests,
|
||||||
gmailDocuments: []
|
gmailDocuments: []
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,13 @@
|
|||||||
if (ev.detail.action !== undefined && Array.isArray(value)) {
|
if (ev.detail.action !== undefined && Array.isArray(value)) {
|
||||||
const action = await getResource(ev.detail.action as ViewAction)
|
const action = await getResource(ev.detail.action as ViewAction)
|
||||||
const channel = value.find((it) => it.value === ev.detail.value)
|
const channel = value.find((it) => it.value === ev.detail.value)
|
||||||
if (action !== undefined && channel !== undefined) {
|
if (action != null && channel != null) {
|
||||||
action(channel, ev)
|
action(channel, ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ChannelsDropdown bind:value {length} {kind} {size} {shape} {editable} on:open={_open} />
|
{#if value}
|
||||||
|
<ChannelsDropdown bind:value {length} {kind} {size} {shape} {editable} on:open={_open} />
|
||||||
|
{/if}
|
||||||
|
Loading…
Reference in New Issue
Block a user