From 1daec4def4396ef544fe57020d246629e3970f93 Mon Sep 17 00:00:00 2001
From: Andrey Sobolev <haiodo@users.noreply.github.com>
Date: Tue, 10 Sep 2024 22:59:38 +0700
Subject: [PATCH] UBERF-8060: Fix user statuses and workspace selection (#6512)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
---
 dev/prod/public/config-huly.json              | 23 +++++++++++++++++
 .../src/components/SelectWorkspace.svelte     | 25 ++++++++-----------
 server/backup/src/backup.ts                   | 13 +++++++---
 server/middleware/src/domainTx.ts             |  9 +------
 server/ws/src/server_http.ts                  |  9 +++++--
 5 files changed, 51 insertions(+), 28 deletions(-)
 create mode 100644 dev/prod/public/config-huly.json

diff --git a/dev/prod/public/config-huly.json b/dev/prod/public/config-huly.json
new file mode 100644
index 0000000000..b98b428b93
--- /dev/null
+++ b/dev/prod/public/config-huly.json
@@ -0,0 +1,23 @@
+{
+  "ACCOUNTS_URL": "https://account.huly.app/",
+  "UPLOAD_URL": "/files",
+  "FILES_URL": "/files/:workspace/:filename?file=:blobId&workspace=:workspace",
+  "REKONI_URL": "https://rekoni.huly.app",
+  "TELEGRAM_URL": "https://telegram.huly.app",
+  "GMAIL_URL": "https://gmail.huly.app/",
+  "CALENDAR_URL": "https://calendar.huly.app/",
+  "COLLABORATOR_URL": "wss://collaborator.huly.app",
+  "BRANDING_URL": "https://huly.app/huly-branding_v2.json",
+  "PREVIEW_CONFIG": "https://huly.app/files/:workspace?file=:blobId&size=:size",
+  "GITHUB_APP": "huly-for-github",
+  "GITHUB_CLIENTID": "Iv1.e263a087de0910e0",
+  "INTERCOM_APP_ID": "",
+  "INTERCOM_API_URL": "",
+  "GITHUB_URL": "https://github.huly.app",
+  "LIVEKIT_WS": "",
+  "LOVE_ENDPOINT": "https://love.huly.app/",
+  "SIGN_URL": "https://sign.huly.app",
+  "PRINT_URL": "https://print.huly.app",
+  "DESKTOP_UPDATES_CHANNEL": "huly",
+  "TELEGRAM_BOT_URL": "https://telegram-bot.huly.app"
+}
\ No newline at end of file
diff --git a/plugins/login-resources/src/components/SelectWorkspace.svelte b/plugins/login-resources/src/components/SelectWorkspace.svelte
index 5f6df4479c..3a7be1b650 100644
--- a/plugins/login-resources/src/components/SelectWorkspace.svelte
+++ b/plugins/login-resources/src/components/SelectWorkspace.svelte
@@ -16,51 +16,46 @@
 <script lang="ts">
   import { LoginInfo, Workspace } from '@hcengineering/login'
   import { OK, Severity, Status } from '@hcengineering/platform'
-  import presentation, { NavLink, isAdminUser } from '@hcengineering/presentation'
+  import presentation, { NavLink, isAdminUser, reduceCalls } from '@hcengineering/presentation'
   import {
     Button,
     Label,
     Scroller,
     SearchEdit,
     deviceOptionsStore as deviceInfo,
-    setMetadataLocalStorage
+    setMetadataLocalStorage,
+    ticker
   } from '@hcengineering/ui'
   import { onMount } from 'svelte'
   import login from '../plugin'
   import { getAccount, getHref, getWorkspaces, goTo, navigateToWorkspace, selectWorkspace } from '../utils'
   import StatusControl from './StatusControl.svelte'
 
-  const CHECK_INTERVAL = 1000
-
   export let navigateUrl: string | undefined = undefined
   let workspaces: Workspace[] = []
-  let flagToUpdateWorkspaces = false
 
   let status = OK
 
   let account: LoginInfo | undefined = undefined
 
+  let flagToUpdateWorkspaces = false
+
   async function loadAccount (): Promise<void> {
     account = await getAccount()
   }
 
-  async function updateWorkspaces (): Promise<void> {
+  const updateWorkspaces = reduceCalls(async function updateWorkspaces (time: number): Promise<void> {
     try {
       workspaces = await getWorkspaces()
     } catch (e) {
       // we should be able to continue from this state
     }
-    if (flagToUpdateWorkspaces) {
-      setTimeout(updateWorkspaces, CHECK_INTERVAL)
-    }
-  }
+  })
+
+  $: if (flagToUpdateWorkspaces) updateWorkspaces($ticker)
 
   onMount(() => {
     void loadAccount()
-
-    return () => {
-      flagToUpdateWorkspaces = false
-    }
   })
 
   async function select (workspace: string): Promise<void> {
@@ -81,8 +76,8 @@
       }
 
       workspaces = res
+      await updateWorkspaces(0)
       flagToUpdateWorkspaces = true
-      await updateWorkspaces()
     } catch (err: any) {
       setMetadataLocalStorage(login.metadata.LastToken, null)
       setMetadataLocalStorage(presentation.metadata.Token, null)
diff --git a/server/backup/src/backup.ts b/server/backup/src/backup.ts
index 8ae6740c4a..47162166b4 100644
--- a/server/backup/src/backup.ts
+++ b/server/backup/src/backup.ts
@@ -862,7 +862,7 @@ export async function backup (
             addedDocuments += descrJson.length
             addedDocuments += blob.size
 
-            printDownloaded(blob._id, descrJson.length)
+            printDownloaded('', descrJson.length)
             try {
               const buffers: Buffer[] = []
               await blobClient.writeTo(ctx, blob._id, blob.size, {
@@ -907,7 +907,7 @@ export async function backup (
                 })
               }
 
-              printDownloaded(blob._id, blob.size)
+              printDownloaded('', blob.size)
             } catch (err: any) {
               if (err.message?.startsWith('No file for') === true) {
                 ctx.error('failed to download blob', { message: err.message })
@@ -925,7 +925,7 @@ export async function backup (
               if (err != null) throw err
             })
             processChanges(d)
-            printDownloaded(d._id, data.length)
+            printDownloaded('', data.length)
           }
         }
       }
@@ -1141,6 +1141,9 @@ export async function restore (
   let uploaded = 0
 
   const printUploaded = (msg: string, size: number): void => {
+    if (size == null) {
+      return
+    }
     uploaded += size
     const newDownloadedMb = Math.round(uploaded / (1024 * 1024))
     const newId = Math.round(newDownloadedMb / 10)
@@ -1275,6 +1278,10 @@ export async function restore (
                     blobs.delete(name)
                     const doc = d?.doc as Blob
                     ;(doc as any)['%hash%'] = changeset.get(doc._id)
+                    let sz = doc.size
+                    if (Number.isNaN(sz) || sz !== bf.length) {
+                      sz = bf.length
+                    }
                     void blobClient.upload(ctx, doc._id, doc.size, doc.contentType, bf).then(() => {
                       void sendChunk(doc, bf.length).finally(() => {
                         requiredDocs.delete(doc._id)
diff --git a/server/middleware/src/domainTx.ts b/server/middleware/src/domainTx.ts
index 84bd5a6350..d8a62b8916 100644
--- a/server/middleware/src/domainTx.ts
+++ b/server/middleware/src/domainTx.ts
@@ -14,7 +14,6 @@
 //
 
 import core, {
-  DOMAIN_TRANSIENT,
   TxProcessor,
   type Doc,
   type Domain,
@@ -49,13 +48,7 @@ export class DomainTxMiddleware extends BaseMiddleware implements Middleware {
 
     for (const tx of txes) {
       if (TxProcessor.isExtendsCUD(tx._class)) {
-        const objectClass = (tx as TxCUD<Doc>).objectClass
-        if (
-          objectClass !== core.class.BenchmarkDoc &&
-          this.context.hierarchy.findDomain(objectClass) !== DOMAIN_TRANSIENT
-        ) {
-          txToStore.push(tx)
-        }
+        txToStore.push(tx)
       }
     }
     let result: TxMiddlewareResult = {}
diff --git a/server/ws/src/server_http.ts b/server/ws/src/server_http.ts
index b0c9095fb6..23a24fe7fd 100644
--- a/server/ws/src/server_http.ts
+++ b/server/ws/src/server_http.ts
@@ -158,7 +158,7 @@ export function startHttpServer (
             void sessions.profiling.stop().then((profile) => {
               ctx.warn(
                 '---------------------------------------------PROFILING SESSION STOPPED---------------------------------------------',
-                { profile }
+                {}
               )
               res.writeHead(200, { 'Content-Type': 'application/json' })
               res.end(profile ?? '{ error: "no profiling" }')
@@ -205,7 +205,12 @@ export function startHttpServer (
       const name = req.query.name as string
       const contentType = req.query.contentType as string
       const size = parseInt((req.query.size as string) ?? '-1')
-
+      if (Number.isNaN(size)) {
+        ctx.error('/api/v1/blob put error', { message: 'invalid NaN file size' })
+        res.writeHead(404, {})
+        res.end()
+        return
+      }
       ctx
         .with(
           'storage upload',