// // Copyright © 2020, 2021 Anticrm Platform Contributors. // Copyright © 2021, 2022 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 { Account, Class, Doc, getCurrentAccount, Ref } from '@hcengineering/core' import notification, { Collaborators, DocUpdates, NotificationClient } from '@hcengineering/notification' import { createQuery, getClient } from '@hcengineering/presentation' import { writable } from 'svelte/store' /** * @public */ export class NotificationClientImpl implements NotificationClient { protected static _instance: NotificationClientImpl | undefined = undefined readonly docUpdatesStore = writable, DocUpdates>>(new Map()) docUpdatesMap: Map, DocUpdates> = new Map() readonly docUpdates = writable([]) private readonly docUpdatesQuery = createQuery(true) private readonly user: Ref private constructor () { this.user = getCurrentAccount()._id this.docUpdatesQuery.query( notification.class.DocUpdates, { user: this.user }, (result) => { this.docUpdates.set(result) this.docUpdatesMap = new Map(result.map((p) => [p.attachedTo, p])) this.docUpdatesStore.set(this.docUpdatesMap) } ) } static createClient (): void { NotificationClientImpl._instance = new NotificationClientImpl() } static getClient (): NotificationClientImpl { if (NotificationClientImpl._instance === undefined) { NotificationClientImpl._instance = new NotificationClientImpl() } return NotificationClientImpl._instance } async read (_id: Ref): Promise { const client = getClient() const docUpdate = this.docUpdatesMap.get(_id) if (docUpdate !== undefined) { if (docUpdate.txes.some((p) => p.isNew)) { docUpdate.txes.forEach((p) => (p.isNew = false)) await client.update(docUpdate, { txes: docUpdate.txes }) } } } async forceRead (_id: Ref, _class: Ref>): Promise { const client = getClient() const docUpdate = this.docUpdatesMap.get(_id) if (docUpdate !== undefined) { if (docUpdate.txes.some((p) => p.isNew)) { docUpdate.txes.forEach((p) => (p.isNew = false)) await client.update(docUpdate, { txes: docUpdate.txes }) } } else { const doc = await client.findOne(_class, { _id }) if (doc !== undefined) { const hiearachy = client.getHierarchy() const collab = hiearachy.as(doc, notification.mixin.Collaborators) if (collab.collaborators === undefined) { await client.createMixin( collab._id, collab._class, collab.space, notification.mixin.Collaborators, { collaborators: [this.user] } ) } else if (!collab.collaborators.includes(this.user)) { await client.updateMixin(collab._id, collab._class, collab.space, notification.mixin.Collaborators, { $push: { collaborators: this.user } }) } await client.createDoc(notification.class.DocUpdates, doc.space, { attachedTo: _id, attachedToClass: _class, user: this.user, hidden: true, txes: [] }) } } } } /** * @public */ export async function hasntNotifications (object: DocUpdates): Promise { if (object._class !== notification.class.DocUpdates) return false return !object.txes.some((p) => p.isNew) } /** * @public */ export async function unsubscribe (object: DocUpdates): Promise { const me = getCurrentAccount()._id const client = getClient() const hierarchy = client.getHierarchy() const target = await client.findOne(object.attachedToClass, { _id: object.attachedTo }) if (target !== undefined) { if (hierarchy.hasMixin(target, notification.mixin.Collaborators)) { const collab = hierarchy.as(target, notification.mixin.Collaborators) if (collab.collaborators.includes(me)) { await client.updateMixin(collab._id, collab._class, collab.space, notification.mixin.Collaborators, { $pull: { collaborators: me } }) } } } await client.remove(object) } /** * @public */ export async function hide (object: DocUpdates | DocUpdates[]): Promise { const client = getClient() if (Array.isArray(object)) { for (const value of object) { await client.update(value, { hidden: true }) } } else { await client.update(object, { hidden: true }) } } /** * @public */ export async function markAsUnread (object: DocUpdates): Promise { const client = getClient() if (object.txes.length === 0) return const txes = object.txes txes[0].isNew = true await client.update(object, { txes }) }