Skip to content

feat: move grants to admin dashboard#100

Merged
lorenzocorallo merged 7 commits intomainfrom
remove-grants
Apr 12, 2026
Merged

feat: move grants to admin dashboard#100
lorenzocorallo merged 7 commits intomainfrom
remove-grants

Conversation

@lorenzocorallo
Copy link
Copy Markdown
Member

Grants can now be created through the admin dashboard with a easier UX.

@lorenzocorallo lorenzocorallo requested a review from toto04 April 12, 2026 11:51
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Removes the Telegram "grants" command and unregisters it from management; changes grant log payload to use an absolute until timestamp; adds WebSocket handlers for grant create/interrupt events and switches Socket.IO to use @socket.io/devalue-parser; updates dependencies.

Changes

Cohort / File(s) Summary
Grants Command Removal
src/commands/management/grants.ts
Deleted the interactive /grant command implementation (parsing, conversation UI, duration/start adjustments, grant creation mutation, and audit logging).
Management Collection Update
src/commands/management/index.ts
Removed grants from the management commands collection (withCollection(...)).
TgLogger types & formatting
src/modules/tg-logger/types.ts, src/modules/tg-logger/index.ts
Changed CREATE log payload shape from duration: Durationuntil: Date; updated logged message to display Valid until: props.until.
WebSocket handlers & client API
src/modules/websocket.ts
Added logGrantCreate and logGrantInterrupt socket events that resolve users from MessageUserStorage and call tgLogger.grants(...); switched Socket.IO to use @socket.io/devalue-parser; updated WebSocketClient generic to expose tgLogger module.
Dependencies
package.json
Bumped @polinetwork/backend ^0.15.11 → ^0.15.15 and added runtime dependency @socket.io/devalue-parser ^0.1.0.

Sequence Diagram(s)

sequenceDiagram
  participant WS as WebSocket Client
  participant Storage as MessageUserStorage
  participant Logger as TgLogger Module
  participant CB as Socket Callback

  WS->>WS: receive "logGrantCreate"(targetId, adminId, since, until, reason)
  WS->>Storage: getStoredUser(targetId)
  alt target missing
    Storage-->>WS: null
    WS->>CB: callback("target not found")
  else target found
    Storage-->>WS: targetUser
    WS->>Storage: getStoredUser(adminId)
    alt admin missing
      Storage-->>WS: null
      WS->>CB: callback("admin not found")
    else admin found
      Storage-->>WS: adminUser
      WS->>Logger: grants({action:"CREATE", target:targetUser, by:adminUser, since, until, reason})
      Logger-->>WS: result (ok / falsy)
      alt logger falsy
        WS->>CB: callback("logger failed")
      else logger ok
        WS->>CB: callback(null)
      end
    end
  end
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: removing the grants Telegram command implementation and updating the management collection, with related refactoring to use a dashboard instead.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lorenzocorallo lorenzocorallo changed the title chore: remove grants command feat: move grants to admin dashboard Apr 12, 2026
@lorenzocorallo lorenzocorallo enabled auto-merge (squash) April 12, 2026 13:19
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/websocket.ts`:
- Line 127: The log message in logGrantInterrupt is incorrectly labeled "grant
create log OK"; update the logger.debug call inside the logGrantInterrupt
function to use a correct success label (e.g., "grant interrupt log OK" or
similar) so successful interrupt handling is properly classified in logs; locate
the logger.debug invocation in logGrantInterrupt and change only the message
string to the accurate label.
- Around line 90-109: The websocket handler for "logGrantCreate" can throw
(e.g., in modules.get("tgLogger").grants or other awaits) and currently may
never call the ack cb; wrap the handler body (or at least the await
modules.get("tgLogger").grants call) in a try/catch and ensure cb(...) is always
invoked — on success call cb(null) and on any caught error call
cb(errorOrMessage) and log the error; apply the same change to the
"logGrantRevoke" handler so both handlers always acknowledge the websocket
request even when awaited calls throw (refer to this.io.on("logGrantCreate") /
this.io.on("logGrantRevoke"), MessageUserStorage.getInstance(), and
modules.get("tgLogger").grants).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1346289f-3074-46d7-93a8-846a7c12f5fd

📥 Commits

Reviewing files that changed from the base of the PR and between f853f49 and 8c7c588.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • package.json
  • src/modules/tg-logger/index.ts
  • src/modules/tg-logger/types.ts
  • src/modules/websocket.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/modules/websocket.ts (2)

91-93: Fetch users concurrently and reuse the storage instance.

Both handlers do two sequential lookups and call MessageUserStorage.getInstance() twice. Use one instance + Promise.all to reduce latency and duplication.

Refactor sketch
-      const target = await MessageUserStorage.getInstance().getStoredUser(userId)
-      const admin = await MessageUserStorage.getInstance().getStoredUser(adminId)
+      const storage = MessageUserStorage.getInstance()
+      const [target, admin] = await Promise.all([
+        storage.getStoredUser(userId),
+        storage.getStoredUser(adminId),
+      ])

Also applies to: 122-124

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/websocket.ts` around lines 91 - 93, Replace the two sequential
getStoredUser calls and duplicate getInstance() calls by calling
MessageUserStorage.getInstance() once and fetching both users concurrently with
Promise.all; specifically, obtain a single storage instance and then do
Promise.all([storage.getStoredUser(userId), storage.getStoredUser(adminId)]) and
check the results for falsy before proceeding. Apply the same change to the
other handler that currently repeats MessageUserStorage.getInstance() and
sequential lookups (the block around the second pair of getStoredUser calls).

99-109: Don’t swallow grant logger errors silently.

The .catch(() => null) path hides the original failure reason, which hurts debugging. Log the caught error before returning null.

Refactor sketch
-        .catch(() => null)
+        .catch((error) => {
+          logger.error({ error }, "[WS] grant create log ERROR -- tgLogger.grants failed")
+          return null
+        })
...
-        .catch(() => null)
+        .catch((error) => {
+          logger.error({ error }, "[WS] grant interrupt log ERROR -- tgLogger.grants failed")
+          return null
+        })

Also applies to: 130-137

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/websocket.ts` around lines 99 - 109, The current call to
modules.get("tgLogger").grants(...).catch(() => null) swallows errors; change
the catch to capture the error (e.g. .catch((err) => { /* log err */; return
null; })) and log the error before returning null — use the existing app logger
if available (e.g. processLogger.error or modules.get("processLogger").error),
or console.error as a fallback. Apply the same change to the second grants call
in the file (the other catch handling the grant response) so neither failure
path hides the original error details.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/websocket.ts`:
- Line 113: Replace the misspelled error string "Cannot send te log" with
"Cannot send the log" wherever it's passed to callback invocations in
src/modules/websocket.ts (the cb(...) calls that return the error message);
ensure both occurrences (the cb("Cannot send te log") usages) are updated to the
corrected string so callbacks return the proper message.

---

Nitpick comments:
In `@src/modules/websocket.ts`:
- Around line 91-93: Replace the two sequential getStoredUser calls and
duplicate getInstance() calls by calling MessageUserStorage.getInstance() once
and fetching both users concurrently with Promise.all; specifically, obtain a
single storage instance and then do Promise.all([storage.getStoredUser(userId),
storage.getStoredUser(adminId)]) and check the results for falsy before
proceeding. Apply the same change to the other handler that currently repeats
MessageUserStorage.getInstance() and sequential lookups (the block around the
second pair of getStoredUser calls).
- Around line 99-109: The current call to
modules.get("tgLogger").grants(...).catch(() => null) swallows errors; change
the catch to capture the error (e.g. .catch((err) => { /* log err */; return
null; })) and log the error before returning null — use the existing app logger
if available (e.g. processLogger.error or modules.get("processLogger").error),
or console.error as a fallback. Apply the same change to the second grants call
in the file (the other catch handling the grant response) so neither failure
path hides the original error details.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0dbf128c-730e-4b6f-a484-9ecbbcc5c691

📥 Commits

Reviewing files that changed from the base of the PR and between 4cbb001 and ca3b78d.

📒 Files selected for processing (1)
  • src/modules/websocket.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
src/modules/websocket.ts (2)

112-112: ⚠️ Potential issue | 🟡 Minor

Fix typo in callback error messages.

"Cannot send te log" should be "Cannot send the log".

Suggested fix
-        cb("Cannot send te log")
+        cb("Cannot send the log")
...
-        cb("Cannot send te log")
+        cb("Cannot send the log")

Also applies to: 139-139

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/websocket.ts` at line 112, Fix the typographical error in the
callback error message: replace the string "Cannot send te log" with "Cannot
send the log" wherever it's invoked (e.g., the cb(...) calls shown in
websocket.ts, including the other occurrence around the later cb call at line
~139). Update both instances so the callback error message is spelled correctly
and maintains the exact same phrasing in both locations.

90-118: ⚠️ Potential issue | 🟠 Major

Always guarantee websocket ack with a top-level try/catch in both grant handlers.

Right now only grants(...).catch(() => null) is guarded; unexpected throws in other awaited steps can still skip cb(...), leaving the ack hanging.

Suggested fix
 this.io.on("logGrantCreate", async ({ userId, adminId, validSince, validUntil, reason }, cb) => {
-  const target = await MessageUserStorage.getInstance().getStoredUser(userId)
-  const admin = await MessageUserStorage.getInstance().getStoredUser(adminId)
-  if (!target || !admin) {
-    logger.error("[WS] grant create log ERROR -- cannot retrieve users")
-    cb("Cannot retrieve the users")
-    return
-  }
-
-  const res = await this.getModule("tgLogger")
-    .grants({
-      action: "CREATE",
-      target: target,
-      by: admin,
-      since: validSince,
-      until: validUntil,
-      reason,
-    })
-    .catch(() => null)
-
-  if (!res) {
-    logger.error("[WS] grant create log ERROR -- cannot send log")
-    cb("Cannot send te log")
-    return
-  }
-
-  logger.debug("[WS] grant create log OK")
-  cb(null)
+  try {
+    const storage = MessageUserStorage.getInstance()
+    const [target, admin] = await Promise.all([storage.getStoredUser(userId), storage.getStoredUser(adminId)])
+    if (!target || !admin) {
+      logger.error("[WS] grant create log ERROR -- cannot retrieve users")
+      cb("Cannot retrieve the users")
+      return
+    }
+
+    await this.getModule("tgLogger").grants({
+      action: "CREATE",
+      target,
+      by: admin,
+      since: validSince,
+      until: validUntil,
+      reason,
+    })
+
+    logger.debug("[WS] grant create log OK")
+    cb(null)
+  } catch (error) {
+    logger.error({ error }, "[WS] grant create log ERROR")
+    cb("Cannot send the log")
+  }
 })

Apply the same structure to logGrantInterrupt.

Also applies to: 120-145

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/websocket.ts` around lines 90 - 118, Wrap the websocket handler
logic for this.io.on("logGrantCreate", async (...) => { ... }) in a top-level
try/catch so any unexpected throw still sends an ack; move the await
MessageUserStorage.getInstance().getStoredUser(...) calls, the await
this.getModule("tgLogger").grants(...), and the logging into the try block and
call cb(errorMessage) from the catch (or cb(null) on success) to guarantee the
ack is always called. Do the same change for the this.io.on("logGrantInterrupt",
...) handler so both handlers always call cb(...) regardless of where an
exception occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/modules/websocket.ts`:
- Line 112: Fix the typographical error in the callback error message: replace
the string "Cannot send te log" with "Cannot send the log" wherever it's invoked
(e.g., the cb(...) calls shown in websocket.ts, including the other occurrence
around the later cb call at line ~139). Update both instances so the callback
error message is spelled correctly and maintains the exact same phrasing in both
locations.
- Around line 90-118: Wrap the websocket handler logic for
this.io.on("logGrantCreate", async (...) => { ... }) in a top-level try/catch so
any unexpected throw still sends an ack; move the await
MessageUserStorage.getInstance().getStoredUser(...) calls, the await
this.getModule("tgLogger").grants(...), and the logging into the try block and
call cb(errorMessage) from the catch (or cb(null) on success) to guarantee the
ack is always called. Do the same change for the this.io.on("logGrantInterrupt",
...) handler so both handlers always call cb(...) regardless of where an
exception occurs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06f9271a-8e42-4937-86d6-38ade47ccfac

📥 Commits

Reviewing files that changed from the base of the PR and between ca3b78d and a8dd59f.

📒 Files selected for processing (1)
  • src/modules/websocket.ts

@lorenzocorallo lorenzocorallo merged commit 80fc6e4 into main Apr 12, 2026
2 checks passed
@lorenzocorallo lorenzocorallo deleted the remove-grants branch April 12, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants