mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 04:08:19 +00:00
Remove duplicated directs (#6516)
This commit is contained in:
parent
1daec4def4
commit
42abc31ab4
@ -74,7 +74,10 @@ export { chunterOperation } from './migration'
|
|||||||
export const DOMAIN_CHUNTER = 'chunter' as Domain
|
export const DOMAIN_CHUNTER = 'chunter' as Domain
|
||||||
|
|
||||||
@Model(chunter.class.ChunterSpace, core.class.Space)
|
@Model(chunter.class.ChunterSpace, core.class.Space)
|
||||||
export class TChunterSpace extends TSpace implements ChunterSpace {}
|
export class TChunterSpace extends TSpace implements ChunterSpace {
|
||||||
|
@Prop(PropCollection(activity.class.ActivityMessage), chunter.string.Messages)
|
||||||
|
messages?: number
|
||||||
|
}
|
||||||
|
|
||||||
@Model(chunter.class.Channel, chunter.class.ChunterSpace)
|
@Model(chunter.class.Channel, chunter.class.ChunterSpace)
|
||||||
@UX(chunter.string.Channel, chunter.icon.Hashtag, undefined, undefined, undefined, chunter.string.Channels)
|
@UX(chunter.string.Channel, chunter.icon.Hashtag, undefined, undefined, undefined, chunter.string.Channels)
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { chunterId, type ThreadMessage } from '@hcengineering/chunter'
|
import { chunterId, type DirectMessage, type ThreadMessage } from '@hcengineering/chunter'
|
||||||
import core, {
|
import core, {
|
||||||
type Account,
|
type Account,
|
||||||
TxOperations,
|
TxOperations,
|
||||||
@ -33,12 +33,13 @@ import {
|
|||||||
} from '@hcengineering/model'
|
} from '@hcengineering/model'
|
||||||
import activity, { migrateMessagesSpace, DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
import activity, { migrateMessagesSpace, DOMAIN_ACTIVITY } from '@hcengineering/model-activity'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import contactPlugin, { type PersonAccount } from '@hcengineering/contact'
|
import contactPlugin, { type Person, type PersonAccount } from '@hcengineering/contact'
|
||||||
import { DOMAIN_NOTIFICATION } from '@hcengineering/model-notification'
|
import { DOMAIN_DOC_NOTIFY, DOMAIN_NOTIFICATION } from '@hcengineering/model-notification'
|
||||||
|
import { type DocUpdateMessage } from '@hcengineering/activity'
|
||||||
|
import { DOMAIN_SPACE } from '@hcengineering/model-core'
|
||||||
|
|
||||||
import chunter from './plugin'
|
import chunter from './plugin'
|
||||||
import { DOMAIN_CHUNTER } from './index'
|
import { DOMAIN_CHUNTER } from './index'
|
||||||
import { type DocUpdateMessage } from '@hcengineering/activity'
|
|
||||||
|
|
||||||
export const DOMAIN_COMMENT = 'comment' as Domain
|
export const DOMAIN_COMMENT = 'comment' as Domain
|
||||||
|
|
||||||
@ -239,6 +240,53 @@ async function removeWrongActivity (client: MigrationClient): Promise<void> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function removeDuplicatedDirects (client: MigrationClient): Promise<void> {
|
||||||
|
const directs = await client.find<DirectMessage>(DOMAIN_SPACE, { _class: chunter.class.DirectMessage })
|
||||||
|
const personAccounts = await client.model.findAll<PersonAccount>(contactPlugin.class.PersonAccount, {})
|
||||||
|
const personByAccount = new Map(personAccounts.map((it) => [it._id, it.person]))
|
||||||
|
|
||||||
|
const accountsToPersons = (members: Ref<Account>[]): Ref<Person>[] => {
|
||||||
|
const personsSet = new Set(
|
||||||
|
members
|
||||||
|
.map((it) => personByAccount.get(it as Ref<PersonAccount>))
|
||||||
|
.filter((it): it is Ref<Person> => it !== undefined)
|
||||||
|
)
|
||||||
|
return Array.from(personsSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
const map: Map<string, DirectMessage[]> = new Map<string, DirectMessage[]>()
|
||||||
|
const toRemove: Ref<DirectMessage>[] = []
|
||||||
|
|
||||||
|
for (const direct of directs) {
|
||||||
|
const persons = accountsToPersons(direct.members)
|
||||||
|
|
||||||
|
if (persons.length === 0) {
|
||||||
|
toRemove.push(direct._id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = persons.sort().join(',')
|
||||||
|
|
||||||
|
if (!map.has(key)) {
|
||||||
|
map.set(key, [direct])
|
||||||
|
} else {
|
||||||
|
map.get(key)?.push(direct)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [, directs] of map) {
|
||||||
|
if (directs.length === 1) continue
|
||||||
|
const toSave = directs.reduce((acc, it) => ((it.messages ?? 0) > (acc.messages ?? 0) ? it : acc), directs[0])
|
||||||
|
const rest = directs.filter((it) => it._id !== toSave._id)
|
||||||
|
toRemove.push(...rest.map((it) => it._id))
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.deleteMany(DOMAIN_SPACE, { _id: { $in: toRemove } })
|
||||||
|
await client.deleteMany(DOMAIN_ACTIVITY, { attachedTo: { $in: toRemove } })
|
||||||
|
await client.deleteMany(DOMAIN_ACTIVITY, { objectId: { $in: toRemove } })
|
||||||
|
await client.deleteMany(DOMAIN_DOC_NOTIFY, { objectId: { $in: toRemove } })
|
||||||
|
}
|
||||||
|
|
||||||
export const chunterOperation: MigrateOperation = {
|
export const chunterOperation: MigrateOperation = {
|
||||||
async migrate (client: MigrationClient): Promise<void> {
|
async migrate (client: MigrationClient): Promise<void> {
|
||||||
await tryMigrate(client, chunterId, [
|
await tryMigrate(client, chunterId, [
|
||||||
@ -283,6 +331,12 @@ export const chunterOperation: MigrateOperation = {
|
|||||||
func: async (client) => {
|
func: async (client) => {
|
||||||
await removeWrongActivity(client)
|
await removeWrongActivity(client)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: 'remove-duplicated-directs-v1',
|
||||||
|
func: async (client) => {
|
||||||
|
await removeDuplicatedDirects(client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
@ -17,9 +17,9 @@
|
|||||||
import { deepEqual } from 'fast-equals'
|
import { deepEqual } from 'fast-equals'
|
||||||
|
|
||||||
import { DirectMessage } from '@hcengineering/chunter'
|
import { DirectMessage } from '@hcengineering/chunter'
|
||||||
import contact, { Employee, PersonAccount } from '@hcengineering/contact'
|
import contact, { Employee, Person, PersonAccount } from '@hcengineering/contact'
|
||||||
import core, { getCurrentAccount, Ref } from '@hcengineering/core'
|
import core, { getCurrentAccount, Ref } from '@hcengineering/core'
|
||||||
import { SelectUsersPopup } from '@hcengineering/contact-resources'
|
import { personIdByAccountId, SelectUsersPopup } from '@hcengineering/contact-resources'
|
||||||
import notification from '@hcengineering/notification'
|
import notification from '@hcengineering/notification'
|
||||||
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
import presentation, { createQuery, getClient } from '@hcengineering/presentation'
|
||||||
import { Modal, showPopup } from '@hcengineering/ui'
|
import { Modal, showPopup } from '@hcengineering/ui'
|
||||||
@ -55,15 +55,31 @@
|
|||||||
const accIds = [myAcc._id, ...employeeAccounts.filter(({ _id }) => _id !== myAcc._id).map(({ _id }) => _id)].sort()
|
const accIds = [myAcc._id, ...employeeAccounts.filter(({ _id }) => _id !== myAcc._id).map(({ _id }) => _id)].sort()
|
||||||
|
|
||||||
const existingDms = await client.findAll(chunter.class.DirectMessage, {})
|
const existingDms = await client.findAll(chunter.class.DirectMessage, {})
|
||||||
|
const newDirectPersons = Array.from(new Set([...employeeIds, myAcc.person])).sort()
|
||||||
|
|
||||||
let direct: DirectMessage | undefined
|
let direct: DirectMessage | undefined
|
||||||
|
|
||||||
for (const dm of existingDms) {
|
for (const dm of existingDms) {
|
||||||
if (deepEqual(dm.members.sort(), accIds)) {
|
const existDirectPersons = Array.from(
|
||||||
|
new Set(dm.members.map((id) => $personIdByAccountId.get(id as Ref<PersonAccount>)))
|
||||||
|
)
|
||||||
|
.filter((person): person is Ref<Person> => person !== undefined)
|
||||||
|
.sort()
|
||||||
|
if (deepEqual(existDirectPersons, newDirectPersons)) {
|
||||||
direct = dm
|
direct = dm
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const existingMembers = direct?.members
|
||||||
|
const missingAccounts = existingMembers !== undefined ? accIds.filter((id) => !existingMembers.includes(id)) : []
|
||||||
|
|
||||||
|
if (direct !== undefined && missingAccounts.length > 0) {
|
||||||
|
await client.updateDoc(chunter.class.DirectMessage, direct.space, direct._id, {
|
||||||
|
members: [...direct.members, ...missingAccounts]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const dmId =
|
const dmId =
|
||||||
direct?._id ??
|
direct?._id ??
|
||||||
(await client.createDoc(chunter.class.DirectMessage, core.space.Space, {
|
(await client.createDoc(chunter.class.DirectMessage, core.space.Space, {
|
||||||
@ -75,12 +91,13 @@
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const context = await client.findOne(notification.class.DocNotifyContext, {
|
const context = await client.findOne(notification.class.DocNotifyContext, {
|
||||||
person: myAcc.person,
|
user: myAcc._id,
|
||||||
objectId: dmId,
|
objectId: dmId,
|
||||||
objectClass: chunter.class.DirectMessage
|
objectClass: chunter.class.DirectMessage
|
||||||
})
|
})
|
||||||
|
|
||||||
if (context !== undefined) {
|
if (context !== undefined) {
|
||||||
|
dispatch('close')
|
||||||
openChannel(dmId, chunter.class.DirectMessage)
|
openChannel(dmId, chunter.class.DirectMessage)
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -97,6 +114,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
openChannel(dmId, chunter.class.DirectMessage)
|
openChannel(dmId, chunter.class.DirectMessage)
|
||||||
|
dispatch('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCancel (): void {
|
function handleCancel (): void {
|
||||||
|
@ -25,7 +25,9 @@ import { Person, ChannelProvider as SocialChannelProvider } from '@hcengineering
|
|||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface ChunterSpace extends Space {}
|
export interface ChunterSpace extends Space {
|
||||||
|
messages?: number
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
|
@ -16,38 +16,38 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AvatarType,
|
AvatarType,
|
||||||
|
type Channel,
|
||||||
|
type ChannelProvider,
|
||||||
|
type Contact,
|
||||||
contactId,
|
contactId,
|
||||||
|
type Employee,
|
||||||
formatName,
|
formatName,
|
||||||
getFirstName,
|
getFirstName,
|
||||||
getLastName,
|
getLastName,
|
||||||
getName,
|
getName,
|
||||||
type Channel,
|
|
||||||
type ChannelProvider,
|
|
||||||
type Contact,
|
|
||||||
type Employee,
|
|
||||||
type Person,
|
type Person,
|
||||||
type PersonAccount
|
type PersonAccount
|
||||||
} from '@hcengineering/contact'
|
} from '@hcengineering/contact'
|
||||||
import core, {
|
import core, {
|
||||||
getCurrentAccount,
|
|
||||||
toIdMap,
|
|
||||||
type Account,
|
type Account,
|
||||||
|
AggregateValue,
|
||||||
|
AggregateValueData,
|
||||||
type Class,
|
type Class,
|
||||||
type Client,
|
type Client,
|
||||||
type Doc,
|
type Doc,
|
||||||
|
type DocumentQuery,
|
||||||
|
getCurrentAccount,
|
||||||
|
type Hierarchy,
|
||||||
type IdMap,
|
type IdMap,
|
||||||
|
matchQuery,
|
||||||
type ObjQueryType,
|
type ObjQueryType,
|
||||||
type Ref,
|
type Ref,
|
||||||
|
type Space,
|
||||||
type Timestamp,
|
type Timestamp,
|
||||||
|
toIdMap,
|
||||||
type TxOperations,
|
type TxOperations,
|
||||||
type UserStatus,
|
type UserStatus,
|
||||||
type WithLookup,
|
type WithLookup
|
||||||
AggregateValue,
|
|
||||||
type Space,
|
|
||||||
type Hierarchy,
|
|
||||||
type DocumentQuery,
|
|
||||||
AggregateValueData,
|
|
||||||
matchQuery
|
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import notification, { type DocNotifyContext, type InboxNotification } from '@hcengineering/notification'
|
import notification, { type DocNotifyContext, type InboxNotification } from '@hcengineering/notification'
|
||||||
import { getEmbeddedLabel, getResource, translate } from '@hcengineering/platform'
|
import { getEmbeddedLabel, getResource, translate } from '@hcengineering/platform'
|
||||||
@ -61,8 +61,8 @@ import {
|
|||||||
type ResolvedLocation,
|
type ResolvedLocation,
|
||||||
type TabItem
|
type TabItem
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import view, { type GrouppingManager, type Filter } from '@hcengineering/view'
|
import view, { type Filter, type GrouppingManager } from '@hcengineering/view'
|
||||||
import { FilterQuery, accessDeniedStore } from '@hcengineering/view-resources'
|
import { accessDeniedStore, FilterQuery } from '@hcengineering/view-resources'
|
||||||
import { derived, get, writable } from 'svelte/store'
|
import { derived, get, writable } from 'svelte/store'
|
||||||
|
|
||||||
import contact from './plugin'
|
import contact from './plugin'
|
||||||
@ -305,6 +305,10 @@ export const channelProviders = writable<ChannelProvider[]>([])
|
|||||||
|
|
||||||
export const personAccountPersonByIdStore = writable<IdMap<WithLookup<Person>>>(new Map())
|
export const personAccountPersonByIdStore = writable<IdMap<WithLookup<Person>>>(new Map())
|
||||||
|
|
||||||
|
export const personIdByAccountId = derived(personAccountByIdStore, (vals) => {
|
||||||
|
return new Map<Ref<PersonAccount>, Ref<Person>>(Array.from(vals.values()).map((it) => [it._id, it.person]))
|
||||||
|
})
|
||||||
|
|
||||||
export const statusByUserStore = writable<Map<Ref<Account>, UserStatus>>(new Map())
|
export const statusByUserStore = writable<Map<Ref<Account>, UserStatus>>(new Map())
|
||||||
|
|
||||||
export const personByIdStore = derived([personAccountPersonByIdStore, employeeByIdStore], (vals) => {
|
export const personByIdStore = derived([personAccountPersonByIdStore, employeeByIdStore], (vals) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user