Files
cg_api_secure-webshare/docs/FORWARD_SYSTEM.md

8.1 KiB

Forward Submission System

This document describes the submission-forward flow that allows users to upload content through the bot for moderator review before it is posted to a destination channel or group.


Database Schema

Defined in migrations/003_forward_system.sql.

forward_definitions

CREATE TABLE forward_definitions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    creator_user_id INTEGER NOT NULL,
    source_chat_id INTEGER NOT NULL,
    destination_chat_id INTEGER NOT NULL,
    review_group_id INTEGER NOT NULL,
    forward_message TEXT NOT NULL DEFAULT '',
    code TEXT NOT NULL UNIQUE,
    share_mode TEXT NOT NULL DEFAULT 'b',
    revoked_at TEXT,
    created_at TEXT NOT NULL DEFAULT datetime('now')
);
Field Description
id Primary key.
creator_user_id Telegram ID of the admin who created the forward.
source_chat_id The group/chat where /create_submit_forward was invoked.
destination_chat_id The target channel/group where approved content is posted.
review_group_id The moderator group where submissions are sent for review.
forward_message Optional template text prepended to approved posts.
code Unique 16-character alphanumeric access code.
share_mode 'b' = blacklist mode (default), 'w' = whitelist mode.
revoked_at Timestamp if the forward link was revoked; NULL while active.

Indexes: idx_forward_code, idx_forward_source.

forward_submissions

CREATE TABLE forward_submissions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    forward_id INTEGER NOT NULL REFERENCES forward_definitions(id),
    user_id INTEGER NOT NULL,
    content_id TEXT NOT NULL REFERENCES contents(id),
    status TEXT NOT NULL DEFAULT 'pending',
    review_message_id INTEGER,
    created_at TEXT NOT NULL DEFAULT datetime('now'),
    resolved_at TEXT,
    resolver_id INTEGER
);
Field Description
id Primary key (submission number).
forward_id The forward this submission belongs to.
user_id Telegram ID of the submitting user.
content_id The uploaded content entry (contents.id).
status pending, approved, ignored, or blacklisted.
review_message_id Telegram message ID of the review post in the review group.
resolved_at Timestamp when a moderator acted on the submission.
resolver_id Telegram ID of the moderator who resolved it.

Indexes: idx_fwd_sub_forward, idx_fwd_sub_user, idx_fwd_sub_status.

forward_lists

CREATE TABLE forward_lists (
    forward_id INTEGER NOT NULL REFERENCES forward_definitions(id),
    user_id INTEGER NOT NULL,
    list_type TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT datetime('now'),
    PRIMARY KEY (forward_id, user_id, list_type)
);
Field Description
forward_id The forward definition.
user_id The affected user.
list_type blacklist or allow.

This table implements per-forward scoped access control.


Creating a Forward (/create_submit_forward)

Usage (group-only, admin-gated):

/create_submit_forward <destination_chat_id> <review_group_id> [forward_message]

Requirements:

  1. Caller must be an administrator or owner of the source group.
  2. The bot must be an administrator in both the destination_chat_id and review_group_id.

What happens:

  1. A 16-character alphanumeric code is generated (generate_forward_code).
  2. A row is inserted into forward_definitions with:
    • source_chat_id = current chat
    • share_mode = 'b' (blacklist mode)
  3. The bot replies with a deep-link URL:
    https://t.me/<bot_username>?start=submitfwdid<code>
    

Entering Submission Mode

Users click the deep link or send:

/start submitfwdid<CODE>

Validation:

  1. The code is looked up in forward_definitions.
  2. If the forward has been revoked (revoked_at IS NOT NULL), the user is told the link is revoked.
  3. The scoped access check ForwardRepo::is_allowed(forward_id, user_id) is performed:
    • The creator is always allowed.
    • In blacklist mode ('b'): allowed unless the user has a blacklist entry.
    • In whitelist mode ('w'): allowed only if the user has an allow entry.
  4. If allowed, the bot enters BotState::SubmitMode { forward_id, code } and presents Continue / Exit buttons.

Submission Flow

  1. Continue — The user is transitioned to BotState::MainMenu { pending_forward_id: Some(forward_id) }. All uploads staged from this point are tagged with the pending forward ID.
  2. Upload — The user stages files (media, documents, or text) and confirms options just like a normal upload.
  3. Finalize — When the user confirms, finalize_upload:
    • Creates and encrypts the content entry.
    • Inserts a row into forward_submissions with status = 'pending'.
    • Posts a review message to the review_group_id with inline buttons:
      • [ Approve ] → callback v1:fwd:approve:{submission_id}
      • [ Ignore ] → callback v1:fwd:ignore:{submission_id}
      • [ Blacklist User ] → callback v1:fwd:blk:{submission_id}
    • Stores the sent message ID back into forward_submissions.review_message_id.
  4. Review — Moderators in the review group click the buttons to act.

Review Actions

All review callbacks require the clicking user to be an administrator in the review group (is_admin_in_chat).

Approve (v1:fwd:approve)

  1. Generates a random 12-character direct-access password (generate_direct_password).
  2. Hashes the password with Argon2 and stores it in contents.password_hash.
  3. Builds the direct link: {base_url}/?cxid={content_id}&sc={password}.
  4. Posts the link to the destination chat, prefixed with forward_message (if set).
  5. DM the submitter:
    • "Your submission was approved."
    • Includes the posted message URL and the direct access link.
  6. Edits the review message to show [ APPROVED ] and the moderator ID.
  7. Sets forward_submissions.status = 'approved'.

Ignore (v1:fwd:ignore)

  1. DM the submitter: "Your submission was rejected."
  2. Edits the review message to show [ IGNORED ] and the moderator ID.
  3. Sets forward_submissions.status = 'ignored'.

Blacklist User (v1:fwd:blk)

  1. Adds the submitter to forward_lists with list_type = 'blacklist' for this forward.
  2. Edits the review message to show [ BLACKLISTED ] and the moderator ID.
  3. Sets forward_submissions.status = 'blacklisted'.
  4. The user is now blocked from using this forward link again (until removed).

Management Commands

All group-only, admin-gated.

/show_c_forward [page]

Lists forward links created in the current source chat (5 per page).

  • Shows code, destination chat ID, review group ID, and status (Active or Revoked).
  • Active forwards include an inline [ Revoke ] button.
  • Pagination via << / >> buttons.

/add_blacklist <user_id>

Iterates all active forwards for the current source chat and inserts the user into each forward's forward_lists as blacklist. Replies with the count of forwards affected.

/rm_blacklist <user_id>

Iterates all active forwards for the current source chat and removes the user from each forward's forward_lists where list_type = 'blacklist'. Replies with the count of forwards affected.


Scoped Access Model

Each forward has its own independent access list stored in forward_lists.

share_mode Behavior
'b' (blacklist) Default. Everyone is allowed unless explicitly blacklisted.
'w' (whitelist) Only explicitly allowed users (and the creator) may submit.

Note: The share_mode is stored per forward but there is currently no admin command to change it after creation; it defaults to 'b' at creation time.


Revoking a Forward

Admins or the creator can revoke a forward via the [ Revoke ] button on /show_c_forward.

  • Validates the forward belongs to the current chat.
  • Requires creator status or admin status.
  • Sets revoked_at = datetime('now').
  • Revoked forwards reject new submissions immediately.