From 6a7d9e3bdab8e4c28ef57022a26a38b80603f2c9 Mon Sep 17 00:00:00 2001
From: Andrey Sobolev <haiodo@users.noreply.github.com>
Date: Mon, 23 Dec 2024 17:54:09 +0700
Subject: [PATCH] UBERF-8993: Fix handling of known errors (#7526)

---
 packages/platform/src/platform.ts          |  1 +
 packages/presentation/src/pipeline.ts      | 19 +++++++++++++++++--
 plugins/client-resources/src/connection.ts |  7 ++++---
 plugins/login-resources/src/utils.ts       |  6 +++++-
 server/account/src/operations.ts           |  6 ++++++
 5 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/packages/platform/src/platform.ts b/packages/platform/src/platform.ts
index 29ff120300..ec85cb5687 100644
--- a/packages/platform/src/platform.ts
+++ b/packages/platform/src/platform.ts
@@ -131,6 +131,7 @@ export default plugin(platformId, {
     BadError: '' as StatusCode,
     UnknownError: '' as StatusCode<{ message: string }>,
     InvalidId: '' as StatusCode<{ id: string }>,
+    ConnectionClosed: '' as StatusCode,
 
     LoadingPlugin: '' as StatusCode<{ plugin: string }>,
     NoLocationForPlugin: '' as StatusCode<{ plugin: Plugin }>,
diff --git a/packages/presentation/src/pipeline.ts b/packages/presentation/src/pipeline.ts
index cd75ef2672..4dc23a0470 100644
--- a/packages/presentation/src/pipeline.ts
+++ b/packages/presentation/src/pipeline.ts
@@ -18,7 +18,7 @@ import {
   type TxResult,
   type WithLookup
 } from '@hcengineering/core'
-import { setPlatformStatus, unknownError, type Resource } from '@hcengineering/platform'
+import platform, { PlatformError, setPlatformStatus, unknownError, type Resource } from '@hcengineering/platform'
 
 /**
  * @public
@@ -112,7 +112,12 @@ export class PresentationPipelineImpl implements PresentationPipeline {
       return this.head !== undefined
         ? await this.head.findAll(_class, query, options)
         : await this.client.findAll(_class, query, options)
-    } catch (err) {
+    } catch (err: any) {
+      if (err instanceof PlatformError) {
+        if (err.status.code === platform.status.ConnectionClosed) {
+          return toFindResult([], -1)
+        }
+      }
       Analytics.handleError(err as Error)
       const status = unknownError(err)
       await setPlatformStatus(status)
@@ -134,6 +139,11 @@ export class PresentationPipelineImpl implements PresentationPipeline {
         ? await this.head.findOne(_class, query, options)
         : await this.client.findOne(_class, query, options)
     } catch (err) {
+      if (err instanceof PlatformError) {
+        if (err.status.code === platform.status.ConnectionClosed) {
+          return
+        }
+      }
       Analytics.handleError(err as Error)
       const status = unknownError(err)
       await setPlatformStatus(status)
@@ -163,6 +173,11 @@ export class PresentationPipelineImpl implements PresentationPipeline {
         return await this.head.tx(tx)
       }
     } catch (err) {
+      if (err instanceof PlatformError) {
+        if (err.status.code === platform.status.ConnectionClosed) {
+          return {}
+        }
+      }
       Analytics.handleError(err as Error)
       const status = unknownError(err)
       await setPlatformStatus(status)
diff --git a/plugins/client-resources/src/connection.ts b/plugins/client-resources/src/connection.ts
index aca8d47ea4..6c74eedcbc 100644
--- a/plugins/client-resources/src/connection.ts
+++ b/plugins/client-resources/src/connection.ts
@@ -50,10 +50,11 @@ import core, {
 } from '@hcengineering/core'
 import platform, {
   PlatformError,
+  Severity,
+  Status,
   UNAUTHORIZED,
   broadcastEvent,
-  getMetadata,
-  unknownError
+  getMetadata
 } from '@hcengineering/platform'
 
 import { HelloRequest, HelloResponse, RPCHandler, ReqId, type Response } from '@hcengineering/rpc'
@@ -551,7 +552,7 @@ class Connection implements ClientConnection {
   }): Promise<any> {
     return this.ctx.newChild('send-request', {}).with(data.method, {}, async (ctx) => {
       if (this.closed) {
-        throw new PlatformError(unknownError('connection closed'))
+        throw new PlatformError(new Status(Severity.ERROR, platform.status.ConnectionClosed, {}))
       }
 
       if (data.once === true) {
diff --git a/plugins/login-resources/src/utils.ts b/plugins/login-resources/src/utils.ts
index 60d7f0df31..b156067923 100644
--- a/plugins/login-resources/src/utils.ts
+++ b/plugins/login-resources/src/utils.ts
@@ -16,7 +16,7 @@
 import { Analytics } from '@hcengineering/analytics'
 import { AccountRole, concatLink, type BaseWorkspaceInfo, type Doc, type Ref } from '@hcengineering/core'
 import { loginId, type LoginInfo, type OtpInfo, type Workspace, type WorkspaceLoginInfo } from '@hcengineering/login'
-import {
+import platform, {
   OK,
   PlatformError,
   Severity,
@@ -1058,6 +1058,10 @@ export async function restorePassword (token: string, password: string): Promise
 }
 
 async function handleStatusError (message: string, err: Status): Promise<void> {
+  if (err.code === platform.status.InvalidPassword || err.code === platform.status.AccountNotFound) {
+    // No need to send to analytics
+    return
+  }
   const label = await translate(err.code, err.params, 'en')
   Analytics.handleError(new Error(`${message}: ${label}`))
 }
diff --git a/server/account/src/operations.ts b/server/account/src/operations.ts
index c35e5b0126..6b596f92ec 100644
--- a/server/account/src/operations.ts
+++ b/server/account/src/operations.ts
@@ -2637,6 +2637,12 @@ function wrap (
             error: new Status(Severity.ERROR, platform.status.Unauthorized, {})
           }
         }
+        if (status.code === platform.status.InvalidPassword || status.code === platform.status.AccountNotFound) {
+          ctx.warn('error', { status: status.code, err: err.message })
+          return {
+            error: status
+          }
+        }
         if (status.code === platform.status.InternalServerError) {
           Analytics.handleError(err)
           ctx.error('error', { status, err })