remnashop
repository·main·Indexed 19 days ago
https://github.com/snoups/remnashopA Telegram bot for the automated sale of VPN subscriptions, featuring deep integration with the Remnawave platform. It includes support for custom banners, Fluent-based translations with custom Telegram emoji support, and a comprehensive set of user management interactors for authentication, email verification, password changes, and advertisement link management.
What's inside remnashop
- remnashop is a Telegram bot designed for selling VPN subscriptions. It is specifically integrated with Remnawave to manage and facilitate the sale of VPN services through the Telegram interface.
Follow the translation key naming convention
mainAll translation keys must follow a strict hierarchical structure to ensure consistency and prevent errors.
Structure
{category}-{scope}-{entity}-{action-or-state}Components
Part Description Example {category}Top-level type of text btn,msg,ntf{scope}Logical group or subsystem user,plan,subscription,error{entity}Specific object or sub-entity content,payment,link{action-or-state}Action (past tense) or State (adjective) created,failed,empty,invalidRules
- Use lowercase with hyphens (
-). No underscores or spaces. - Follow the exact order:
category$\rightarrow$scope$\rightarrow$entity$\rightarrow$action/state. - Actions should be past tense verbs (e.g.,
created,deleted). - States should be adjectives (e.g.,
empty,not-found). - Recommended: Max 5 segments and total length under 32 characters.
- Use lowercase with hyphens (
Configure and use custom banners
mainYou can provide custom banner images by placing them in the
banners/folder within your user volume. The system follows a specific lookup hierarchy to find the most relevant banner for a user's locale and current page. If no user-provided banner is found, the bot falls back to its built-in defaults.Configuration
Enable or disable banners using the environment variable:
BOT_USE_BANNERS: Set totrueto enable,falseto disable.
Banner Lookup Order
banners/{user_locale}/{page}(User volume)banners/{user_locale}/default(User volume)banners/{default_locale}/{page}(User volume)banners/{default_locale}/default(User volume)banners/default(User volume)banners/{user_locale}/{page}(Bot default)banners/default(Bot global default)
Supported Banner Names
Filenames must match one of these
BannerNamevalues:DEFAULT: Fallback banner.MENU: Main menu banner.DASHBOARD: Dashboard banner.SUBSCRIPTION: Subscription banner.REFERRAL: Referral banner.
Supported Formats
JPG,JPEG,PNG,GIF,WEBPCustomize the QR Code logo
mainTo add branding to the generated invitation QR code, place a logo file in your user volume. The system will overlay this image in the center of the QR code.
- Path:
assets/logo.png - Format:
PNG(preferably with a transparent background).
- Path:
Configure and override translations
mainThe bot uses Fluent (
.ftl) files for translations. You can override built-in translations or add new custom ones by placingcustom.ftlfiles in your user volumetranslations/folder.Configuration
APP_LOCALES: A comma-separated list of supported locales (e.g.,ru,en).APP_DEFAULT_LOCALE: The default locale.
How Overrides Work
For each locale, the bot loads files in this priority:
assets/translations/{locale}/custom.ftl(Your overrides - Highest Priority)assets.default/translations/{locale}/*.ftl(Bot built-ins - Fallback)
Custom Keys
To avoid collisions with built-in keys, prefix your custom keys with
custom-. Use the standard Fluent syntax:custom-key-name = Translation textConstraints
- Buttons: Max 32 characters.
- Messages: Max 1024 characters.
# Custom menu buttons custom-menu-link1 = 1️⃣ First button custom-menu-link2 = 2️⃣ Second button # Custom plan names custom-plan-name1 = 1️⃣ Basic plan custom-plan-name2 = 2️⃣ Premium planUse custom Telegram emojis in translations
mainYou can include custom Telegram emojis in your
.ftltranslation files. This requires the bot to have a paid username or the owner to have Telegram Premium.Getting Emoji IDs
Send the emoji to
@getidsbotor@RawDataBotto retrieve thecustom_emoji_id.Supported Syntax
1. Full Format
Best for explicit control:
btn-example = <tg-emoji emoji-id="5406756500108501710">🎁</tg-emoji> Button text2. Short Format
Best for brevity; the system expands this to the full tag automatically:
btn-example = <e id="5406756500108501710">🎁</e> Button textNote: Always include a plain emoji inside the tag as a fallback for clients that do not support custom emojis.
Usage Contexts
- Buttons: Automatically recognized by
Emoji*widgets (e.g.,EmojiButton,EmojiBack). - Messages: Handled by the
I18nFormatwidget.
Priority
If a button's
Stylehasicon_custom_emoji_idexplicitly set via code, it will override the emoji found in the translation key text.# Example in buttons.ftl btn-menu = .connect = <tg-emoji emoji-id="5447410659077661506">🚀</tg-emoji> Connect .devices = <e id="5271604874419647061">📱</e> Devices # Example in messages msg-broadcast-main = <tg-emoji emoji-id="5424818078833715060">📢</tg-emoji> <b>Broadcast</b>- Buttons: Automatically recognized by
Manage user discounts and trial availability
mainThe
profile_edit.pymodule provides several interactor classes for managing user profiles, specifically for administrative tasks like adjusting discounts, points, and trial status.Permissions
Most profile editing operations require the
Permission.USER_EDITORpermission. However, resetting one's own referral code is available toPermission.PUBLICusers, subject to system settings and cooldown periods.Security Rules
For administrative commands, an actor can only edit a target user if:
- The actor is the target user themselves (
actor.id == target_user.id). - The actor's role is strictly greater than the target user's role (
actor.role > target_user.role).
If these conditions are not met, a
PermissionDeniedErroris raised.- The actor is the target user themselves (
Referral Level logic
mainReferrals are organized into levels using the
ReferralLevelenum. The level of a new referral is determined by the level of its parent in the referral chain:- If there is no parent (the referrer is not part of a chain), the level is
ReferralLevel.FIRST. - If a parent exists, the new level is
parent_level.value + 1. - The level cannot exceed the maximum value defined in the
ReferralLevelenum.
This hierarchy allows the system to track multi-level referral structures.
- If there is no parent (the referrer is not part of a chain), the level is
Referral reward types and levels
mainThe referral system utilizes the following enums to define how rewards are structured and distributed:
Reward Types (
ReferralRewardType):POINTS: Grants user points.EXTRA_DAYS: Grants subscription time.
Referral Levels (
ReferralLevel):FIRST: The immediate referrer of the user.SECOND: The referrer of the immediate referrer (the 'grand-referrer').
Accrual Strategies (
ReferralAccrualStrategy):ON_FIRST_PAYMENT: Rewards are only triggered on the user's first successful purchase.
Configure and use automated database backups
mainThe
AutoBackupDatabaseinteractor automates the creation of database backups based on system settings. It ensures backups are not created too frequently and manages disk space by rotating old files.Configuration Logic: The automation relies on the following settings retrieved via
SettingsDao:backup.enabled: Iffalse, no backup is performed.backup.interval_hours: The minimum time elapsed since the last backup (found inBACKUP_DIR) before a new one is triggered.backup.max_files: The maximum number of backup files to retain inBACKUP_DIR. Once this limit is reached, the oldest files are deleted.backup.send_to_chat: Iftrue, the backup file is sent to administrators (Role.OWNERandRole.DEV) via theNotifier.
Workflow:
- Checks if backups are enabled and if the
interval_hourshas passed since the last file inBACKUP_DIR. - Creates a SQL dump in a temporary directory.
- Moves the dump to
BACKUP_DIRwith the namedb_backup_<timestamp>.sql. - Rotates files if the count exceeds
max_files. - Optionally notifies admins if
send_to_chatis enabled.
Supported Promocode Reward Types
mainThe
ActivatePromocodeinteractor supports the followingPromocodeRewardTypevalues, each affecting different parts of the user's account:DURATION: Extends the subscriptionexpire_atdate by a specified number of days. A reward of0results in an unlimited subscription.TRAFFIC: Increases thetraffic_limit(in GB). A reward of0results in unlimited traffic.DEVICES: Increases thedevice_limit. A reward of0results in unlimited devices.SUBSCRIPTION: Applies a new plan from aplan_snapshot. This can either update an existing subscription or create a new one via Remnawave.PERSONAL_DISCOUNT: Applies a percentage discount to the user'spersonal_discountfield.PURCHASE_DISCOUNT: Applies a percentage discount to the user'spurchase_discountfield.
Configure API documentation (Swagger and ReDoc)
mainThe Remnashop API documentation is controlled via the
swagger_enabledflag in yourAppConfig. When enabled, the following endpoints are available:/docs: Swagger UI withpersistAuthorizationenabled./redoc: ReDoc documentation./openapi.json: The raw OpenAPI schema.
Note that these endpoints are marked with
include_in_schema=False, meaning they won't appear in the generated OpenAPI schema itself.