Files
cg_api_secure-webshare/docs/FORWARD_SYSTEM.md

9.2 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}
      • [ Blackl. ] → callback v1:fwd:blk:{submission_id}
      • [ Ban ] → callback v1:fwd:ban:{submission_id}
      • [ Ban/BL u. ] → callback v1:fwd:banblk:{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.

Note: Media batching is implemented for both review group presentation and approved destination posts. The bot decrypts and sends up to 10 files per media group, attaching the review text or approval caption to the last item.


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).

Ban (v1:fwd:ban)

  1. Bans the submitter in both the destination chat and the review group.
  2. Records ban punishments in the punishments table for both chats.
  3. Edits the review message to show [ BANNED ] and the moderator ID.
  4. Sets forward_submissions.status = 'banned'.

Ban + Blacklist (v1:fwd:banblk)

  1. Bans the submitter in both the destination chat and the review group (same as v1:fwd:ban).
  2. Records ban punishments in the punishments table for both chats.
  3. Also adds the submitter to forward_lists with list_type = 'blacklist' (same as v1:fwd:blk).
  4. Edits the review message to show [ BAN/BL ] and the moderator ID.
  5. Sets forward_submissions.status = 'banblk'.

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.