Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
220 KB
Referenced Files
None
Subscribers
None
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7bc926..ecc1ff7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,740 +1,741 @@
# Changelog
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
Exclamation symbols (:exclamation:) note something of importance e.g. breaking changes. Click them to learn more.
## [Unreleased]
### Notes
- [:ledger: View file changes][Unreleased] ∙ [:page_with_curl: DB migration script][unreleased-sql-migration]
- [:exclamation:][unreleased-bc-minimum-php-81] PHP 8.1+ required!
### Added
- Bot API 7.0 (@noplanman, @TiiFuchs) (#1459)
+- Bot API 7.1 (@noplanman)
### Changed
- [:exclamation:][unreleased-bc-user-to-users] Various fields have been pluralised from "user" to "users".
### Deprecated
### Removed
### Fixed
### Security
## [0.82.0] - 2023-10-26
### Notes
- [:ledger: View file changes][0.82.0] ∙ [:page_with_curl: DB migration script][0.82.0-sql-migration]
- Really the last version that supports PHP 7! Only PHP 8 after this one.
### Added
- Bot API 6.8, 6.9 (@noplanman) (#1418, #1427)
- Test against PHP 8.3 (@sergiy-petrov) (#1421)
### Fixed
- Missing `thumbnail_url` renaming.
- Fix broken exception handling (@mlocati) (#1425)
## [0.81.0] - 2023-05-27
### Notes
- [:ledger: View file changes][0.81.0] ∙ [:page_with_curl: DB migration script][0.81.0-sql-migration]
- Last version that supports PHP 7.
### Added
- Support dynamic Entity properties for newer PHP versions (@alesinicio, @TiiFuchs) (#1390)
- Bot API 6.4, 6.5, 6.6, 6.7 (@noplanman) (#1389)
### Removed
- Keyboard validations (@noplanman) (#1395)
### Fixed
- Fixed a bug where new incoming updates are not correctly passed to the Command object after the first time when getUpdates is used. (@uspilot) (#1384)
## [0.80.0] - 2022-11-09
### Notes
- [:ledger: View file changes][0.80.0] ∙ [:page_with_curl: DB migration script][0.80.0-sql-migration]
### Added
- Bot API 6.3 (@TiiFuchs) (#1371)
### Changed
- [:exclamation:][0.80.0-bc-commands-with-underscores] Commands can now contain underscores (`FooBarCommand` is handled by `/foo_bar`). (@mlocati) (#1365)
## [0.79.0] - 2022-09-04
### Notes
- [:ledger: View file changes][0.79.0]
### Added
- Bot API 6.2 (@OxMohsen) (#1350)
### Removed
- `VoiceChatX` entities, use `VideoChatX` entities instead.
- `all_members_are_administrators` property from `Message` entity. Database column still exists, but may be removed in the future.
- `Request::getChatMembersCount()`, use `Request::getChatMemberCount()` instead.
- `Request::kickChatMember()`, use `Request::banChatMember()` instead.
## [0.78.0] - 2022-07-03
### Notes
- [:ledger: View file changes][0.78.0] ∙ [:page_with_curl: DB migration script][0.78.0-sql-migration]
- 64 bit PHP install required to handle files larger than 2GB!
### Added
- Bot API 6.1 (@jyxjjj, @OxMohsen, @noplanman) (#1333, #1338, #1339)
- New Update field helpers for Command class.
## [0.77.1] - 2022-04-24
### Notes
- [:ledger: View file changes][0.77.1]
### Fixed
- PHP8+ `mixed` type hint removed
## [0.77.0] - 2022-04-24
### Notes
- [:ledger: View file changes][0.77.0] ∙ [:page_with_curl: DB migration script][0.77.0-sql-migration]
### Added
- Bot API 6.0 (@TiiFuchs) (#1318)
### Deprecated
- Telegram changed `voice_chat_X` to `video_chat_X`. `VoiceChatX` event classes are deprecated, use new `VideoChatX` event classes instead.
### Fixed
- Return correct data in `Entity::jsonSerialize` (@TiiFuchs)
## [0.76.1] - 2022-03-30
### Notes
- [:ledger: View file changes][0.76.1]
### Fixed
- Fix Entity serialising for Keyboards (@TiiFuchs) (#1304)
## [0.76.0] - 2022-03-20
### Notes
- [:ledger: View file changes][0.76.0]
### Added
- Bot API 5.6 (@TiiFuchs) (#1275)
- Bot API 5.7 (@TiiFuchs) (#1284)
- PSR3 (psr/log) version 2 and 3 compatible (@noplanman) (#1287)
- Entity implements and uses JsonSerializable now (@TiiFuchs)
- Test with PHP 8.1 on Travis CI (@osavchenko) (#1291)
### Changed
- Bugfix: Fixed condition in \Longman\TelegramBot\Entities\Chat::isGroupChat() that previously also counted super groups and channels. (@TiiFuchs)
## [0.75.0] - 2021-12-29
### Notes
- [:ledger: View file changes][0.75.0] ∙ [:page_with_curl: DB migration script][0.75.0-sql-migration]
### Added
- Ability to directly set commands paths. (@wright-tw, @noplanman) (#1252)
- Bot API 5.4. (@TiiFuchs, @noplanman) (#1266)
- Bot API 5.5. (@TiiFuchs, @noplanman) (#1267)
- The field `message_auto_delete_time` was added to the Chat Entity (@TiiFuchs) (#1265)
### Removed
- [:exclamation:][0.75.0-bc-removed-chatactions] Removed deprecated `ChatAction::` `RECORD_AUDIO` and `UPLOAD_AUDIO`. Use `RECORD_VOICE` and `UPLOAD_VOICE` instead. (@TiiFuchs) (#1267)
### Fixed
- PHP 8.1 deprecations. (@maxgorovenko) (#1260)
## [0.74.0] - 2021-06-26
### Notes
- [:ledger: View file changes][0.74.0]
### Added
- [:exclamation:][0.74.0-bc-chatmember-subentities] Bot API 5.3 (Personalized Commands, Keyboard Placeholders). (@TiiFuchs, @noplanman) (#1229, #1231)
## [0.73.1] - 2021-06-20
### Notes
- [:ledger: View file changes][0.73.1]
### Fixed
- Allow new optional parameters when setting and deleting webhook. (@TiiFuchs) (#1226)
## [0.73.0] - 2021-06-14
### Notes
- [:ledger: View file changes][0.73.0] ∙ [:page_with_curl: DB migration script][0.73.0-sql-migration]
### Added
- Bot API 5.2 (Payments 2.0). (#1216)
- Possibility to connect to MySQL DB with unix socket. (@Tynik) (#1220)
### Changed
- `Telegram::runCommands` returns array of `ServerResponse` objects of executed commands. (#1223)
### Fixed
- Regex for namespace extraction from custom command classes.
- Nested and user-triggered `Telegram::runCommands`. (#1223)
## [0.72.0] - 2021-04-16
### Notes
- [:ledger: View file changes][0.72.0] ∙ [:page_with_curl: DB migration script][0.72.0-sql-migration]
### Added
- Bot API 5.1 (ChatMember Update types, Improved Invite Links, Voice Chat). (@massadm, @noplanman) (#1199)
- Method to allow adding command classes directly. (@alligator77, @noplanman) (#1207, #1209)
### Deprecated
- `Telegram::handleGetUpdates` method should be passed a `$data` array for parameters. (#1202)
### Fixed
- `message.edit_date` is now of type `timestamp`. (#1191)
- Allow all update types by default when using `getUpdates` method. (#1202)
## [0.71.0] - 2021-03-05
### Notes
- [:ledger: View file changes][0.71.0]
### Added
- Define a custom Bot API server and file download URI. (#1168)
### Changed
- Improved error messages for empty input. (#1164)
- Log update when processing it, not when fetching input. (#1164)
### Fixed
- `getUpdates` method wrongly sends only 1 Update when a limit of 0 is passed. (#1169)
- `Telegram::runCommands()` now passes the correct message text to the commands. (#1181)
- Request limiter accepts chat ID as integer and string. (#1182)
- Calling Keyboard constructor without any parameters. (@hutattedonmyarm) (#1184)
## [0.70.1] - 2020-12-25
### Notes
- [:ledger: View file changes][0.70.1]
### Added
- Extra parameter for `Request::sendMessage()` to pass options and return all response objects for split messages. (#1163)
### Fixed
- Ensure download and upload path variables are defined. (#1162)
## [0.70.0] - 2020-12-21
### Notes
- [:ledger: View file changes][0.70.0] ∙ [:page_with_curl: DB migration script][0.70.0-sql-migration]
- [:exclamation:][0.70.0-bc-minimum-php-73] PHP 7.3+ required, so make sure your code is up to date with correct types!
### Added
- Bot API 5.0 (Big update!). (#1147)
### Changed
- Upgrade code to PHP 7.3. (#1136, #1158)
- Speed up `/clean` query. (@dva-re) (#1139)
- Various code prettifications. (@akalongman) (#1140, #1141, #1142, #1143)
### Security
- Minimum PHP 7.3, allow PHP 8.0. (#1136, #1158)
## [0.64.0] - 2020-10-04
### Notes
- [:ledger: View file changes][0.64.0]
### Added
- Support for Guzzle 7. (@KristobalJunta) (#1133)
### Fixed
- Correct SQL migration script for older versions of MySQL. (#1135)
## [0.63.1] - 2020-06-24
### Notes
- [:ledger: View file changes][0.63.1]
- This fixed version is necessary for Windows users.
### Fixed
- Regex in `getFileNamespace()` that introduced a breaking bug in #1114. (@jacklul) (#1115)
- Fixed `runCommands()` not working due to custom namespace feature. (@jacklul) (#1115, #1118)
## [0.63.0] - 2020-06-17
### Notes
- [:ledger: View file changes][0.63.0] ∙ [:page_with_curl: DB migration script][0.63.0-sql-migration]
### Added
- New method `setUpdateFilter($callback)` used to filter `processUpdate(Update $update)` calls. If `$callback` returns `false` the update isn't processed and an empty falsey `ServerResponse` is returned. (@VRciF) (#1045)
- Replaced 'generic' and 'genericmessage' strings with Telegram::GENERIC_COMMAND and Telegram::GENERIC_MESSAGE_COMMAND constants. (@1int) (#1074)
- Bot API 4.8 (Extra Poll and Dice features). (#1082)
- Allow custom MySQL port to be defined for tests. (#1090)
- New static method `Entity::escapeMarkdownV2` for MarkdownV2. (#1094)
- Remove bot token from debug http logs, this can be disabled by setting `TelegramLog::$remove_bot_token` parameter to `false`. (@jacklul) (#1095)
- `TelegramLog::$always_log_request_and_response` parameter to force output of the request and response data to the debug log, also for successful requests. (#1089)
- Bot API 4.9 (New `via_bot` field). (#1112)
### Changed
- [:exclamation:][0.63.0-bc-static-method-entityescapemarkdown] Made `Entity::escapeMarkdown` static, to not require an `Entity` object. (#1094)
- Allow custom namespacing for commands. (@Jonybang) (#689)
### Fixed
- Primary key for `poll_answer` also requires the `user_id`. (#1087)
- Small SQL foreign key fixes. (#1105)
## [0.62.0] - 2020-04-08
### Notes
- [:ledger: View file changes][0.62.0] ∙ [:page_with_curl: DB migration script][0.62.0-sql-migration]
### Added
- Bot API 4.5 (Unique file IDs, MarkdownV2). (#1046)
- Chain the exception thrown when getting commands from path. (#1030)
- Support `language_code` in `DB::selectChats()` for filtering the chats selection. (#1058)
- Bot API 4.6 (Polls 2.0). (#1066)
- Bot API 4.7 (Dice, Sticker Sets, Bot Commands). (#1067)
### Changed
- Save notes an unescaped JSON, to allow easy DB reading and editing of values. (#1005)
- `Request::setClient()` now accepts more flexible `ClientInterface`. (#1068)
### Removed
- Unnecessary `instanceof` checks for entities. (#1068)
- Unused `Request::$input` variable. (#1068)
### Fixed
- Execution of `/start` command without any custom implementation.
- Return `animation` type for GIF Message (which returns both `animation` and `document`). (#1044)
- Change lowercase function to `mb_strtolower` from `strtolower` because of `latin-extented` characters. (#1051)
- Extend `Request::mediaInputHelper()` to include `thumb` parameter. (#1059)
- Various docblock annotations. (#1068)
## [0.61.1] - 2019-11-23
### Notes
- [:ledger: View file changes][0.61.1]
### Added
- Tests for schema update scripts, to ensure that updates work as expected. (#1025)
### Fixed
- Parameter `inline_query_id` in `InlineQuery::answerInlineQuery`. (#1021)
- Corrected DB schema update 0.60.0-0.61.0. (#1025)
## [0.61.0] - 2019-11-02
### Notes
- [:ledger: View file changes][0.61.0] ∙ [:page_with_curl: DB migration script][0.61.0-sql-migration]
- :exclamation: Built-in logging (Monolog) has been removed, a custom PSR-3 logger must be used now! (see #964 for more info)
### Added
- Code snippet in `GenericmessageCommand` to keep obsolete service message system commands working. (#999)
- Static boolean property `SystemCommand::$execute_deprecated` (must be assigned before handling the request) to try and execute any deprecated system command. (#999)
- Improved MySQL DB index for `message` table, making the cleanup much faster on bigger databases. (Thanks to @damianperez) (#1015)
- `/cleanup` command now supports dry run which simply outputs all queries that would be run. (#1015)
### Changed
- Small readme and code fixes / simplifications. (#1001)
- Upgrade PHPUnit to 8.x and PHPCS to 3.5. For tests now minimum PHP version is 7.2. (#1008)
- Updated updates log importer (requires PHP7+). (#1009)
### Removed
- Service message system commands, which are now handled by `GenericmessageCommand`. (#999)
- [:exclamation:][0.61.0-bc-remove-monolog-from-core] Monolog has been removed as built-in logging engine. (#1009)
- Assets have been moved to a dedicated repository. (#1012)
### Fixed
- Boolean value for Polls gets saved correctly in MySQL DB. (#996)
- Correctly use `Request::answerInlineQuery` in `InlineQuery::answer`. (#1001)
- PSR-12 incompatibilities in the codebase. (#1008)
- Improved and corrected `/cleanup` command. (#1015)
## [0.60.0] - 2019-08-16
### Notes
- [:ledger: View file changes][0.60.0]
### Added
- Bot API 4.4 (Animated stickers, `ChatPermissions`). (#990)
### Changed
- Allow passing native entity objects to requests. (#991)
### Fixed
- Non-existing commands now correctly execute `GenericCommand` again. (#993)
## [0.59.1] - 2019-07-18
### Notes
- [:ledger: View file changes][0.59.1]
- :exclamation: Deprecated logging method will be removed in the next version, update to PSR-3 now! (see #964 for more info)
### Added
- Issue labels set automatically via templates.
### Changed
- Logging only updates or only debug/errors is now possible. (#983)
### Fixed
- Don't output deprecation notices if no logging is enabled. (#983)
- Respect custom HTTP Client initialisation, no matter when it is set. (#986)
## [0.59.0] - 2019-07-07
### Notes
- [:ledger: View file changes][0.59.0]
### Changed
- Touched up readme including header and badges. (#981)
- Updated changelog to be more useful for external integrations like [Tidelift] and GitHub releases. (#981)
### Removed
- Abstract methods from `InputMedia` interface, as method annotations didn't work for propagation. (#978)
## [0.58.0] - 2019-06-26
### Notes
- [:ledger: View file changes][0.58.0] ∙ [:page_with_curl: DB migration script][0.58.0-sql-migration]
- Logging now uses [PSR-3] `LoggerInterface`. Learn more about how to use it here: #964
### Added
- New funding and support details. (#971)
- Custom issue templates. (#972)
- Bot API 4.3 (Seamless Telegram Login, `LoginUrl`) (#957)
- `reply_markup` field to `Message` entity. (#957)
### Changed
- Use PSR-12 for code style. (#966)
- Some general housekeeping. (#972)
- [:exclamation:][0.58.0-bc-return-value-of-empty-entity-properties] Return an empty array for Entity properties with no items, instead of `null`. (#969)
- `TelegramLog` now adheres to [PSR-3] `LoggerInterface` and allows custom logger implementations. (#964)
### Deprecated
- Old logging that uses Monolog still works but will be removed in the near future. Use `TelegramLog::initialize($logger, $update_logger);` from now on. (#964)
- [:exclamation:][0.58.0-bc-startcommand-is-now-a-usercommand] `StartCommand` is now a `UserCommand` (not `SystemCommand` any more). (#970)
### Removed
- Botan.io integration completely removed. (#968)
### Fixed
- `forward_date` is now correctly saved to the DB. (#967)
- Broken `StickerSet::getStickers()` method. (#969)
- Smaller code and docblock fixes. (#973)
### Security
- Security disclosure managed by [Tidelift]. (#971)
- Don't allow a user to call system commands directly. (#970)
## [0.57.0] - 2019-06-01
### Notes
- [:ledger: View file changes][0.57.0] ∙ [:page_with_curl: DB migration script][0.57.0-sql-migration]
- :grey_exclamation: This is a big update and involves a bunch of MySQL database updates, so please *review the changelog carefully*.
### Added
- New logo! :tada: (#954)
- Bot API 4.2 (Polls). (#948)
- `getIsMember()` method to `ChatMember` entity. (#948)
- `getForwardSenderName()` method to `Message` entity. (#948)
- `forward_sender_name` (and forgotten `forward_signature`) DB fields. (#948)
- Added missing API fields to Entities and DB. (#885)
- Created database tables for `shipping_query` and `pre_checkout_query`. (#885)
### Fixed
- Missing DB table name specifier in `/cleanup` command. (#947)
## [0.56.0] - 2019-04-15
### Notes
- [:ledger: View file changes][0.56.0] ∙ [:page_with_curl: DB migration script][0.56.0-sql-migration]
- :grey_exclamation: This is a big update, so please *review the changelog carefully*!
### Added
- Helper for sending `InputMedia` objects using `Request::sendMediaGroup()` and `Request::editMediaMessage()` methods.
- Allow passing absolute file path for InputFile fields, instead of `Request::encodeFile($path)`. (#934)
### Changed
- All Message field types dynamically search for an existing Command class that can handle them. (#940)
- Upgrade dependencies. (#945)
### Deprecated
- Botan.io service has been discontinued. (#925)
- Most built-in System Commands will be handled by GenericmessageCommand by default in a future release and will require a custom implementation. (#940)
### Fixed
- Constraint errors in `/cleanup` command. (#930)
- Return correct objects for requests. (#934)
- PHPCS: static before visibility declaration. (#945)
## [0.55.1] - 2019-01-06
### Notes
- [:ledger: View file changes][0.55.1]
### Added
- Add missing `Request::editMessageMedia()` and `CallbackQuery::getChatInstance()` methods. (#916)
### Fixed
- Return correct message type. (#913)
## [0.55.0] - 2018-12-20
### Notes
- [:ledger: View file changes][0.55.0] ∙ [:page_with_curl: DB migration script][0.55.0-sql-migration]
### Added
- Bot API 4.0 and 4.1 (Telegram Passport) (#870, #871)
- Test PHP 7.3 with Travis. (#903)
### Changed
- [:exclamation:][0.55.0-bc-move-animation-out-of-games-namespace] Move Animation entity out of Games namespace.
### Fixed
- Added missing `video_note` to `Message` types.
## [0.54.1] - 2018-10-23
### Notes
- [:ledger: View file changes][0.54.1]
### Fixed
- `sendToActiveChats` now works correctly for any valid Request action. (#898)
## [0.54.0] - 2018-07-21
### Notes
- [:ledger: View file changes][0.54.0] ∙ [:page_with_curl: DB migration script][0.54.0-sql-migration]
### Added
- `ChatAction` class to simplify chat action selection. (#859)
- Telegram Games platform! (#732)
- Ability to set custom MySQL port. (#860)
- New `InvalidBotTokenException` exception. (#855)
### Changed
- [:exclamation:][0.54.0-bc-rename-constants] Rename and ensure no redefinition of constants: `BASE_PATH` -> `TB_BASE_PATH`, `BASE_COMMANDS_PATH` -> `TB_BASE_COMMANDS_PATH`. (#813)
- Improve readability of readme code snippets. (#861)
### Fixed
- Response from `getStickerSet`. (#838)
## [0.53.0] - 2018-04-01
### Notes
- [:ledger: View file changes][0.53.0] ∙ [:page_with_curl: DB migration script][0.53.0-sql-migration]
### Added
- Implemented new changes for Bot API 3.6 (streamable InputMediaVideo, connected website). (#799)
- `Telegram::getLastUpdateId()` method, returns ID of the last update that was processed. (#767)
- `Telegram::useGetUpdatesWithoutDatabase()` method, enables `Telegram::handleGetUpdates()` to run without a database. (#767)
### Changed
- Updated Travis to use Trusty containers (for HHVM) and add PHP 7.2 to the tests. (#739)
- Add debug log entry instead of throwing an exception for duplicate updates. (#765)
- `Telegram::handleGetUpdates()` can now work without a database connection (not enabled by default). (#767)
- Improved `/sendtochannel` and `/sendtoall` commands, using new message helpers. (#810)
### Fixed
- PHPCS fixes for updated CodeSniffer dependency. (#739)
- Send messages correctly via `/sendtochannel`. (#803)
## [0.52.0] - 2018-01-07
### Notes
- [:ledger: View file changes][0.52.0]
### Fixed
- Entity relations and wrong types for payments. (#731)
- Allow empty string for `switch_inline_query` and `switch_inline_query_current_chat` (InlineKeyboardButton). (#736)
- Fix empty date entry for User and Chat entities, using the current timestamp instead. (#738)
## [0.51.0] - 2017-12-05
### Notes
- [:ledger: View file changes][0.51.0] ∙ [:page_with_curl: DB migration script][0.51.0-sql-migration]
### Added
- Implemented new changes for Bot API 3.5 (InputMedia, MediaGroup). (#718)
## [0.50.0] - 2017-10-17
### Notes
- [:ledger: View file changes][0.50.0]
### Added
- Finish implementing payments, adding all missing type checks and docblock methods. (#647)
- Implemented new changes for Bot API 3.4 (Live Locations). (#675)
### Changed
- [:exclamation:][0.50.0-bc-messagegetcommand-return-value] `Message::getCommand()` returns `null` if not a command, instead of `false`. (#654)
### Fixed
- SQL update script for version 0.44.1-0.45.0.
- Issues found by Scrutinizer (Type hints and return values). (#654)
- Check inline keyboard button parameter value correctly. (#672)
## [0.49.0] - 2017-09-17
### Notes
- [:ledger: View file changes][0.49.0]
### Added
- Donation section and links in readme.
- Missing payment methods in `Request` class.
- Some helper methods for replying to commands and answering queries.
### Changed
- Updated and optimised all DB classes, removing a lot of bulky code.
### Fixed
- Ensure named SQL statement parameters are unique.
- Channel selection when using `DB::selectChats()`.
## [0.48.0] - 2017-08-26
### Notes
- [:ledger: View file changes][0.48.0] ∙ [:page_with_curl: DB migration script][0.48.0-sql-migration]
### Added
- New entities, methods, update types and inline keyboard button for Payments (Bot API 3.0).
- Add new methods, fields and objects for working with stickers (Bot API 3.2).
- New fields for Chat, User and Message objects (Bot API 3.3). `is_bot` added to `user` DB table.
### Changed
- [:exclamation:][0.48.0-bc-correct-printerror] Corrected `ServerResponse->printError` method to print by default and return by setting `$return` parameter.
- Ensure command names are handled as lower case.
### Fixed
- Correctly save `reply_to_message` to DB.
## [0.47.1] - 2017-08-06
### Notes
- [:ledger: View file changes][0.47.1]
### Added
- Linked version numbers in changelog for easy verification of code changes.
### Fixed
- Private-only commands work with edited messages now too.
## [0.47.0] - 2017-08-06 [YANKED]
### Notes
- [:ledger: View file changes][0.47.0]
### Changed
- Updated readme to latest state of 0.47.0.
### Fixed
- `Telegram::enableAdmin()` now handles duplicate additions properly.
- `Request::getMe()` failure doesn't break cron execution any more.
### Security
- [:exclamation:][0.47.0-bc-private-only-admin-commands] New command parameter `$private_only` to enforce usage in private chats only (set by default for Admin commands).
## [0.46.0] - 2017-07-15
### Notes
- [:ledger: View file changes][0.46.0]
### Added
- Callbacks can be added to be executed when callback queries are called.
- New Bot API 3.1 changes (#550).
- `/cleanup` command for admins, that cleans out old entries from the DB.
### Changed
- [:exclamation:][0.46.0-bc-request-class-refactor] Big refactor of the `Request` class, removing most custom method implementations.
## [0.45.0] - 2017-06-25
### Notes
- [:ledger: View file changes][0.45.0] ∙ [:page_with_curl: DB migration script][0.45.0-sql-migration]
### Added
- Documents can be sent by providing its contents via Psr7 stream (as opposed to passing a file path).
- Allow setting a custom Guzzle HTTP Client for requests (#511, #536).
- First implementations towards Bots API 3.0.
### Changed
- [:exclamation:][0.45.0-bc-chats-params-array] `Request::sendToActiveChats` and `DB::selectChats` now accept parameters as an options array and allow selecting of channels.
### Deprecated
- Deprecated `Message::getNewChatMember()` (Use `Message::getNewChatMembers()` instead to get an array of all newly added members).
### Removed
- [:exclamation:][0.45.0-bc-up-download-directory] Upload and download directories are not set any more by default and must be set manually.
- [:exclamation:][0.45.0-bc-remove-deprecated-methods] Completely removed `Telegram::getBotName()` and `Entity::getBotName()` (Use `::getBotUsername()` instead).
- [:exclamation:][0.45.0-bc-remove-deprecated-methods] Completely removed deprecated `Telegram::unsetWebhook()` (Use `Telegram::deleteWebhook()` instead).
### Fixed
- ID fields are now typed with `PARAM_STR` PDO data type, to allow huge numbers.
- Message type data type for PDO corrected.
- Indexed table columns now have a fitting length.
- Take `custom_input` into account when using getUpdates method (mainly for testing).
- Request limiter has been fixed to correctly support channels.
## [0.44.1] - 2017-04-25
### Notes
- [:ledger: View file changes][0.44.1]
### Fixed
- Erroneous exception when using webhook without a database connection.
## [0.44.0] - 2017-04-25
### Notes
- [:ledger: View file changes][0.44.0]
### Added
- Proper standalone `scrutinizer.yml` config.
- Human-readable `last_error_date_string` for debug command.
### Changed
- Bot username no longer required for object instantiation.
### Removed
- All examples have been moved to a [dedicated repository][example-bot].
### Fixed
- [:exclamation:][0.44.0-bc-update-content-type] Format of Update content type using `$update->getUpdateContent()`.
## [0.43.0] - 2017-04-17
### Notes
- [:ledger: View file changes][0.43.0]
### Added
- Travis CI webhook for Support Bot.
- Interval for request limiter.
- `isRunCommands()` method to check if called via `runCommands()`.
- Ensure coding standards for `tests` folder with `phpcs`.
### Changed
- Move default commands to `examples` folder.
- All links point to new organisation repo.
- Add PHP 7.1 support and update dependencies.
### Fixed
- Prevent handling the same Telegram updates multiple times, throw exception instead.
## [0.42.0] - 2017-04-09
### Notes
- [:ledger: View file changes][0.42.0]
### Added
- Added `getBotId()` to directly access bot ID.
### Changed
- Rename `bot_name` to `bot_username` everywhere.
### Deprecated
- Deprecated `Telegram::getBotName()` (Use `Telegram::getBotUsername()` instead).
### Fixed
- Tests are more reliable now, using a properly formatted API key.
## [0.41.0] - 2017-03-25
### Notes
- [:ledger: View file changes][0.41.0]
### Added
- `$show_in_help` attribute for commands, to set if it should be displayed in the `/help` command.
- Link to new Telegram group: `https://telegram.me/PHP_Telegram_Bot_Support`
- Introduce change log.
## [0.40.1] - 2017-03-07
### Notes
- [:ledger: View file changes][0.40.1]
### Fixed
- Infinite message loop, caused by incorrect Entity variable.
## [0.40.0] - 2017-02-20
### Notes
- [:ledger: View file changes][0.40.0]
### Added
- Request limiter for incoming requests.
### Fixed
- Faulty formatting in logger.
## [0.39.0] - 2017-01-20
### Notes
- [:ledger: View file changes][0.39.0]
### Added
- Newest bot API changes.
- Allow direct access to PDO object (`DB::getPdo()`).
- Simple `/debug` command that displays various system information to help debugging.
- Crontab-friendly script.
### Changed
- Botan integration improvements.
- Make logger more flexible.
### Fixed
- Various bugs and recommendations by Scrutinizer.
## [0.38.1] - 2016-12-25
### Notes
- [:ledger: View file changes][0.38.1]
### Fixed
- Usage of self-signed certificates in conjunction with the new `allowed_updates` webhook parameter.
## [0.38.0] - 2016-12-25
### Notes
- [:ledger: View file changes][0.38.0]
### Added
- New `switch_inline_query_current_chat` option for inline keyboard.
- Support for `channel_post` and `edited_channel_post`.
- New alias `deleteWebhook` (for `unsetWebhook`).
### Changed
- Update WebhookInfo entity and `setWebhook` to allow passing of new arguments.
## [0.37.1] - 2016-12-24
### Notes
- [:ledger: View file changes][0.37.1]
### Fixed
- Keyboards that are built without using the KeyboardButton objects.
- Commands that are called via `/command@botname` by correctly passing them the bot name.
## [0.37.0] - 2016-12-13
### Notes
- [:ledger: View file changes][0.37.0]
### Changed
- Logging improvements to Botan integration.
### Deprecated
- Move `hideKeyboard` to `removeKeyboard`.
[unreleased-sql-migration]: https://github.com/php-telegram-bot/core/tree/develop/utils/db-schema-update/0.82.0-unreleased.sql
[unreleased-bc-unreleased-bc-minimum-php-81]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-81
[unreleased-bc-unreleased-bc-user-to-users]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#user-to-users
[0.82.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.81.0-0.82.0.sql
[0.81.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.80.0-0.81.0.sql
[0.80.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.79.0-0.80.0.sql
[0.80.0-bc-commands-with-underscores]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#commands-with-underscores
[0.78.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.77.1-0.78.0.sql
[0.77.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.76.1-0.77.0.sql
[0.75.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.74.0-0.75.0.sql
[0.75.0-bc-removed-chatactions]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#removed-deprecated-chatactions
[0.74.0-bc-chatmember-subentities]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#chatmember-subentities
[0.73.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.72.0-0.73.0.sql
[0.72.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.71.0-0.72.0.sql
[0.70.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.64.0-0.70.0.sql
[0.70.0-bc-minimum-php-73]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#minimum-php-73
[0.63.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.62.0-0.63.0.sql
[0.63.0-bc-static-method-entityescapemarkdown]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#static-method-entityescapemarkdown
[0.62.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.61.1-0.62.0.sql
[0.61.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.60.0-0.61.0.sql
[0.61.0-bc-remove-monolog-from-core]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#remove-monolog-from-core
[0.58.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.57.0-0.58.0.sql
[0.58.0-bc-return-value-of-empty-entity-properties]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#return-value-of-empty-entity-properties
[0.58.0-bc-startcommand-is-now-a-usercommand]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#startcommand-is-now-a-usercommand
[0.57.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.56.0-0.57.0.sql
[0.55.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.54.1-0.55.0.sql
[0.55.0-bc-move-animation-out-of-games-namespace]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#move-animation-out-of-games-namespace
[0.54.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.53.0-0.54.0.sql
[0.54.0-bc-rename-constants]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#rename-constants
[0.53.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.52.0-0.53.0.sql
[0.51.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.50.0-0.51.0.sql
[0.50.0-bc-messagegetcommand-return-value]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#messagegetcommand-return-value
[0.48.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/master/utils/db-schema-update/0.47.1-0.48.0.sql
[0.48.0-bc-correct-printerror]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#correct-printerror
[0.47.0-bc-private-only-admin-commands]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#private-only-admin-commands
[0.46.0-bc-request-class-refactor]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#request-class-refactor
[0.46.0-sql-migration]: https://github.com/php-telegram-bot/core/tree/0.45.0/utils/db-schema-update/0.44.1-0.45.0.sql
[0.45.0-bc-remove-deprecated-methods]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#remove-deprecated-methods
[0.45.0-bc-chats-params-array]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#chats-params-array
[0.45.0-bc-up-download-directory]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#up-download-directory
[0.44.0-bc-update-content-type]: https://github.com/php-telegram-bot/core/wiki/Breaking-backwards-compatibility#update-getupdatecontent
[example-bot]: https://github.com/php-telegram-bot/example-bot
[PSR-3]: https://www.php-fig.org/psr/psr-3
[Tidelift]: https://tidelift.com/subscription/pkg/packagist-longman-telegram-bot?utm_source=packagist-longman-telegram-bot&utm_medium=referral&utm_campaign=changelog
[Unreleased]: https://github.com/php-telegram-bot/core/compare/master...develop
[0.82.0]: https://github.com/php-telegram-bot/core/compare/0.81.0...0.82.0
[0.81.0]: https://github.com/php-telegram-bot/core/compare/0.80.0...0.81.0
[0.80.0]: https://github.com/php-telegram-bot/core/compare/0.79.0...0.80.0
[0.79.0]: https://github.com/php-telegram-bot/core/compare/0.78.0...0.79.0
[0.78.0]: https://github.com/php-telegram-bot/core/compare/0.77.1...0.78.0
[0.77.1]: https://github.com/php-telegram-bot/core/compare/0.77.0...0.77.1
[0.77.0]: https://github.com/php-telegram-bot/core/compare/0.76.1...0.77.0
[0.76.1]: https://github.com/php-telegram-bot/core/compare/0.76.0...0.76.1
[0.76.0]: https://github.com/php-telegram-bot/core/compare/0.75.0...0.76.0
[0.75.0]: https://github.com/php-telegram-bot/core/compare/0.74.0...0.75.0
[0.74.0]: https://github.com/php-telegram-bot/core/compare/0.73.1...0.74.0
[0.73.1]: https://github.com/php-telegram-bot/core/compare/0.73.0...0.73.1
[0.73.0]: https://github.com/php-telegram-bot/core/compare/0.72.0...0.73.0
[0.72.0]: https://github.com/php-telegram-bot/core/compare/0.71.0...0.72.0
[0.71.0]: https://github.com/php-telegram-bot/core/compare/0.70.1...0.71.0
[0.70.1]: https://github.com/php-telegram-bot/core/compare/0.70.0...0.70.1
[0.70.0]: https://github.com/php-telegram-bot/core/compare/0.64.0...0.70.0
[0.64.0]: https://github.com/php-telegram-bot/core/compare/0.63.1...0.64.0
[0.63.1]: https://github.com/php-telegram-bot/core/compare/0.63.0...0.63.1
[0.63.0]: https://github.com/php-telegram-bot/core/compare/0.62.0...0.63.0
[0.62.0]: https://github.com/php-telegram-bot/core/compare/0.61.1...0.62.0
[0.61.1]: https://github.com/php-telegram-bot/core/compare/0.61.0...0.61.1
[0.61.0]: https://github.com/php-telegram-bot/core/compare/0.60.0...0.61.0
[0.60.0]: https://github.com/php-telegram-bot/core/compare/0.59.1...0.60.0
[0.59.1]: https://github.com/php-telegram-bot/core/compare/0.59.0...0.59.1
[0.59.0]: https://github.com/php-telegram-bot/core/compare/0.58.0...0.59.0
[0.58.0]: https://github.com/php-telegram-bot/core/compare/0.57.0...0.58.0
[0.57.0]: https://github.com/php-telegram-bot/core/compare/0.56.0...0.57.0
[0.56.0]: https://github.com/php-telegram-bot/core/compare/0.55.1...0.56.0
[0.55.1]: https://github.com/php-telegram-bot/core/compare/0.55.0...0.55.1
[0.55.0]: https://github.com/php-telegram-bot/core/compare/0.54.1...0.55.0
[0.54.1]: https://github.com/php-telegram-bot/core/compare/0.54.0...0.54.1
[0.54.0]: https://github.com/php-telegram-bot/core/compare/0.53.0...0.54.0
[0.53.0]: https://github.com/php-telegram-bot/core/compare/0.52.0...0.53.0
[0.52.0]: https://github.com/php-telegram-bot/core/compare/0.51.0...0.52.0
[0.51.0]: https://github.com/php-telegram-bot/core/compare/0.50.0...0.51.0
[0.50.0]: https://github.com/php-telegram-bot/core/compare/0.49.0...0.50.0
[0.49.0]: https://github.com/php-telegram-bot/core/compare/0.48.0...0.49.0
[0.48.0]: https://github.com/php-telegram-bot/core/compare/0.47.1...0.48.0
[0.47.1]: https://github.com/php-telegram-bot/core/compare/0.47.0...0.47.1
[0.47.0]: https://github.com/php-telegram-bot/core/compare/0.46.0...0.47.0
[0.46.0]: https://github.com/php-telegram-bot/core/compare/0.45.0...0.46.0
[0.45.0]: https://github.com/php-telegram-bot/core/compare/0.44.1...0.45.0
[0.44.1]: https://github.com/php-telegram-bot/core/compare/0.44.0...0.44.1
[0.44.0]: https://github.com/php-telegram-bot/core/compare/0.43.0...0.44.0
[0.43.0]: https://github.com/php-telegram-bot/core/compare/0.42.0...0.43.0
[0.42.0]: https://github.com/php-telegram-bot/core/compare/0.41.0...0.42.0
[0.41.0]: https://github.com/php-telegram-bot/core/compare/0.40.1...0.41.0
[0.40.1]: https://github.com/php-telegram-bot/core/compare/0.40.0...0.40.1
[0.40.0]: https://github.com/php-telegram-bot/core/compare/0.39.0...0.40.0
[0.39.0]: https://github.com/php-telegram-bot/core/compare/0.38.1...0.39.0
[0.38.1]: https://github.com/php-telegram-bot/core/compare/0.38.0...0.38.1
[0.38.0]: https://github.com/php-telegram-bot/core/compare/0.37.1...0.38.0
[0.37.1]: https://github.com/php-telegram-bot/core/compare/0.37.0...0.37.1
[0.37.0]: https://github.com/php-telegram-bot/core/compare/0.36...0.37.0
diff --git a/README.md b/README.md
index 8be0697..0a227de 100644
--- a/README.md
+++ b/README.md
@@ -1,725 +1,725 @@
<h1 align="center">
PHP Telegram Bot<br>
<br>
<img src="https://raw.githubusercontent.com/php-telegram-bot/assets/master/logo/512px/logo_plain.png" title="PHP Telegram Bot" alt="PHP Telegram Bot logo">
<br>
</h1>
A Telegram Bot based on the official [Telegram Bot API]
-[![API Version](https://img.shields.io/badge/Bot%20API-6.9%20%28September%202023%29-32a2da.svg)](https://core.telegram.org/bots/api-changelog#september-22-2023)
+[![API Version](https://img.shields.io/badge/Bot%20API-7.1%20%28February%202024%29-32a2da.svg)](https://core.telegram.org/bots/api-changelog#february-16-2024)
[![Join the bot support group on Telegram](https://img.shields.io/badge/telegram-@PHP__Telegram__Bot__Support-64659d.svg)](https://telegram.me/PHP_Telegram_Bot_Support)
[![Donate](https://img.shields.io/badge/%F0%9F%92%99-Donate%20%2F%20Support%20Us-blue.svg)](#donate)
[![Tests](https://github.com/php-telegram-bot/core/actions/workflows/tests.yaml/badge.svg)](https://github.com/php-telegram-bot/core/actions/workflows/tests.yaml)
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/php-telegram-bot/core/master.svg?style=flat)](https://scrutinizer-ci.com/g/php-telegram-bot/core/?b=master)
[![Code Quality](https://img.shields.io/scrutinizer/g/php-telegram-bot/core/master.svg?style=flat)](https://scrutinizer-ci.com/g/php-telegram-bot/core/?b=master)
[![Latest Stable Version](https://img.shields.io/packagist/v/longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
[![Dependencies](https://tidelift.com/badges/github/php-telegram-bot/core?style=flat)][Tidelift]
[![Total Downloads](https://img.shields.io/packagist/dt/longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
[![Downloads Month](https://img.shields.io/packagist/dm/longman/telegram-bot.svg)](https://packagist.org/packages/longman/telegram-bot)
[![Minimum PHP Version](http://img.shields.io/badge/php-%3E%3D8.1-8892BF.svg)](https://php.net/)
[![License](https://img.shields.io/packagist/l/longman/telegram-bot.svg)](https://github.com/php-telegram-bot/core/LICENSE)
## Table of Contents
- [Introduction](#introduction)
- [Instructions](#instructions)
- [Create your first bot](#create-your-first-bot)
- [Require this package with Composer](#require-this-package-with-composer)
- [Choose how to retrieve Telegram updates](#choose-how-to-retrieve-telegram-updates)
- [Using a custom Bot API server](#using-a-custom-bot-api-server)
- [Webhook installation](#webhook-installation)
- [Self Signed Certificate](#self-signed-certificate)
- [Unset Webhook](#unset-webhook)
- [getUpdates installation](#getupdates-installation)
- [getUpdates without database](#getupdates-without-database)
- [Filter Update](#filter-update)
- [Support](#support)
- [Types](#types)
- [Inline Query](#inline-query)
- [Methods](#methods)
- [Send Message](#send-message)
- [Send Photo](#send-photo)
- [Send Chat Action](#send-chat-action)
- [getUserProfilePhoto](#getuserprofilephoto)
- [getFile and downloadFile](#getfile-and-downloadfile)
- [Send message to all active chats](#send-message-to-all-active-chats)
- [Utils](#utils)
- [MySQL storage (Recommended)](#mysql-storage-recommended)
- [External Database connection](#external-database-connection)
- [Channels Support](#channels-support)
- [Commands](#commands)
- [Predefined Commands](#predefined-commands)
- [Custom Commands](#custom-commands)
- [Commands Configuration](#commands-configuration)
- [Admin Commands](#admin-commands)
- [Set Admins](#set-admins)
- [Channel Administration](#channel-administration)
- [Upload and Download directory path](#upload-and-download-directory-path)
- [Logging](doc/01-utils.md)
- [Documentation](#documentation)
- [Assets](#assets)
- [Example bot](#example-bot)
- [Projects with this library](#projects-with-this-library)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [Security](#security)
- [Donate](#donate)
- [For enterprise](#for-enterprise)
- [License](#license)
- [Credits](#credits)
## Introduction
This is a pure PHP Telegram Bot, fully extensible via plugins.
Telegram announced official support for a [Bot API](https://telegram.org/blog/bot-revolution), allowing integrators of all sorts to bring automated interactions to the mobile platform.
This Bot aims to provide a platform where one can simply write a bot and have interactions in a matter of minutes.
The Bot can:
- Retrieve updates with [webhook](#webhook-installation) and [getUpdates](#getupdates-installation) methods.
-- Supports all types and methods according to Telegram Bot API 6.9 (September 2023).
+- Supports all types and methods according to Telegram Bot API 7.1 (February 2024).
- Supports supergroups.
- Handle commands in chat with other bots.
- Manage Channel from the bot admin interface.
- Full support for **inline bots**.
- Inline keyboard.
- Messages, InlineQuery and ChosenInlineQuery are stored in the Database.
- Conversation feature.
---
This code is available on [GitHub](https://github.com/php-telegram-bot/core). Pull requests are welcome.
## Instructions
### Create your first bot
1. Message [`@BotFather`](https://telegram.me/BotFather) with the following text: `/newbot`
If you don't know how to message by username, click the search field on your Telegram app and type `@BotFather`, where you should be able to initiate a conversation. Be careful not to send it to the wrong contact, because some users have similar usernames to `BotFather`.
![BotFather initial conversation](https://user-images.githubusercontent.com/9423417/60736229-bc2aeb80-9f45-11e9-8d35-5b53145347bc.png)
2. `@BotFather` replies with:
```
Alright, a new bot. How are we going to call it? Please choose a name for your bot.
```
3. Type whatever name you want for your bot.
4. `@BotFather` replies with:
```
Good. Now let's choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot.
```
5. Type whatever username you want for your bot, minimum 5 characters, and must end with `bot`. For example: `telesample_bot`
6. `@BotFather` replies with:
```
Done! Congratulations on your new bot. You will find it at
telegram.me/telesample_bot. You can now add a description, about
section and profile picture for your bot, see /help for a list of
commands.
Use this token to access the HTTP API:
123456789:AAG90e14-0f8-40183D-18491dDE
For a description of the Bot API, see this page:
https://core.telegram.org/bots/api
```
7. Note down the 'token' mentioned above.
*Optionally set the bot privacy:*
1. Send `/setprivacy` to `@BotFather`.
![BotFather later conversation](https://user-images.githubusercontent.com/9423417/60736340-26439080-9f46-11e9-970f-8f33bbe39c5f.png)
2. `@BotFather` replies with:
```
Choose a bot to change group messages settings.
```
3. Type (or select) `@telesample_bot` (change to the username you set at step 5
above, but start it with `@`)
4. `@BotFather` replies with:
```
'Enable' - your bot will only receive messages that either start with the '/' symbol or mention the bot by username.
'Disable' - your bot will receive all messages that people send to groups.
Current status is: ENABLED
```
5. Type (or select) `Disable` to let your bot receive all messages sent to a group.
6. `@BotFather` replies with:
```
Success! The new status is: DISABLED. /help
```
### Require this package with Composer
Install this package through [Composer].
Edit your project's `composer.json` file to require `longman/telegram-bot`.
Create *composer.json* file
```json
{
"name": "yourproject/yourproject",
"type": "project",
"require": {
"php": "^8.1",
"longman/telegram-bot": "*"
}
}
```
and run `composer update`
**or**
run this command in your command line:
```bash
composer require longman/telegram-bot
```
### Choose how to retrieve Telegram updates
The bot can handle updates with [**Webhook**](#webhook-installation) or [**getUpdates**](#getupdates-installation) method:
| | Webhook | getUpdates |
| ---- | :----: | :----: |
| Description | Telegram sends the updates directly to your host | You have to fetch Telegram updates manually |
| Host with https | Required | Not required |
| MySQL | Not required | ([Not](#getupdates-without-database)) Required |
## Using a custom Bot API server
**For advanced users only!**
As from Telegram Bot API 5.0, users can [run their own Bot API server] to handle updates.
This means, that the PHP Telegram Bot needs to be configured to serve that custom URI.
Additionally, you can define the URI where uploaded files to the bot can be downloaded (note the `{API_KEY}` placeholder).
```php
Longman\TelegramBot\Request::setCustomBotApiUri(
$api_base_uri = 'https://your-bot-api-server', // Default: https://api.telegram.org
$api_base_download_uri = '/path/to/files/{API_KEY}' // Default: /file/bot{API_KEY}
);
```
**Note:** If you are running your bot in `--local` mode, you won't need the `Request::downloadFile()` method, since you can then access your files directly from the absolute path returned by `Request::getFile()`.
## Webhook installation
Note: For a more detailed explanation, head over to the [example-bot repository] and follow the instructions there.
In order to set a [Webhook][api-setwebhook] you need a server with HTTPS and composer support.
(For a [self signed certificate](#self-signed-certificate) you need to add some extra code)
Create *[set.php]* with the following contents:
```php
<?php
// Load composer
require __DIR__ . '/vendor/autoload.php';
$bot_api_key = 'your:bot_api_key';
$bot_username = 'username_bot';
$hook_url = 'https://your-domain/path/to/hook.php';
try {
// Create Telegram API object
$telegram = new Longman\TelegramBot\Telegram($bot_api_key, $bot_username);
// Set webhook
$result = $telegram->setWebhook($hook_url);
if ($result->isOk()) {
echo $result->getDescription();
}
} catch (Longman\TelegramBot\Exception\TelegramException $e) {
// log telegram errors
// echo $e->getMessage();
}
```
Open your *set.php* via the browser to register the webhook with Telegram.
You should see `Webhook was set`.
Now, create *[hook.php]* with the following contents:
```php
<?php
// Load composer
require __DIR__ . '/vendor/autoload.php';
$bot_api_key = 'your:bot_api_key';
$bot_username = 'username_bot';
try {
// Create Telegram API object
$telegram = new Longman\TelegramBot\Telegram($bot_api_key, $bot_username);
// Handle telegram webhook request
$telegram->handle();
} catch (Longman\TelegramBot\Exception\TelegramException $e) {
// Silence is golden!
// log telegram errors
// echo $e->getMessage();
}
```
### Self Signed Certificate
Upload the certificate and add the path as a parameter in *set.php*:
```php
$result = $telegram->setWebhook($hook_url, ['certificate' => '/path/to/certificate']);
```
### Unset Webhook
Edit *[unset.php]* with your bot credentials and execute it.
## getUpdates installation
For best performance, the MySQL database should be enabled for the `getUpdates` method!
Create *[getUpdatesCLI.php]* with the following contents:
```php
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
$bot_api_key = 'your:bot_api_key';
$bot_username = 'username_bot';
$mysql_credentials = [
'host' => 'localhost',
'port' => 3306, // optional
'user' => 'dbuser',
'password' => 'dbpass',
'database' => 'dbname',
];
try {
// Create Telegram API object
$telegram = new Longman\TelegramBot\Telegram($bot_api_key, $bot_username);
// Enable MySQL
$telegram->enableMySql($mysql_credentials);
// Handle telegram getUpdates request
$telegram->handleGetUpdates();
} catch (Longman\TelegramBot\Exception\TelegramException $e) {
// log telegram errors
// echo $e->getMessage();
}
```
Next, give the file permission to execute:
```bash
$ chmod +x getUpdatesCLI.php
```
Lastly, run it!
```bash
$ ./getUpdatesCLI.php
```
### getUpdates without database
If you choose to / or are obliged to use the `getUpdates` method without a database, you can replace the `$telegram->enableMySql(...);` line above with:
```php
$telegram->useGetUpdatesWithoutDatabase();
```
## Filter Update
:exclamation: Note that by default, Telegram will send any new update types that may be added in the future. This may cause commands that don't take this into account to break!
It is suggested that you specifically define which update types your bot can receive and handle correctly.
You can define which update types are sent to your bot by defining them when setting the [webhook](#webhook-installation) or passing an array of allowed types when using [getUpdates](#getupdates-installation).
```php
use Longman\TelegramBot\Entities\Update;
// For all update types currently implemented in this library:
// $allowed_updates = Update::getUpdateTypes();
// Define the list of allowed Update types manually:
$allowed_updates = [
Update::TYPE_MESSAGE,
Update::TYPE_CHANNEL_POST,
// etc.
];
// When setting the webhook.
$telegram->setWebhook($hook_url, ['allowed_updates' => $allowed_updates]);
// When handling the getUpdates method.
$telegram->handleGetUpdates(['allowed_updates' => $allowed_updates]);
```
Alternatively, Update processing can be allowed or denied by defining a custom update filter.
Let's say we only want to allow messages from a user with ID `428`, we can do the following before handling the request:
```php
$telegram->setUpdateFilter(function (Update $update, Telegram $telegram, &$reason = 'Update denied by update_filter') {
$user_id = $update->getMessage()->getFrom()->getId();
if ($user_id === 428) {
return true;
}
$reason = "Invalid user with ID {$user_id}";
return false;
});
```
The reason for denying an update can be defined with the `$reason` parameter. This text gets written to the debug log.
## Support
### Types
-All types are implemented according to Telegram API 6.9 (September 2023).
+All types are implemented according to Telegram API 7.1 (February 2024).
### Inline Query
-Full support for inline query according to Telegram API 6.9 (September 2023).
+Full support for inline query according to Telegram API 7.1 (February 2024).
### Methods
-All methods are implemented according to Telegram API 6.9 (September 2023).
+All methods are implemented according to Telegram API 7.1 (February 2024).
#### Send Message
Messages longer than 4096 characters are split up into multiple messages.
```php
$result = Request::sendMessage([
'chat_id' => $chat_id,
'text' => 'Your utf8 text 😜 ...',
]);
```
#### Send Photo
To send a local photo, add it properly to the `$data` parameter using the file path:
```php
$result = Request::sendPhoto([
'chat_id' => $chat_id,
'photo' => Request::encodeFile('/path/to/pic.jpg'),
]);
```
If you know the `file_id` of a previously uploaded file, just use it directly in the data array:
```php
$result = Request::sendPhoto([
'chat_id' => $chat_id,
'photo' => 'AAQCCBNtIhAoAAss4tLEZ3x6HzqVAAqC',
]);
```
To send a remote photo, use the direct URL instead:
```php
$result = Request::sendPhoto([
'chat_id' => $chat_id,
'photo' => 'https://example.com/path/to/pic.jpg',
]);
```
*sendAudio*, *sendDocument*, *sendAnimation*, *sendSticker*, *sendVideo*, *sendVoice* and *sendVideoNote* all work in the same way, just check the [API documentation](https://core.telegram.org/bots/api#sendphoto) for the exact usage.
See the *[ImageCommand.php]* for a full example.
#### Send Chat Action
```php
Request::sendChatAction([
'chat_id' => $chat_id,
'action' => Longman\TelegramBot\ChatAction::TYPING,
]);
```
#### getUserProfilePhoto
Retrieve the user photo. (see *[WhoamiCommand.php]* for a full example)
#### getFile and downloadFile
Get the file path and download it. (see *[WhoamiCommand.php]* for a full example)
#### Send message to all active chats
To do this you have to enable the MySQL connection.
Here's an example of use (check [`DB::selectChats()`][DB::selectChats] for parameter usage):
```php
$results = Request::sendToActiveChats(
'sendMessage', // Callback function to execute (see Request.php methods)
['text' => 'Hey! Check out the new features!!'], // Param to evaluate the request
[
'groups' => true,
'supergroups' => true,
'channels' => false,
'users' => true,
]
);
```
You can also broadcast a message to users, from the private chat with your bot. Take a look at the [admin commands](#admin-commands) below.
## Utils
### MySQL storage (Recommended)
If you want to save messages/users/chats for further usage in commands, create a new database (`utf8mb4_unicode_520_ci`), import *[structure.sql]* and enable MySQL support BEFORE `handle()` method:
```php
$mysql_credentials = [
'host' => 'localhost',
'port' => 3306, // optional
'user' => 'dbuser',
'password' => 'dbpass',
'database' => 'dbname',
];
$telegram->enableMySql($mysql_credentials);
```
You can set a custom prefix to all the tables while you are enabling MySQL:
```php
$telegram->enableMySql($mysql_credentials, $bot_username . '_');
```
You can also store inline query and chosen inline query data in the database.
#### External Database connection
It is possible to provide the library with an external MySQL PDO connection.
Here's how to configure it:
```php
$telegram->enableExternalMySql($external_pdo_connection);
//$telegram->enableExternalMySql($external_pdo_connection, $table_prefix)
```
### Channels Support
All methods implemented can be used to manage channels.
With [admin commands](#admin-commands) you can manage your channels directly with your bot private chat.
## Commands
### Predefined Commands
The bot is able to recognise commands in a chat with multiple bots (/command@mybot).
It can also execute commands that get triggered by events, so-called Service Messages.
### Custom Commands
Maybe you would like to develop your own commands.
There is a guide to help you [create your own commands][wiki-create-your-own-commands].
Also, be sure to have a look at the [example commands][ExampleCommands-folder] to learn more about custom commands and how they work.
You can add your custom commands in different ways:
```php
// Add a folder that contains command files
$telegram->addCommandsPath('/path/to/command/files');
//$telegram->addCommandsPaths(['/path/to/command/files', '/another/path']);
// Add a command directly using the class name
$telegram->addCommandClass(MyCommand::class);
//$telegram->addCommandClasses([MyCommand::class, MyOtherCommand::class]);
```
### Commands Configuration
With this method you can set some command specific parameters, for example:
```php
// Google geocode/timezone API key for /date command
$telegram->setCommandConfig('date', [
'google_api_key' => 'your_google_api_key_here',
]);
// OpenWeatherMap API key for /weather command
$telegram->setCommandConfig('weather', [
'owm_api_key' => 'your_owm_api_key_here',
]);
```
### Admin Commands
Enabling this feature, the bot admin can perform some super user commands like:
- List all the chats started with the bot */chats*
- Clean up old database entries */cleanup*
- Show debug information about the bot */debug*
- Send message to all chats */sendtoall*
- Post any content to your channels */sendtochannel*
- Inspect a user or a chat with */whois*
Take a look at all default admin commands stored in the *[src/Commands/AdminCommands/][AdminCommands-folder]* folder.
#### Set Admins
You can specify one or more admins with this option:
```php
// Single admin
$telegram->enableAdmin(your_telegram_user_id);
// Multiple admins
$telegram->enableAdmins([
your_telegram_user_id,
other_telegram_user_id,
]);
```
Telegram user id can be retrieved with the *[/whoami][WhoamiCommand.php]* command.
#### Channel Administration
To enable this feature follow these steps:
- Add your bot as channel administrator, this can be done with any Telegram client.
- Enable admin interface for your user as explained in the admin section above.
- Enter your channel name as a parameter for the *[/sendtochannel][SendtochannelCommand.php]* command:
```php
$telegram->setCommandConfig('sendtochannel', [
'your_channel' => [
'@type_here_your_channel',
]
]);
```
- If you want to manage more channels:
```php
$telegram->setCommandConfig('sendtochannel', [
'your_channel' => [
'@type_here_your_channel',
'@type_here_another_channel',
'@and_so_on',
]
]);
```
- Enjoy!
## Upload and Download directory path
To use the Upload and Download functionality, you need to set the paths with:
```php
$telegram->setDownloadPath('/your/path/Download');
$telegram->setUploadPath('/your/path/Upload');
```
## Documentation
Take a look at the repo [Wiki] for further information and tutorials!
Feel free to improve!
## Assets
All project assets can be found in the [assets](https://github.com/php-telegram-bot/assets) repository.
## Example bot
We're busy working on a full A-Z example bot, to help get you started with this library and to show you how to use all its features.
You can check the progress of the [example-bot repository]).
## Projects with this library
Here's a list of projects that feats this library, feel free to add yours!
- [Inline Games](https://github.com/jacklul/inlinegamesbot) ([@inlinegamesbot](https://telegram.me/inlinegamesbot))
- [Super-Dice-Roll](https://github.com/RafaelDelboni/Super-Dice-Roll) ([@superdiceroll_bot](https://telegram.me/superdiceroll_bot))
- [tg-mentioned-bot](https://github.com/gruessung/tg-mentioned-bot)
- [OSMdeWikiBot](https://github.com/OSM-de/TelegramWikiBot) ([@OSM_de](https://t.me/OSM_de))
- [pass-generator-webbot](https://github.com/OxMohsen/pass-generator-webbot)
- [Chess Quiz Bot](https://github.com/1int/chess-quiz-bot)
- [PHP Telegram Bot - Symfony Bundle](https://github.com/m4n50n/telegram_bot_bundle)
## Troubleshooting
If you like living on the edge, please report any bugs you find on the [PHP Telegram Bot issues][issues] page.
## Contributing
See [CONTRIBUTING](CONTRIBUTING.md) for more information.
## Security
See [SECURITY](SECURITY.md) for more information.
## Donate
All work on this bot consists of many hours of coding during our free time, to provide you with a Telegram Bot library that is easy to use and extend.
If you enjoy using this library and would like to say thank you, donations are a great way to show your support.
Donations are invested back into the project :+1:
Thank you for keeping this project alive :pray:
- [![Patreon](https://user-images.githubusercontent.com/9423417/59235980-a5fa6b80-8be3-11e9-8ae7-020bc4ae9baa.png) Patreon.com/phptelegrambot][Patreon]
- [![OpenCollective](https://user-images.githubusercontent.com/9423417/59235978-a561d500-8be3-11e9-89be-82ec54be1546.png) OpenCollective.com/php-telegram-bot][OpenCollective]
- [![Ko-fi](https://user-images.githubusercontent.com/9423417/59235976-a561d500-8be3-11e9-911d-b1908c3e6a33.png) Ko-fi.com/phptelegrambot][Ko-fi]
- [![Tidelift](https://user-images.githubusercontent.com/9423417/59235982-a6930200-8be3-11e9-8ac2-bfb6991d80c5.png) Tidelift.com/longman/telegram-bot][Tidelift]
- [![Liberapay](https://user-images.githubusercontent.com/9423417/59235977-a561d500-8be3-11e9-9d16-bc3b13d3ceba.png) Liberapay.com/PHP-Telegram-Bot][Liberapay]
- [![PayPal](https://user-images.githubusercontent.com/9423417/59235981-a5fa6b80-8be3-11e9-9761-15eb7a524cb0.png) PayPal.me/noplanman][PayPal-noplanman] (account of @noplanman)
- [![Bitcoin](https://user-images.githubusercontent.com/9423417/59235974-a4c93e80-8be3-11e9-9fde-260c821b6eae.png) 166NcyE7nDxkRPWidWtG1rqrNJoD5oYNiV][Bitcoin]
- [![Ethereum](https://user-images.githubusercontent.com/9423417/59235975-a4c93e80-8be3-11e9-8762-7a47c62c968d.png) 0x485855634fa212b0745375e593fAaf8321A81055][Ethereum]
## For enterprise
Available as part of the Tidelift Subscription.
The maintainers of `PHP Telegram Bot` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.][Tidelift]
## License
Please see the [LICENSE](LICENSE) included in this repository for a full copy of the MIT license, which this project is licensed under.
## Credits
Credit list in [CREDITS](CREDITS)
---
[Telegram Bot API]: https://core.telegram.org/bots/api "Telegram Bot API"
[Composer]: https://getcomposer.org/ "Composer"
[run their own Bot API server]: https://core.telegram.org/bots/api#using-a-local-bot-api-server "Using a Local Bot API Server"
[example-bot repository]: https://github.com/php-telegram-bot/example-bot "Example Bot repository"
[api-setwebhook]: https://core.telegram.org/bots/api#setwebhook "Webhook on Telegram Bot API"
[set.php]: https://github.com/php-telegram-bot/example-bot/blob/master/set.php "example set.php"
[unset.php]: https://github.com/php-telegram-bot/example-bot/blob/master/unset.php "example unset.php"
[hook.php]: https://github.com/php-telegram-bot/example-bot/blob/master/hook.php "example hook.php"
[getUpdatesCLI.php]: https://github.com/php-telegram-bot/example-bot/blob/master/getUpdatesCLI.php "example getUpdatesCLI.php"
[AdminCommands-folder]: https://github.com/php-telegram-bot/core/tree/master/src/Commands/AdminCommands "Admin commands folder"
[ExampleCommands-folder]: https://github.com/php-telegram-bot/example-bot/blob/master/Commands "Example commands folder"
[ImageCommand.php]: https://github.com/php-telegram-bot/example-bot/blob/master/Commands/Other/ImageCommand.php "example /image command"
[WhoamiCommand.php]: https://github.com/php-telegram-bot/example-bot/blob/master/Commands/WhoamiCommand.php "example /whoami command"
[HelpCommand.php]: https://github.com/php-telegram-bot/example-bot/blob/master/Commands/HelpCommand.php "example /help command"
[SendtochannelCommand.php]: https://github.com/php-telegram-bot/core/blob/master/src/Commands/AdminCommands/SendtochannelCommand.php "/sendtochannel admin command"
[DB::selectChats]: https://github.com/php-telegram-bot/core/blob/0.70.0/src/DB.php#L1148 "DB::selectChats() parameters"
[structure.sql]: https://github.com/php-telegram-bot/core/blob/master/structure.sql "DB structure for importing"
[Wiki]: https://github.com/php-telegram-bot/core/wiki "PHP Telegram Bot Wiki"
[wiki-create-your-own-commands]: https://github.com/php-telegram-bot/core/wiki/Create-your-own-commands "Create your own commands"
[issues]: https://github.com/php-telegram-bot/core/issues "PHP Telegram Bot Issues"
[Patreon]: https://www.patreon.com/phptelegrambot "Support us on Patreon"
[OpenCollective]: https://opencollective.com/php-telegram-bot "Support us on Open Collective"
[Ko-fi]: https://ko-fi.com/phptelegrambot "Support us on Ko-fi"
[Tidelift]: https://tidelift.com/subscription/pkg/packagist-longman-telegram-bot?utm_source=packagist-longman-telegram-bot&utm_medium=referral&utm_campaign=enterprise&utm_term=repo "Learn more about the Tidelift Subscription"
[Liberapay]: https://liberapay.com/PHP-Telegram-Bot "Donate with Liberapay"
[PayPal-noplanman]: https://paypal.me/noplanman "Donate with PayPal"
[Bitcoin]: https://www.blockchain.com/btc/address/166NcyE7nDxkRPWidWtG1rqrNJoD5oYNiV "Donate with Bitcoin"
[Ethereum]: https://etherscan.io/address/0x485855634fa212b0745375e593fAaf8321A81055 "Donate with Ethereum"
diff --git a/src/Commands/Command.php b/src/Commands/Command.php
index 0d53250..5ddba9d 100644
--- a/src/Commands/Command.php
+++ b/src/Commands/Command.php
@@ -1,456 +1,456 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Commands;
use Longman\TelegramBot\DB;
use Longman\TelegramBot\Entities\CallbackQuery;
use Longman\TelegramBot\Entities\ChatJoinRequest;
use Longman\TelegramBot\Entities\ChatMemberUpdated;
use Longman\TelegramBot\Entities\ChosenInlineResult;
use Longman\TelegramBot\Entities\InlineQuery;
use Longman\TelegramBot\Entities\Message;
use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery;
use Longman\TelegramBot\Entities\Payments\ShippingQuery;
use Longman\TelegramBot\Entities\Poll;
use Longman\TelegramBot\Entities\PollAnswer;
use Longman\TelegramBot\Entities\ServerResponse;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Exception\TelegramException;
use Longman\TelegramBot\Request;
use Longman\TelegramBot\Telegram;
/**
* Class Command
*
* Base class for commands. It includes some helper methods that can fetch data directly from the Update object.
*
* @method Message getMessage() Optional. New incoming message of any kind — text, photo, sticker, etc.
* @method Message getEditedMessage() Optional. New version of a message that is known to the bot and was edited
* @method Message getChannelPost() Optional. New post in the channel, can be any kind — text, photo, sticker, etc.
* @method Message getEditedChannelPost() Optional. New version of a post in the channel that is known to the bot and was edited
* @method InlineQuery getInlineQuery() Optional. New incoming inline query
* @method ChosenInlineResult getChosenInlineResult() Optional. The result of an inline query that was chosen by a user and sent to their chat partner.
* @method CallbackQuery getCallbackQuery() Optional. New incoming callback query
* @method ShippingQuery getShippingQuery() Optional. New incoming shipping query. Only for invoices with flexible price
* @method PreCheckoutQuery getPreCheckoutQuery() Optional. New incoming pre-checkout query. Contains full information about checkout
* @method Poll getPoll() Optional. New poll state. Bots receive only updates about polls, which are sent or stopped by the bot
* @method PollAnswer getPollAnswer() Optional. A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls that were sent by the bot itself.
* @method ChatMemberUpdated getMyChatMember() Optional. The bot's chat member status was updated in a chat. For private chats, this update is received only when the bot is blocked or unblocked by the user.
* @method ChatMemberUpdated getChatMember() Optional. A chat member's status was updated in a chat. The bot must be an administrator in the chat and must explicitly specify “chat_member” in the list of allowed_updates to receive these updates.
* @method ChatJoinRequest getChatJoinRequest() Optional. A request to join the chat has been sent. The bot must have the can_invite_users administrator right in the chat to receive these updates.
*/
abstract class Command
{
/**
* Auth level for user commands
*/
public const AUTH_USER = 'User';
/**
* Auth level for system commands
*/
public const AUTH_SYSTEM = 'System';
/**
* Auth level for admin commands
*/
public const AUTH_ADMIN = 'Admin';
/**
* Telegram object
*
* @var Telegram
*/
protected $telegram;
/**
* Update object
*
* @var Update
*/
protected $update;
/**
* Name
*
* @var string
*/
protected $name = '';
/**
* Description
*
* @var string
*/
protected $description = 'Command description';
/**
* Usage
*
* @var string
*/
protected $usage = 'Command usage';
/**
* Show in Help
*
* @var bool
*/
protected $show_in_help = true;
/**
* Version
*
* @var string
*/
protected $version = '1.0.0';
/**
* If this command is enabled
*
* @var bool
*/
protected $enabled = true;
/**
* If this command needs mysql
*
* @var bool
*/
protected $need_mysql = false;
/**
* Make sure this command only executes on a private chat.
*
* @var bool
*/
protected $private_only = false;
/**
* Command config
*
* @var array
*/
protected $config = [];
/**
* Constructor
*
* @param Telegram $telegram
* @param Update|null $update
*/
public function __construct(Telegram $telegram, ?Update $update = null)
{
$this->telegram = $telegram;
if ($update !== null) {
$this->setUpdate($update);
}
$this->config = $telegram->getCommandConfig($this->name);
}
/**
* Set update object
*
* @param Update $update
*
* @return Command
*/
public function setUpdate(Update $update): Command
{
$this->update = $update;
return $this;
}
/**
* Pre-execute command
*
* @return ServerResponse
* @throws TelegramException
*/
public function preExecute(): ServerResponse
{
if ($this->need_mysql && !($this->telegram->isDbEnabled() && DB::isDbConnected())) {
return $this->executeNoDb();
}
if ($this->isPrivateOnly() && $this->removeNonPrivateMessage()) {
$message = $this->getMessage() ?: $this->getEditedMessage() ?: $this->getChannelPost() ?: $this->getEditedChannelPost();
if ($user = $message->getFrom()) {
return Request::sendMessage([
'chat_id' => $user->getId(),
'parse_mode' => 'Markdown',
'text' => sprintf(
"/%s command is only available in a private chat.\n(`%s`)",
$this->getName(),
- $message->getText()
+ $message->getText(),
),
]);
}
return Request::emptyResponse();
}
return $this->execute();
}
/**
* Execute command
*
* @return ServerResponse
* @throws TelegramException
*/
abstract public function execute(): ServerResponse;
/**
* Execution if MySQL is required but not available
*
* @return ServerResponse
* @throws TelegramException
*/
public function executeNoDb(): ServerResponse
{
return $this->replyToChat('Sorry no database connection, unable to execute "' . $this->name . '" command.');
}
/**
* Get update object
*
* @return Update|null
*/
public function getUpdate(): ?Update
{
return $this->update;
}
/**
* Relay any non-existing function calls to Update object.
*
* This is purely a helper method to make requests from within execute() method easier.
*
* @param string $name
* @param array $arguments
*
* @return Command
*/
public function __call(string $name, array $arguments)
{
if ($this->update === null) {
return null;
}
return call_user_func_array([$this->update, $name], $arguments);
}
/**
* Get command config
*
* Look for config $name if found return it, if not return $default.
* If $name is not set return all set config.
*
* @param string|null $name
* @param mixed $default
*
* @return mixed
*/
public function getConfig(?string $name = null, $default = null)
{
if ($name === null) {
return $this->config;
}
return $this->config[$name] ?? $default;
}
/**
* Get telegram object
*
* @return Telegram
*/
public function getTelegram(): Telegram
{
return $this->telegram;
}
/**
* Get usage
*
* @return string
*/
public function getUsage(): string
{
return $this->usage;
}
/**
* Get version
*
* @return string
*/
public function getVersion(): string
{
return $this->version;
}
/**
* Get description
*
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
/**
* Get name
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Get Show in Help
*
* @return bool
*/
public function showInHelp(): bool
{
return $this->show_in_help;
}
/**
* Check if command is enabled
*
* @return bool
*/
public function isEnabled(): bool
{
return $this->enabled;
}
/**
* If this command is intended for private chats only.
*
* @return bool
*/
public function isPrivateOnly(): bool
{
return $this->private_only;
}
/**
* If this is a SystemCommand
*
* @return bool
*/
public function isSystemCommand(): bool
{
return ($this instanceof SystemCommand);
}
/**
* If this is an AdminCommand
*
* @return bool
*/
public function isAdminCommand(): bool
{
return ($this instanceof AdminCommand);
}
/**
* If this is a UserCommand
*
* @return bool
*/
public function isUserCommand(): bool
{
return ($this instanceof UserCommand);
}
/**
* Delete the current message if it has been called in a non-private chat.
*
* @return bool
*/
protected function removeNonPrivateMessage(): bool
{
$message = $this->getMessage() ?: $this->getEditedMessage();
if ($message) {
$chat = $message->getChat();
if (!$chat->isPrivateChat()) {
// Delete the falsely called command message.
Request::deleteMessage([
'chat_id' => $chat->getId(),
'message_id' => $message->getMessageId(),
]);
return true;
}
}
return false;
}
/**
* Helper to reply to a chat directly.
*
* @param string $text
* @param array $data
*
* @return ServerResponse
* @throws TelegramException
*/
public function replyToChat(string $text, array $data = []): ServerResponse
{
if ($message = $this->getMessage() ?: $this->getEditedMessage() ?: $this->getChannelPost() ?: $this->getEditedChannelPost()) {
$reply = [
'chat_id' => $message->getChat()->getId(),
'text' => $text,
];
-
+
if ($message->getIsTopicMessage()) {
$reply['message_thread_id'] = $message->getMessageThreadId();
}
-
+
return Request::sendMessage(array_merge($reply, $data));
}
return Request::emptyResponse();
}
/**
* Helper to reply to a user directly.
*
* @param string $text
* @param array $data
*
* @return ServerResponse
* @throws TelegramException
*/
public function replyToUser(string $text, array $data = []): ServerResponse
{
if ($message = $this->getMessage() ?: $this->getEditedMessage()) {
return Request::sendMessage(array_merge([
'chat_id' => $message->getFrom()->getId(),
'text' => $text,
], $data));
}
return Request::emptyResponse();
}
}
diff --git a/src/DB.php b/src/DB.php
index cae89be..487ea7f 100644
--- a/src/DB.php
+++ b/src/DB.php
@@ -1,1725 +1,1729 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
* Written by Marco Boretto <marco.bore@gmail.com>
*/
namespace Longman\TelegramBot;
use Longman\TelegramBot\Entities\CallbackQuery;
use Longman\TelegramBot\Entities\Chat;
use Longman\TelegramBot\Entities\ChatBoostRemoved;
use Longman\TelegramBot\Entities\ChatBoostUpdated;
use Longman\TelegramBot\Entities\ChatJoinRequest;
use Longman\TelegramBot\Entities\ChatMemberUpdated;
use Longman\TelegramBot\Entities\ChosenInlineResult;
use Longman\TelegramBot\Entities\InlineQuery;
use Longman\TelegramBot\Entities\Message;
use Longman\TelegramBot\Entities\MessageReactionCountUpdated;
use Longman\TelegramBot\Entities\MessageReactionUpdated;
use Longman\TelegramBot\Entities\Payments\PreCheckoutQuery;
use Longman\TelegramBot\Entities\Payments\ShippingQuery;
use Longman\TelegramBot\Entities\Poll;
use Longman\TelegramBot\Entities\PollAnswer;
use Longman\TelegramBot\Entities\Update;
use Longman\TelegramBot\Entities\User;
use Longman\TelegramBot\Exception\TelegramException;
use PDO;
use PDOException;
class DB
{
/**
* MySQL credentials
*
* @var array
*/
protected static $mysql_credentials = [];
/**
* PDO object
*
* @var PDO
*/
protected static $pdo;
/**
* Table prefix
*
* @var string
*/
protected static $table_prefix;
/**
* Telegram class object
*
* @var Telegram
*/
protected static $telegram;
/**
* Initialize
*
* @param array $credentials Database connection details
* @param Telegram $telegram Telegram object to connect with this object
* @param string $table_prefix Table prefix
* @param string $encoding Database character encoding
*
* @return PDO PDO database object
* @throws TelegramException
*/
public static function initialize(
array $credentials,
Telegram $telegram,
$table_prefix = '',
$encoding = 'utf8mb4',
): PDO {
if (empty($credentials)) {
throw new TelegramException('MySQL credentials not provided!');
}
if (isset($credentials['unix_socket'])) {
$dsn = 'mysql:unix_socket=' . $credentials['unix_socket'];
} else {
$dsn = 'mysql:host=' . $credentials['host'];
}
$dsn .= ';dbname=' . $credentials['database'];
if (!empty($credentials['port'])) {
$dsn .= ';port=' . $credentials['port'];
}
$options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . $encoding];
try {
$pdo = new PDO($dsn, $credentials['user'], $credentials['password'], $options);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
self::$pdo = $pdo;
self::$telegram = $telegram;
self::$mysql_credentials = $credentials;
self::$table_prefix = $table_prefix;
self::defineTables();
return self::$pdo;
}
/**
* External Initialize
*
* Let you use the class with an external already existing Pdo Mysql connection.
*
* @param PDO $external_pdo_connection PDO database object
* @param Telegram $telegram Telegram object to connect with this object
* @param string $table_prefix Table prefix
*
* @return PDO PDO database object
* @throws TelegramException
*/
public static function externalInitialize(
PDO $external_pdo_connection,
Telegram $telegram,
string $table_prefix = '',
): PDO {
if ($external_pdo_connection === null) {
throw new TelegramException('MySQL external connection not provided!');
}
self::$pdo = $external_pdo_connection;
self::$telegram = $telegram;
self::$mysql_credentials = [];
self::$table_prefix = $table_prefix;
self::defineTables();
return self::$pdo;
}
/**
* Define all the tables with the proper prefix
*/
protected static function defineTables(): void
{
$tables = [
'callback_query',
'chat',
'chat_boost_updated',
'chat_boost_removed',
'chat_join_request',
'chat_member_updated',
'chosen_inline_result',
'edited_message',
'inline_query',
'message',
'message_reaction',
'message_reaction_count',
'poll',
'poll_answer',
'pre_checkout_query',
'request_limiter',
'shipping_query',
'telegram_update',
'user',
'user_chat',
];
foreach ($tables as $table) {
$table_name = 'TB_' . strtoupper($table);
if (!defined($table_name)) {
define($table_name, self::$table_prefix . $table);
}
}
}
/**
* Check if database connection has been created
*
* @return bool
*/
public static function isDbConnected(): bool
{
return self::$pdo !== null;
}
/**
* Get the PDO object of the connected database
*
* @return PDO|null
*/
public static function getPdo(): ?PDO
{
return self::$pdo;
}
/**
* Fetch update(s) from DB
*
* @param int $limit Limit the number of updates to fetch
* @param string $id Check for unique update id
*
* @return array|bool Fetched data or false if not connected
* @throws TelegramException
*/
public static function selectTelegramUpdate(int $limit = 0, string $id = '')
{
if (!self::isDbConnected()) {
return false;
}
try {
$sql = '
SELECT `id`
FROM `' . TB_TELEGRAM_UPDATE . '`
';
if ($id !== '') {
$sql .= ' WHERE `id` = :id';
} else {
$sql .= ' ORDER BY `id` DESC';
}
if ($limit > 0) {
$sql .= ' LIMIT :limit';
}
$sth = self::$pdo->prepare($sql);
if ($limit > 0) {
$sth->bindValue(':limit', $limit, PDO::PARAM_INT);
}
if ($id !== '') {
$sth->bindValue(':id', $id);
}
$sth->execute();
return $sth->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Fetch message(s) from DB
*
* @param int $limit Limit the number of messages to fetch
*
* @return array|bool Fetched data or false if not connected
* @throws TelegramException
*/
public static function selectMessages(int $limit = 0)
{
if (!self::isDbConnected()) {
return false;
}
try {
$sql = '
SELECT *
FROM `' . TB_MESSAGE . '`
ORDER BY `id` DESC
';
if ($limit > 0) {
$sql .= ' LIMIT :limit';
}
$sth = self::$pdo->prepare($sql);
if ($limit > 0) {
$sth->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$sth->execute();
return $sth->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Convert from unix timestamp to timestamp
*
* @param ?int $unixtime Unix timestamp (if empty, current timestamp is used)
*
* @return string
*/
protected static function getTimestamp(?int $unixtime = null): string
{
return date('Y-m-d H:i:s', $unixtime ?? time());
}
/**
* Convert array of Entity items to a JSON array
*
* @param array $entities
* @param mixed $default
*
* @return mixed
* @todo Find a better way, as json_* functions are very heavy
*
*/
public static function entitiesArrayToJson(array $entities, $default = null)
{
if (empty($entities)) {
return $default;
}
// Convert each Entity item into an object based on its JSON reflection
$json_entities = array_map(function ($entity) {
return json_decode($entity, true);
}, $entities);
return json_encode($json_entities);
}
/**
* Insert entry to telegram_update table
*
* @throws TelegramException
*/
protected static function insertTelegramUpdate(
int $update_id,
?int $chat_id = null,
?int $message_id = null,
?int $edited_message_id = null,
?int $channel_post_id = null,
?int $edited_channel_post_id = null,
?string $message_reaction_id = null,
?string $message_reaction_count_id = null,
?string $inline_query_id = null,
?string $chosen_inline_result_id = null,
?string $callback_query_id = null,
?string $shipping_query_id = null,
?string $pre_checkout_query_id = null,
?string $poll_id = null,
?string $poll_answer_poll_id = null,
?string $my_chat_member_updated_id = null,
?string $chat_member_updated_id = null,
?string $chat_join_request_id = null,
?string $chat_boost_updated_id = null,
?string $chat_boost_removed_id = null,
): ?bool {
if ($message_id === null && $edited_message_id === null && $channel_post_id === null && $edited_channel_post_id === null && $message_reaction_id === null && $message_reaction_count_id === null && $inline_query_id === null && $chosen_inline_result_id === null && $callback_query_id === null && $shipping_query_id === null && $pre_checkout_query_id === null && $poll_id === null && $poll_answer_poll_id === null && $my_chat_member_updated_id === null && $chat_member_updated_id === null && $chat_join_request_id === null && $chat_boost_updated_id === null && $chat_boost_removed_id === null) {
throw new TelegramException('message_id, edited_message_id, channel_post_id, edited_channel_post_id, message_reaction_id, message_reaction_count_id, inline_query_id, chosen_inline_result_id, callback_query_id, shipping_query_id, pre_checkout_query_id, poll_id, poll_answer_poll_id, my_chat_member_updated_id, chat_member_updated_id, chat_join_request_id, chat_boost_updated_id, chat_boost_removed_id are all null');
}
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_TELEGRAM_UPDATE . '`
(
`id`, `chat_id`, `message_id`, `edited_message_id`,
`channel_post_id`, `edited_channel_post_id`, `message_reaction_id`, `message_reaction_count_id`,
`inline_query_id`, `chosen_inline_result_id`,
`callback_query_id`, `shipping_query_id`, `pre_checkout_query_id`,
`poll_id`, `poll_answer_poll_id`, `my_chat_member_updated_id`, `chat_member_updated_id`,
`chat_join_request_id`, `chat_boost_updated_id`, `chat_boost_removed_id`
) VALUES (
:id, :chat_id, :message_id, :edited_message_id,
:channel_post_id, :edited_channel_post_id, :message_reaction_id, :message_reaction_count_id,
:inline_query_id, :chosen_inline_result_id,
:callback_query_id, :shipping_query_id, :pre_checkout_query_id,
:poll_id, :poll_answer_poll_id, :my_chat_member_updated_id, :chat_member_updated_id,
:chat_join_request_id, :chat_boost_updated_id, :chat_boost_removed_id
)
');
$sth->bindValue(':id', $update_id);
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':message_id', $message_id);
$sth->bindValue(':edited_message_id', $edited_message_id);
$sth->bindValue(':channel_post_id', $channel_post_id);
$sth->bindValue(':edited_channel_post_id', $edited_channel_post_id);
$sth->bindValue(':message_reaction_id', $message_reaction_id);
$sth->bindValue(':message_reaction_count_id', $message_reaction_count_id);
$sth->bindValue(':inline_query_id', $inline_query_id);
$sth->bindValue(':chosen_inline_result_id', $chosen_inline_result_id);
$sth->bindValue(':callback_query_id', $callback_query_id);
$sth->bindValue(':shipping_query_id', $shipping_query_id);
$sth->bindValue(':pre_checkout_query_id', $pre_checkout_query_id);
$sth->bindValue(':poll_id', $poll_id);
$sth->bindValue(':poll_answer_poll_id', $poll_answer_poll_id);
$sth->bindValue(':my_chat_member_updated_id', $my_chat_member_updated_id);
$sth->bindValue(':chat_member_updated_id', $chat_member_updated_id);
$sth->bindValue(':chat_join_request_id', $chat_join_request_id);
$sth->bindValue(':chat_boost_updated_id', $chat_boost_updated_id);
$sth->bindValue(':chat_boost_removed_id', $chat_boost_removed_id);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert users and save their connection to chats
*
* @param User $user
* @param string|null $date
* @param Chat|null $chat
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertUser(User $user, ?string $date = null, ?Chat $chat = null): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_USER . '`
(`id`, `is_bot`, `username`, `first_name`, `last_name`, `language_code`, `is_premium`, `added_to_attachment_menu`, `created_at`, `updated_at`)
VALUES
(:id, :is_bot, :username, :first_name, :last_name, :language_code, :is_premium, :added_to_attachment_menu, :created_at, :updated_at)
ON DUPLICATE KEY UPDATE
`is_bot` = VALUES(`is_bot`),
`username` = VALUES(`username`),
`first_name` = VALUES(`first_name`),
`last_name` = VALUES(`last_name`),
`language_code` = VALUES(`language_code`),
`is_premium` = VALUES(`is_premium`),
`added_to_attachment_menu` = VALUES(`added_to_attachment_menu`),
`updated_at` = VALUES(`updated_at`)
');
$sth->bindValue(':id', $user->getId());
$sth->bindValue(':is_bot', $user->getIsBot(), PDO::PARAM_INT);
$sth->bindValue(':username', $user->getUsername());
$sth->bindValue(':first_name', $user->getFirstName());
$sth->bindValue(':last_name', $user->getLastName());
$sth->bindValue(':language_code', $user->getLanguageCode());
$sth->bindValue(':is_premium', $user->getIsPremium(), PDO::PARAM_INT);
$sth->bindValue(':added_to_attachment_menu', $user->getAddedToAttachmentMenu(), PDO::PARAM_INT);
$date = $date ?: self::getTimestamp();
$sth->bindValue(':created_at', $date);
$sth->bindValue(':updated_at', $date);
$status = $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
// Also insert the relationship to the chat into the user_chat table
if ($chat) {
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_USER_CHAT . '`
(`user_id`, `chat_id`)
VALUES
(:user_id, :chat_id)
');
$sth->bindValue(':user_id', $user->getId());
$sth->bindValue(':chat_id', $chat->getId());
$status = $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
return $status;
}
/**
* Insert chat
*
* @param Chat $chat
* @param string|null $date
* @param int|null $migrate_to_chat_id
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChat(Chat $chat, ?string $date = null, ?int $migrate_to_chat_id = null): ?bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_CHAT . '`
(`id`, `type`, `title`, `username`, `first_name`, `last_name`, `is_forum`, `created_at` ,`updated_at`, `old_id`)
VALUES
(:id, :type, :title, :username, :first_name, :last_name, :is_forum, :created_at, :updated_at, :old_id)
ON DUPLICATE KEY UPDATE
`type` = VALUES(`type`),
`title` = VALUES(`title`),
`username` = VALUES(`username`),
`first_name` = VALUES(`first_name`),
`last_name` = VALUES(`last_name`),
`is_forum` = VALUES(`is_forum`),
`updated_at` = VALUES(`updated_at`)
');
$chat_id = $chat->getId();
$chat_type = $chat->getType();
if ($migrate_to_chat_id !== null) {
$chat_type = 'supergroup';
$sth->bindValue(':id', $migrate_to_chat_id);
$sth->bindValue(':old_id', $chat_id);
} else {
$sth->bindValue(':id', $chat_id);
$sth->bindValue(':old_id', $migrate_to_chat_id);
}
$sth->bindValue(':type', $chat_type);
$sth->bindValue(':title', $chat->getTitle());
$sth->bindValue(':username', $chat->getUsername());
$sth->bindValue(':first_name', $chat->getFirstName());
$sth->bindValue(':last_name', $chat->getLastName());
$sth->bindValue(':is_forum', $chat->getIsForum());
$date = $date ?: self::getTimestamp();
$sth->bindValue(':created_at', $date);
$sth->bindValue(':updated_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert request into database
*
* @param Update $update
*
* @return bool
* @throws TelegramException
* @todo self::$pdo->lastInsertId() - unsafe usage if expected previous insert fails?
*
*/
public static function insertRequest(Update $update): bool
{
if (!self::isDbConnected()) {
return false;
}
$chat_id = null;
$message_id = null;
$edited_message_id = null;
$channel_post_id = null;
$edited_channel_post_id = null;
$message_reaction_id = null;
$message_reaction_count_id = null;
$inline_query_id = null;
$chosen_inline_result_id = null;
$callback_query_id = null;
$shipping_query_id = null;
$pre_checkout_query_id = null;
$poll_id = null;
$poll_answer_poll_id = null;
$my_chat_member_updated_id = null;
$chat_member_updated_id = null;
$chat_join_request_id = null;
$chat_boost_updated_id = null;
$chat_boost_removed_id = null;
if (($message = $update->getMessage()) && self::insertMessageRequest($message)) {
$chat_id = $message->getChat()->getId();
$message_id = $message->getMessageId();
} elseif (($edited_message = $update->getEditedMessage()) && self::insertEditedMessageRequest($edited_message)) {
$chat_id = $edited_message->getChat()->getId();
$edited_message_id = (int) self::$pdo->lastInsertId();
} elseif (($channel_post = $update->getChannelPost()) && self::insertMessageRequest($channel_post)) {
$chat_id = $channel_post->getChat()->getId();
$channel_post_id = $channel_post->getMessageId();
} elseif (($edited_channel_post = $update->getEditedChannelPost()) && self::insertEditedMessageRequest($edited_channel_post)) {
$chat_id = $edited_channel_post->getChat()->getId();
$edited_channel_post_id = (int) self::$pdo->lastInsertId();
} elseif (($message_reaction = $update->getMessageReaction()) && self::insertMessageReaction($message_reaction)) {
$chat_id = $message_reaction->getChat()->getId();
$message_id = $message_reaction->getMessageId();
$message_reaction_id = self::$pdo->lastInsertId();
} elseif (($message_reaction_count = $update->getMessageReactionCount()) && self::insertMessageReactionCount($message_reaction_count)) {
$chat_id = $message_reaction_count->getChat()->getId();
$message_id = $message_reaction_count->getMessageId();
$message_reaction_count_id = self::$pdo->lastInsertId();
} elseif (($inline_query = $update->getInlineQuery()) && self::insertInlineQueryRequest($inline_query)) {
$inline_query_id = $inline_query->getId();
} elseif (($chosen_inline_result = $update->getChosenInlineResult()) && self::insertChosenInlineResultRequest($chosen_inline_result)) {
$chosen_inline_result_id = self::$pdo->lastInsertId();
} elseif (($callback_query = $update->getCallbackQuery()) && self::insertCallbackQueryRequest($callback_query)) {
$callback_query_id = $callback_query->getId();
} elseif (($shipping_query = $update->getShippingQuery()) && self::insertShippingQueryRequest($shipping_query)) {
$shipping_query_id = $shipping_query->getId();
} elseif (($pre_checkout_query = $update->getPreCheckoutQuery()) && self::insertPreCheckoutQueryRequest($pre_checkout_query)) {
$pre_checkout_query_id = $pre_checkout_query->getId();
} elseif (($poll = $update->getPoll()) && self::insertPollRequest($poll)) {
$poll_id = $poll->getId();
} elseif (($poll_answer = $update->getPollAnswer()) && self::insertPollAnswerRequest($poll_answer)) {
$poll_answer_poll_id = $poll_answer->getPollId();
} elseif (($my_chat_member = $update->getMyChatMember()) && self::insertChatMemberUpdatedRequest($my_chat_member)) {
$my_chat_member_updated_id = self::$pdo->lastInsertId();
} elseif (($chat_member = $update->getChatMember()) && self::insertChatMemberUpdatedRequest($chat_member)) {
$chat_member_updated_id = self::$pdo->lastInsertId();
} elseif (($chat_join_request = $update->getChatJoinRequest()) && self::insertChatJoinRequestRequest($chat_join_request)) {
$chat_join_request_id = self::$pdo->lastInsertId();
} elseif (($chat_boost_updated = $update->getChatBoost()) && self::insertChatBoostUpdatedRequest($chat_boost_updated)) {
$chat_boost_updated_id = self::$pdo->lastInsertId();
} elseif (($chat_boost_removed = $update->getRemovedChatBoost()) && self::insertChatBoostRemovedRequest($chat_boost_removed)) {
$chat_boost_removed_id = self::$pdo->lastInsertId();
} else {
return false;
}
return self::insertTelegramUpdate(
$update->getUpdateId(),
$chat_id,
$message_id,
$edited_message_id,
$channel_post_id,
$edited_channel_post_id,
$message_reaction_id,
$message_reaction_count_id,
$inline_query_id,
$chosen_inline_result_id,
$callback_query_id,
$shipping_query_id,
$pre_checkout_query_id,
$poll_id,
$poll_answer_poll_id,
$my_chat_member_updated_id,
$chat_member_updated_id,
$chat_join_request_id,
$chat_boost_updated_id,
$chat_boost_removed_id,
);
}
public static function insertMessageReaction(MessageReactionUpdated $message_reaction): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_MESSAGE_REACTION . '`
(`chat_id`, `message_id`, `user_id`, `actor_chat_id`, `old_reaction`, `new_reaction`, `created_at`)
VALUES
(:chat_id, :message_id, :user_id, :actor_chat_id, :old_reaction, :new_reaction, :created_at)
');
$date = self::getTimestamp($message_reaction->getDate());
$chat_id = null;
$user_id = null;
$actor_chat_id = null;
if ($chat = $message_reaction->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
if ($user = $message_reaction->getUser()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
if ($actor_chat = $message_reaction->getActorChat()) {
$actor_chat_id = $actor_chat->getId();
self::insertChat($actor_chat, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':message_id', $message_reaction->getMessageId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':actor_chat_id', $actor_chat_id);
$sth->bindValue(':old_reaction', self::entitiesArrayToJson($message_reaction->getOldReaction() ?: []));
$sth->bindValue(':new_reaction', self::entitiesArrayToJson($message_reaction->getNewReaction() ?: []));
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
public static function insertMessageReactionCount(MessageReactionCountUpdated $message_reaction_count): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_MESSAGE_REACTION_COUNT . '`
(`chat_id`, `message_id`, `reactions`, `created_at`)
VALUES
(:chat_id, :message_id, :reactions, :created_at)
');
$date = self::getTimestamp($message_reaction_count->getDate());
$chat_id = null;
if ($chat = $message_reaction->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':message_id', $message_reaction_count->getMessageId());
$sth->bindValue(':reactions', $message_reaction_count->getReactions());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert inline query request into database
*
* @param InlineQuery $inline_query
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertInlineQueryRequest(InlineQuery $inline_query): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_INLINE_QUERY . '`
(`id`, `user_id`, `location`, `query`, `offset`, `chat_type`, `created_at`)
VALUES
(:id, :user_id, :location, :query, :offset, :chat_type, :created_at)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $inline_query->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':id', $inline_query->getId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':location', $inline_query->getLocation());
$sth->bindValue(':query', $inline_query->getQuery());
$sth->bindValue(':offset', $inline_query->getOffset());
$sth->bindValue(':chat_type', $inline_query->getChatType());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert chosen inline result request into database
*
* @param ChosenInlineResult $chosen_inline_result
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChosenInlineResultRequest(ChosenInlineResult $chosen_inline_result): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_CHOSEN_INLINE_RESULT . '`
(`result_id`, `user_id`, `location`, `inline_message_id`, `query`, `created_at`)
VALUES
(:result_id, :user_id, :location, :inline_message_id, :query, :created_at)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $chosen_inline_result->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':result_id', $chosen_inline_result->getResultId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':location', $chosen_inline_result->getLocation());
$sth->bindValue(':inline_message_id', $chosen_inline_result->getInlineMessageId());
$sth->bindValue(':query', $chosen_inline_result->getQuery());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert callback query request into database
*
* @param CallbackQuery $callback_query
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertCallbackQueryRequest(CallbackQuery $callback_query): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_CALLBACK_QUERY . '`
(`id`, `user_id`, `chat_id`, `message_id`, `inline_message_id`, `chat_instance`, `data`, `game_short_name`, `created_at`)
VALUES
(:id, :user_id, :chat_id, :message_id, :inline_message_id, :chat_instance, :data, :game_short_name, :created_at)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $callback_query->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$chat_id = null;
$message_id = null;
if ($message = $callback_query->getMessage()) {
$chat_id = $message->getChat()->getId();
$message_id = $message->getMessageId();
$is_message = self::$pdo->query('
SELECT *
FROM `' . TB_MESSAGE . '`
WHERE `id` = ' . $message_id . '
AND `chat_id` = ' . $chat_id . '
LIMIT 1
')->rowCount();
if ($is_message) {
self::insertEditedMessageRequest($message);
} else {
self::insertMessageRequest($message);
}
}
$sth->bindValue(':id', $callback_query->getId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':message_id', $message_id);
$sth->bindValue(':inline_message_id', $callback_query->getInlineMessageId());
$sth->bindValue(':chat_instance', $callback_query->getChatInstance());
$sth->bindValue(':data', $callback_query->getData());
$sth->bindValue(':game_short_name', $callback_query->getGameShortName());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert shipping query request into database
*
* @param ShippingQuery $shipping_query
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertShippingQueryRequest(ShippingQuery $shipping_query): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_SHIPPING_QUERY . '`
(`id`, `user_id`, `invoice_payload`, `shipping_address`, `created_at`)
VALUES
(:id, :user_id, :invoice_payload, :shipping_address, :created_at)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $shipping_query->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':id', $shipping_query->getId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':invoice_payload', $shipping_query->getInvoicePayload());
$sth->bindValue(':shipping_address', $shipping_query->getShippingAddress());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert pre checkout query request into database
*
* @param PreCheckoutQuery $pre_checkout_query
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertPreCheckoutQueryRequest(PreCheckoutQuery $pre_checkout_query): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_PRE_CHECKOUT_QUERY . '`
(`id`, `user_id`, `currency`, `total_amount`, `invoice_payload`, `shipping_option_id`, `order_info`, `created_at`)
VALUES
(:id, :user_id, :currency, :total_amount, :invoice_payload, :shipping_option_id, :order_info, :created_at)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $pre_checkout_query->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':id', $pre_checkout_query->getId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':currency', $pre_checkout_query->getCurrency());
$sth->bindValue(':total_amount', $pre_checkout_query->getTotalAmount());
$sth->bindValue(':invoice_payload', $pre_checkout_query->getInvoicePayload());
$sth->bindValue(':shipping_option_id', $pre_checkout_query->getShippingOptionId());
$sth->bindValue(':order_info', $pre_checkout_query->getOrderInfo());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert poll request into database
*
* @param Poll $poll
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertPollRequest(Poll $poll): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_POLL . '`
(`id`, `question`, `options`, `total_voter_count`, `is_closed`, `is_anonymous`, `type`, `allows_multiple_answers`, `correct_option_id`, `explanation`, `explanation_entities`, `open_period`, `close_date`, `created_at`)
VALUES
(:id, :question, :options, :total_voter_count, :is_closed, :is_anonymous, :type, :allows_multiple_answers, :correct_option_id, :explanation, :explanation_entities, :open_period, :close_date, :created_at)
ON DUPLICATE KEY UPDATE
`options` = VALUES(`options`),
`total_voter_count` = VALUES(`total_voter_count`),
`is_closed` = VALUES(`is_closed`),
`is_anonymous` = VALUES(`is_anonymous`),
`type` = VALUES(`type`),
`allows_multiple_answers` = VALUES(`allows_multiple_answers`),
`correct_option_id` = VALUES(`correct_option_id`),
`explanation` = VALUES(`explanation`),
`explanation_entities` = VALUES(`explanation_entities`),
`open_period` = VALUES(`open_period`),
`close_date` = VALUES(`close_date`)
');
$sth->bindValue(':id', $poll->getId());
$sth->bindValue(':question', $poll->getQuestion());
$sth->bindValue(':options', self::entitiesArrayToJson($poll->getOptions() ?: []));
$sth->bindValue(':total_voter_count', $poll->getTotalVoterCount());
$sth->bindValue(':is_closed', $poll->getIsClosed(), PDO::PARAM_INT);
$sth->bindValue(':is_anonymous', $poll->getIsAnonymous(), PDO::PARAM_INT);
$sth->bindValue(':type', $poll->getType());
$sth->bindValue(':allows_multiple_answers', $poll->getAllowsMultipleAnswers(), PDO::PARAM_INT);
$sth->bindValue(':correct_option_id', $poll->getCorrectOptionId());
$sth->bindValue(':explanation', $poll->getExplanation());
$sth->bindValue(':explanation_entities', self::entitiesArrayToJson($poll->getExplanationEntities() ?: []));
$sth->bindValue(':open_period', $poll->getOpenPeriod());
$sth->bindValue(':close_date', self::getTimestamp($poll->getCloseDate()));
$sth->bindValue(':created_at', self::getTimestamp());
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert poll answer request into database
*
* @param PollAnswer $poll_answer
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertPollAnswerRequest(PollAnswer $poll_answer): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_POLL_ANSWER . '`
(`poll_id`, `user_id`, `option_ids`, `created_at`)
VALUES
(:poll_id, :user_id, :option_ids, :created_at)
ON DUPLICATE KEY UPDATE
`option_ids` = VALUES(`option_ids`)
');
$date = self::getTimestamp();
$user_id = null;
if ($user = $poll_answer->getUser()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':poll_id', $poll_answer->getPollId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':option_ids', json_encode($poll_answer->getOptionIds()));
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert chat member updated request into database
*
* @param ChatMemberUpdated $chat_member_updated
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChatMemberUpdatedRequest(ChatMemberUpdated $chat_member_updated): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_CHAT_MEMBER_UPDATED . '`
(`chat_id`, `user_id`, `date`, `old_chat_member`, `new_chat_member`, `invite_link`, `created_at`)
VALUES
(:chat_id, :user_id, :date, :old_chat_member, :new_chat_member, :invite_link, :created_at)
');
$date = self::getTimestamp();
$chat_id = null;
$user_id = null;
if ($chat = $chat_member_updated->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
if ($user = $chat_member_updated->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':date', self::getTimestamp($chat_member_updated->getDate()));
$sth->bindValue(':old_chat_member', $chat_member_updated->getOldChatMember());
$sth->bindValue(':new_chat_member', $chat_member_updated->getNewChatMember());
$sth->bindValue(':invite_link', $chat_member_updated->getInviteLink());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert chat join request into database
*
* @param ChatJoinRequest $chat_join_request
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChatJoinRequestRequest(ChatJoinRequest $chat_join_request): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_CHAT_JOIN_REQUEST . '`
(`chat_id`, `user_id`, `date`, `bio`, `invite_link`, `created_at`)
VALUES
(:chat_id, :user_id, :date, :bio, :invite_link, :created_at)
');
$date = self::getTimestamp();
$chat_id = null;
$user_id = null;
if ($chat = $chat_join_request->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
if ($user = $chat_join_request->getFrom()) {
$user_id = $user->getId();
self::insertUser($user, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':date', self::getTimestamp($chat_join_request->getDate()));
$sth->bindValue(':bio', $chat_join_request->getBio());
$sth->bindValue(':invite_link', $chat_join_request->getInviteLink());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert chat boost updated into database
*
* @param ChatBoostUpdated $chat_boost_updated
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChatBoostUpdatedRequest(ChatBoostUpdated $chat_boost_updated): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_CHAT_BOOST_UPDATED . '`
(`chat_id`, `boost`, `created_at`)
VALUES
(:chat_id, :boost, :created_at)
');
$date = self::getTimestamp();
$chat_id = null;
if ($chat = $chat_boost_updated->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':boost', $chat_boost_updated->getBoost());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert chat boost removed into database
*
* @param ChatBoostRemoved $chat_boost_removed
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertChatBoostRemovedRequest(ChatBoostRemoved $chat_boost_removed): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('
INSERT INTO `' . TB_CHAT_BOOST_REMOVED . '`
(`chat_id`, `boost_id`, `remove_date`, `source`, `created_at`)
VALUES
(:chat_id, :boost_id, :remove_date, :source, :created_at)
');
$date = self::getTimestamp();
$chat_id = null;
if ($chat = $chat_boost_removed->getChat()) {
$chat_id = $chat->getId();
self::insertChat($chat, $date);
}
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':boost_id', $chat_boost_removed->getBoostId());
$sth->bindValue(':remove_date', self::getTimestamp($chat_boost_removed->getRemoveDate()));
$sth->bindValue(':source', $chat_boost_removed->getSource());
$sth->bindValue(':created_at', $date);
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert Message request in db
*
* @param Message $message
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertMessageRequest(Message $message): bool
{
if (!self::isDbConnected()) {
return false;
}
$date = self::getTimestamp($message->getDate());
// Insert chat, update chat id in case it migrated
$chat = $message->getChat();
self::insertChat($chat, $date, $message->getMigrateToChatId());
$sender_chat_id = null;
if ($sender_chat = $message->getSenderChat()) {
self::insertChat($sender_chat);
$sender_chat_id = $sender_chat->getId();
}
// Insert user and the relation with the chat
if ($user = $message->getFrom()) {
self::insertUser($user, $date, $chat);
}
// Insert the forwarded message user in users table
$forward_date = $message->getForwardDate() ? self::getTimestamp($message->getForwardDate()) : null;
if ($forward_from = $message->getForwardFrom()) {
self::insertUser($forward_from);
$forward_from = $forward_from->getId();
}
if ($forward_from_chat = $message->getForwardFromChat()) {
self::insertChat($forward_from_chat);
$forward_from_chat = $forward_from_chat->getId();
}
$via_bot_id = null;
if ($via_bot = $message->getViaBot()) {
self::insertUser($via_bot);
$via_bot_id = $via_bot->getId();
}
// New and left chat member
$new_chat_members_ids = null;
$left_chat_member_id = null;
$new_chat_members = $message->getNewChatMembers();
$left_chat_member = $message->getLeftChatMember();
if (!empty($new_chat_members)) {
foreach ($new_chat_members as $new_chat_member) {
if ($new_chat_member instanceof User) {
// Insert the new chat user
self::insertUser($new_chat_member, $date, $chat);
$new_chat_members_ids[] = $new_chat_member->getId();
}
}
$new_chat_members_ids = implode(',', $new_chat_members_ids);
} elseif ($left_chat_member) {
// Insert the left chat user
self::insertUser($left_chat_member, $date, $chat);
$left_chat_member_id = $left_chat_member->getId();
}
try {
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_MESSAGE . '`
(
- `id`, `user_id`, `chat_id`, `message_thread_id`, `sender_chat_id`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
+ `id`, `user_id`, `chat_id`, `message_thread_id`, `sender_chat_id`, `sender_boost_count`, `date`, `forward_from`, `forward_from_chat`, `forward_from_message_id`,
`forward_signature`, `forward_sender_name`, `forward_date`, `is_topic_message`,
- `reply_to_chat`, `reply_to_message`, `external_reply`, `via_bot`, `link_preview_options`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`,
+ `reply_to_chat`, `reply_to_message`, `external_reply`, `quote`, `reply_to_story`, `via_bot`, `link_preview_options`, `edit_date`, `media_group_id`, `author_signature`, `text`, `entities`, `caption_entities`,
`audio`, `document`, `animation`, `game`, `photo`, `sticker`, `story`, `video`, `voice`, `video_note`, `caption`, `has_media_spoiler`, `contact`,
`location`, `venue`, `poll`, `dice`, `new_chat_members`, `left_chat_member`,
`new_chat_title`, `new_chat_photo`, `delete_chat_photo`, `group_chat_created`,
`supergroup_chat_created`, `channel_chat_created`, `message_auto_delete_timer_changed`, `migrate_to_chat_id`, `migrate_from_chat_id`,
- `pinned_message`, `invoice`, `successful_payment`, `users_shared`, `chat_shared`, `connected_website`, `write_access_allowed`, `passport_data`, `proximity_alert_triggered`,
+ `pinned_message`, `invoice`, `successful_payment`, `users_shared`, `chat_shared`, `connected_website`, `write_access_allowed`, `passport_data`, `proximity_alert_triggered`, `boost_added`,
`forum_topic_created`, `forum_topic_edited`, `forum_topic_closed`, `forum_topic_reopened`, `general_forum_topic_hidden`, `general_forum_topic_unhidden`,
`video_chat_scheduled`, `video_chat_started`, `video_chat_ended`, `video_chat_participants_invited`, `web_app_data`, `reply_markup`
) VALUES (
- :message_id, :user_id, :chat_id, :message_thread_id, :sender_chat_id, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
+ :message_id, :user_id, :chat_id, :message_thread_id, :sender_chat_id, :sender_boost_count, :date, :forward_from, :forward_from_chat, :forward_from_message_id,
:forward_signature, :forward_sender_name, :forward_date, :is_topic_message,
- :reply_to_chat, :reply_to_message, :external_reply, :via_bot, :link_preview_options, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities,
+ :reply_to_chat, :reply_to_message, :external_reply, :quote, :reply_to_story, :via_bot, :link_preview_options, :edit_date, :media_group_id, :author_signature, :text, :entities, :caption_entities,
:audio, :document, :animation, :game, :photo, :sticker, :story, :video, :voice, :video_note, :caption, :has_media_spoiler, :contact,
:location, :venue, :poll, :dice, :new_chat_members, :left_chat_member,
:new_chat_title, :new_chat_photo, :delete_chat_photo, :group_chat_created,
:supergroup_chat_created, :channel_chat_created, :message_auto_delete_timer_changed, :migrate_to_chat_id, :migrate_from_chat_id,
- :pinned_message, :invoice, :successful_payment, :users_shared, :chat_shared, :connected_website, :write_access_allowed, :passport_data, :proximity_alert_triggered,
+ :pinned_message, :invoice, :successful_payment, :users_shared, :chat_shared, :connected_website, :write_access_allowed, :passport_data, :proximity_alert_triggered, :boost_added,
:forum_topic_created, :forum_topic_edited, :forum_topic_closed, :forum_topic_reopened, :general_forum_topic_hidden, :general_forum_topic_unhidden,
:video_chat_scheduled, :video_chat_started, :video_chat_ended, :video_chat_participants_invited, :web_app_data, :reply_markup
)
');
$user_id = $user ? $user->getId() : null;
$chat_id = $chat->getId();
$reply_to_message_id = null;
if ($reply_to_message = $message->getReplyToMessage()) {
$reply_to_message_id = $reply_to_message->getMessageId();
// please notice that, as explained in the documentation, reply_to_message don't contain other
// reply_to_message field so recursion deep is 1
self::insertMessageRequest($reply_to_message);
}
$sth->bindValue(':message_id', $message->getMessageId());
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':sender_chat_id', $sender_chat_id);
$sth->bindValue(':message_thread_id', $message->getMessageThreadId());
$sth->bindValue(':user_id', $user_id);
+ $sth->bindValue(':sender_boost_count', $message->getSenderBoostCount());
$sth->bindValue(':date', $date);
$sth->bindValue(':forward_from', $forward_from);
$sth->bindValue(':forward_from_chat', $forward_from_chat);
$sth->bindValue(':forward_from_message_id', $message->getForwardFromMessageId());
$sth->bindValue(':forward_signature', $message->getForwardSignature());
$sth->bindValue(':forward_sender_name', $message->getForwardSenderName());
$sth->bindValue(':forward_date', $forward_date);
$sth->bindValue(':is_topic_message', $message->getIsTopicMessage());
$reply_to_chat_id = null;
if ($reply_to_message_id !== null) {
$reply_to_chat_id = $chat_id;
}
$sth->bindValue(':reply_to_chat', $reply_to_chat_id);
$sth->bindValue(':reply_to_message', $reply_to_message_id);
$sth->bindValue(':external_reply', $message->getExternalReply());
+ $sth->bindValue(':quote', $message->getQuote());
+ $sth->bindValue(':reply_to_story', $message->getReplyToStory());
$sth->bindValue(':via_bot', $via_bot_id);
$sth->bindValue(':link_preview_options', $message->getLinkPreviewOptions());
$sth->bindValue(':edit_date', self::getTimestamp($message->getEditDate()));
$sth->bindValue(':media_group_id', $message->getMediaGroupId());
$sth->bindValue(':author_signature', $message->getAuthorSignature());
$sth->bindValue(':text', $message->getText());
$sth->bindValue(':entities', self::entitiesArrayToJson($message->getEntities() ?: []));
$sth->bindValue(':caption_entities', self::entitiesArrayToJson($message->getCaptionEntities() ?: []));
$sth->bindValue(':audio', $message->getAudio());
$sth->bindValue(':document', $message->getDocument());
$sth->bindValue(':animation', $message->getAnimation());
$sth->bindValue(':game', $message->getGame());
$sth->bindValue(':photo', self::entitiesArrayToJson($message->getPhoto() ?: []));
$sth->bindValue(':sticker', $message->getSticker());
$sth->bindValue(':story', $message->getStory());
$sth->bindValue(':video', $message->getVideo());
$sth->bindValue(':voice', $message->getVoice());
$sth->bindValue(':video_note', $message->getVideoNote());
$sth->bindValue(':caption', $message->getCaption());
$sth->bindValue(':has_media_spoiler', $message->getHasMediaSpoiler());
$sth->bindValue(':contact', $message->getContact());
$sth->bindValue(':location', $message->getLocation());
$sth->bindValue(':venue', $message->getVenue());
$sth->bindValue(':poll', $message->getPoll());
$sth->bindValue(':dice', $message->getDice());
$sth->bindValue(':new_chat_members', $new_chat_members_ids);
$sth->bindValue(':left_chat_member', $left_chat_member_id);
$sth->bindValue(':new_chat_title', $message->getNewChatTitle());
$sth->bindValue(':new_chat_photo', self::entitiesArrayToJson($message->getNewChatPhoto() ?: []));
$sth->bindValue(':delete_chat_photo', $message->getDeleteChatPhoto());
$sth->bindValue(':group_chat_created', $message->getGroupChatCreated());
$sth->bindValue(':supergroup_chat_created', $message->getSupergroupChatCreated());
$sth->bindValue(':channel_chat_created', $message->getChannelChatCreated());
$sth->bindValue(':message_auto_delete_timer_changed', $message->getMessageAutoDeleteTimerChanged());
$sth->bindValue(':migrate_to_chat_id', $message->getMigrateToChatId());
$sth->bindValue(':migrate_from_chat_id', $message->getMigrateFromChatId());
$sth->bindValue(':pinned_message', $message->getPinnedMessage());
$sth->bindValue(':invoice', $message->getInvoice());
$sth->bindValue(':successful_payment', $message->getSuccessfulPayment());
$sth->bindValue(':users_shared', $message->getUsersShared());
$sth->bindValue(':chat_shared', $message->getChatShared());
$sth->bindValue(':connected_website', $message->getConnectedWebsite());
$sth->bindValue(':write_access_allowed', $message->getWriteAccessAllowed());
$sth->bindValue(':passport_data', $message->getPassportData());
$sth->bindValue(':proximity_alert_triggered', $message->getProximityAlertTriggered());
+ $sth->bindValue(':boost_added', $message->getBoostAdded());
$sth->bindValue(':forum_topic_created', $message->getForumTopicCreated());
$sth->bindValue(':forum_topic_edited', $message->getForumTopicEdited());
$sth->bindValue(':forum_topic_closed', $message->getForumTopicClosed());
$sth->bindValue(':forum_topic_reopened', $message->getForumTopicReopened());
$sth->bindValue(':general_forum_topic_hidden', $message->getGeneralForumTopicHidden());
$sth->bindValue(':general_forum_topic_unhidden', $message->getGeneralForumTopicUnhidden());
$sth->bindValue(':video_chat_scheduled', $message->getVideoChatScheduled());
$sth->bindValue(':video_chat_started', $message->getVideoChatStarted());
$sth->bindValue(':video_chat_ended', $message->getVideoChatEnded());
$sth->bindValue(':video_chat_participants_invited', $message->getVideoChatParticipantsInvited());
$sth->bindValue(':web_app_data', $message->getWebAppData());
$sth->bindValue(':reply_markup', $message->getReplyMarkup());
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert Edited Message request in db
*
* @param Message $edited_message
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertEditedMessageRequest(Message $edited_message): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$edit_date = self::getTimestamp($edited_message->getEditDate());
// Insert chat
$chat = $edited_message->getChat();
self::insertChat($chat, $edit_date);
// Insert user and the relation with the chat
if ($user = $edited_message->getFrom()) {
self::insertUser($user, $edit_date, $chat);
}
$sth = self::$pdo->prepare('
INSERT IGNORE INTO `' . TB_EDITED_MESSAGE . '`
(`chat_id`, `message_id`, `user_id`, `edit_date`, `text`, `entities`, `caption`)
VALUES
(:chat_id, :message_id, :user_id, :edit_date, :text, :entities, :caption)
');
$user_id = $user ? $user->getId() : null;
$sth->bindValue(':chat_id', $chat->getId());
$sth->bindValue(':message_id', $edited_message->getMessageId());
$sth->bindValue(':user_id', $user_id);
$sth->bindValue(':edit_date', $edit_date);
$sth->bindValue(':text', $edited_message->getText());
$sth->bindValue(':entities', self::entitiesArrayToJson($edited_message->getEntities() ?: []));
$sth->bindValue(':caption', $edited_message->getCaption());
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Select Groups, Supergroups, Channels and/or single user Chats (also by ID or text)
*
* @param $select_chats_params
*
* @return array|bool
* @throws TelegramException
*/
public static function selectChats($select_chats_params)
{
if (!self::isDbConnected()) {
return false;
}
// Set defaults for omitted values.
$select = array_merge([
'groups' => true,
'supergroups' => true,
'channels' => true,
'users' => true,
'date_from' => null,
'date_to' => null,
'chat_id' => null,
'text' => null,
'language' => null,
], $select_chats_params);
if (!$select['groups'] && !$select['users'] && !$select['supergroups'] && !$select['channels']) {
return false;
}
try {
$query = '
SELECT * ,
' . TB_CHAT . '.`id` AS `chat_id`,
' . TB_CHAT . '.`username` AS `chat_username`,
' . TB_CHAT . '.`created_at` AS `chat_created_at`,
' . TB_CHAT . '.`updated_at` AS `chat_updated_at`
';
if ($select['users']) {
$query .= '
, ' . TB_USER . '.`id` AS `user_id`
FROM `' . TB_CHAT . '`
LEFT JOIN `' . TB_USER . '`
ON ' . TB_CHAT . '.`id`=' . TB_USER . '.`id`
';
} else {
$query .= 'FROM `' . TB_CHAT . '`';
}
// Building parts of query
$where = [];
$tokens = [];
if (!$select['groups'] || !$select['users'] || !$select['supergroups'] || !$select['channels']) {
$chat_or_user = [];
$select['groups'] && $chat_or_user[] = TB_CHAT . '.`type` = "group"';
$select['supergroups'] && $chat_or_user[] = TB_CHAT . '.`type` = "supergroup"';
$select['channels'] && $chat_or_user[] = TB_CHAT . '.`type` = "channel"';
$select['users'] && $chat_or_user[] = TB_CHAT . '.`type` = "private"';
$where[] = '(' . implode(' OR ', $chat_or_user) . ')';
}
if (null !== $select['date_from']) {
$where[] = TB_CHAT . '.`updated_at` >= :date_from';
$tokens[':date_from'] = $select['date_from'];
}
if (null !== $select['date_to']) {
$where[] = TB_CHAT . '.`updated_at` <= :date_to';
$tokens[':date_to'] = $select['date_to'];
}
if (null !== $select['chat_id']) {
$where[] = TB_CHAT . '.`id` = :chat_id';
$tokens[':chat_id'] = $select['chat_id'];
}
if ($select['users'] && null !== $select['language']) {
$where[] = TB_USER . '.`language_code` = :language';
$tokens[':language'] = $select['language'];
}
if (null !== $select['text']) {
$text_like = '%' . strtolower($select['text']) . '%';
if ($select['users']) {
$where[] = '(
LOWER(' . TB_CHAT . '.`title`) LIKE :text1
OR LOWER(' . TB_USER . '.`first_name`) LIKE :text2
OR LOWER(' . TB_USER . '.`last_name`) LIKE :text3
OR LOWER(' . TB_USER . '.`username`) LIKE :text4
)';
$tokens[':text1'] = $text_like;
$tokens[':text2'] = $text_like;
$tokens[':text3'] = $text_like;
$tokens[':text4'] = $text_like;
} else {
$where[] = 'LOWER(' . TB_CHAT . '.`title`) LIKE :text';
$tokens[':text'] = $text_like;
}
}
if (!empty($where)) {
$query .= ' WHERE ' . implode(' AND ', $where);
}
$query .= ' ORDER BY ' . TB_CHAT . '.`updated_at` ASC';
$sth = self::$pdo->prepare($query);
$sth->execute($tokens);
return $sth->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Get Telegram API request count for current chat / message
*
* @param int|string|null $chat_id
* @param string|null $inline_message_id
*
* @return array|bool Array containing TOTAL and CURRENT fields or false on invalid arguments
* @throws TelegramException
*/
public static function getTelegramRequestCount($chat_id = null, string $inline_message_id = null)
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('SELECT
(SELECT COUNT(DISTINCT `chat_id`) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_1) AS LIMIT_PER_SEC_ALL,
(SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_2 AND ((`chat_id` = :chat_id_1 AND `inline_message_id` IS NULL) OR (`inline_message_id` = :inline_message_id AND `chat_id` IS NULL))) AS LIMIT_PER_SEC,
(SELECT COUNT(*) FROM `' . TB_REQUEST_LIMITER . '` WHERE `created_at` >= :created_at_minute AND `chat_id` = :chat_id_2) AS LIMIT_PER_MINUTE
');
$date = self::getTimestamp();
$date_minute = self::getTimestamp(strtotime('-1 minute'));
$sth->bindValue(':chat_id_1', $chat_id);
$sth->bindValue(':chat_id_2', $chat_id);
$sth->bindValue(':inline_message_id', $inline_message_id);
$sth->bindValue(':created_at_1', $date);
$sth->bindValue(':created_at_2', $date);
$sth->bindValue(':created_at_minute', $date_minute);
$sth->execute();
return $sth->fetch();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Insert Telegram API request in db
*
* @param string $method
* @param array $data
*
* @return bool If the insert was successful
* @throws TelegramException
*/
public static function insertTelegramRequest(string $method, array $data): bool
{
if (!self::isDbConnected()) {
return false;
}
try {
$sth = self::$pdo->prepare('INSERT INTO `' . TB_REQUEST_LIMITER . '`
(`method`, `chat_id`, `inline_message_id`, `created_at`)
VALUES
(:method, :chat_id, :inline_message_id, :created_at);
');
$chat_id = $data['chat_id'] ?? null;
$inline_message_id = $data['inline_message_id'] ?? null;
$sth->bindValue(':chat_id', $chat_id);
$sth->bindValue(':inline_message_id', $inline_message_id);
$sth->bindValue(':method', $method);
$sth->bindValue(':created_at', self::getTimestamp());
return $sth->execute();
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
/**
* Bulk update the entries of any table
*
* @param string $table
* @param array $fields_values
* @param array $where_fields_values
*
* @return bool
* @throws TelegramException
*/
public static function update(string $table, array $fields_values, array $where_fields_values): bool
{
if (empty($fields_values) || !self::isDbConnected()) {
return false;
}
try {
// Building parts of query
$tokens = $fields = $where = [];
// Fields with values to update
foreach ($fields_values as $field => $value) {
$token = ':' . count($tokens);
$fields[] = "`{$field}` = {$token}";
$tokens[$token] = $value;
}
// Where conditions
foreach ($where_fields_values as $field => $value) {
$token = ':' . count($tokens);
$where[] = "`{$field}` = {$token}";
$tokens[$token] = $value;
}
$sql = 'UPDATE `' . $table . '` SET ' . implode(', ', $fields);
$sql .= count($where) > 0 ? ' WHERE ' . implode(' AND ', $where) : '';
return self::$pdo->prepare($sql)->execute($tokens);
} catch (PDOException $e) {
throw new TelegramException($e->getMessage());
}
}
}
diff --git a/src/Entities/Chat.php b/src/Entities/Chat.php
index 8a46c51..284e58b 100644
--- a/src/Entities/Chat.php
+++ b/src/Entities/Chat.php
@@ -1,143 +1,145 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Entities;
use Longman\TelegramBot\Entities\ReactionType\Factory as ReactionTypeFactory;
use Longman\TelegramBot\Entities\ReactionType\ReactionType;
/**
* This object represents a chat.
*
* @link https://core.telegram.org/bots/api#chat
*
* @property string type Type of chat, can be either "private ", "group", "supergroup" or "channel"
*
* @method int getId() Unique identifier for this chat. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
* @method string getType() Type of chat, can be either "private ", "group", "supergroup" or "channel"
* @method string getTitle() Optional. Title, for channels and group chats
* @method string getUsername() Optional. Username, for private chats, supergroups and channels if available
* @method string getFirstName() Optional. First name of the other party in a private chat
* @method string getLastName() Optional. Last name of the other party in a private chat
* @method bool getIsForum() Optional. True, if the supergroup chat is a forum (has topics enabled)
* @method int getAccentColorId() Identifier of the accent color for the chat name and backgrounds of the chat photo, reply header, and link preview. See accent colors for more details.
* @method ChatPhoto getPhoto() Optional. Chat photo. Returned only in getChat.
* @method string[] getActiveUsernames() Optional. If non-empty, the list of all active chat usernames; for private chats, supergroups and channels. Returned only in getChat.
* @method ReactionType[] getAvailableReactions() Optional. List of available reactions allowed in the chat. If omitted, then all emoji reactions are allowed. Returned only in getChat.
* @method string getBackgroundCustomEmojiId() Optional. Custom emoji identifier of the emoji chosen by the chat for the reply header and link preview background
* @method int getProfileAccentColorId() Optional. Identifier of the accent color for the chat's profile background. See profile accent colors for more details.
* @method string getProfileBackgroundCustomEmojiId() Optional. Custom emoji identifier of the emoji chosen by the chat for its profile background
* @method string getEmojiStatusCustomEmojiId() Optional. Custom emoji identifier of emoji status of the other party in a private chat. Returned only in getChat.
* @method int getEmojiStatusExpirationDate() Optional. Expiration date of the emoji status of the other party in a private chat in Unix time, if any. Returned only in getChat.
* @method string getBio() Optional. Bio of the other party in a private chat. Returned only in getChat.
* @method bool getHasPrivateForwards() Optional. True, if privacy settings of the other party in the private chat allows to use tg://user?id=<user_id> links only in chats with the user. Returned only in getChat.
* @method bool getHasRestrictedVoiceAndVideoMessages() Optional. True, if the privacy settings of the other party restrict sending voice and video note messages in the private chat. Returned only in getChat.
* @method bool getJoinToSendMessages() Optional. True, if users need to join the supergroup before they can send messages. Returned only in getChat.
* @method bool getJoinByRequest() Optional. True, if all users directly joining the supergroup need to be approved by supergroup administrators. Returned only in getChat.
* @method string getDescription() Optional. Description, for groups, supergroups and channel chats. Returned only in getChat.
* @method string getInviteLink() Optional. Chat invite link, for groups, supergroups and channel chats. Each administrator in a chat generates their own invite links, so the bot must first generate the link using exportChatInviteLink. Returned only in getChat.
* @method Message getPinnedMessage() Optional. Pinned message, for groups, supergroups and channels. Returned only in getChat.
* @method ChatPermissions getPermissions() Optional. Default chat member permissions, for groups and supergroups. Returned only in getChat.
* @method int getSlowModeDelay() Optional. For supergroups, the minimum allowed delay between consecutive messages sent by each unpriviledged user. Returned only in getChat.
+ * @method int getUnrestrictBoostCount() Optional. For supergroups, the minimum number of boosts that a non-administrator user needs to add in order to ignore slow mode and chat permissions.
* @method int getMessageAutoDeleteTime() Optional. The time after which all messages sent to the chat will be automatically deleted; in seconds. Returned only in getChat.
* @method bool getHasAggressiveAntiSpamEnabled() Optional. True, if aggressive anti-spam checks are enabled in the supergroup. The field is only available to chat administrators. Returned only in getChat.
* @method bool getHasHiddenMembers() Optional. True, if non-administrators can only get the list of bots and administrators in the chat. Returned only in getChat.
* @method bool getHasProtectedContent() Optional. True, if messages from the chat can't be forwarded to other chats. Returned only in getChat.
* @method bool getHasVisibleHistory() Optional. True, if new chat members will have access to old messages; available only to chat administrators
* @method string getStickerSetName() Optional. For supergroups, name of group sticker set. Returned only in getChat.
* @method bool getCanSetStickerSet() Optional. True, if the bot can change the group sticker set. Returned only in getChat.
+ * @method string getCustomEmojiStickerSetName() Optional. For supergroups, the name of the group's custom emoji sticker set. Custom emoji from this set can be used by all users and bots in the group.
* @method int getLinkedChatId() Optional. Unique identifier for the linked chat. Returned only in getChat.
* @method ChatLocation getLocation() Optional. For supergroups, the location to which the supergroup is connected. Returned only in getChat.
*/
class Chat extends Entity
{
/**
* {@inheritdoc}
*/
protected function subEntities(): array
{
return [
'photo' => ChatPhoto::class,
'available_reactions' => [ReactionTypeFactory::class],
'pinned_message' => Message::class,
'permissions' => ChatPermissions::class,
'location' => ChatLocation::class,
];
}
public function __construct(array $data)
{
parent::__construct($data);
$id = $this->getId();
$type = $this->getType();
if (!$type) {
$id > 0 && $this->type = 'private';
$id < 0 && $this->type = 'group';
}
}
/**
* Try to mention the user of this chat, else return the title
*
* @param bool $escape_markdown
*
* @return string
*/
public function tryMention($escape_markdown = false): string
{
if ($this->isPrivateChat()) {
return parent::tryMention($escape_markdown);
}
return $this->getTitle();
}
/**
* Check if this is a group chat
*
* @return bool
*/
public function isGroupChat(): bool
{
return $this->getType() === 'group';
}
/**
* Check if this is a private chat
*
* @return bool
*/
public function isPrivateChat(): bool
{
return $this->getType() === 'private';
}
/**
* Check if this is a super group
*
* @return bool
*/
public function isSuperGroup(): bool
{
return $this->getType() === 'supergroup';
}
/**
* Check if this is a channel
*
* @return bool
*/
public function isChannel(): bool
{
return $this->getType() === 'channel';
}
}
diff --git a/src/Entities/Story.php b/src/Entities/ChatBoostAdded.php
similarity index 57%
copy from src/Entities/Story.php
copy to src/Entities/ChatBoostAdded.php
index 5647db2..baa5d8b 100644
--- a/src/Entities/Story.php
+++ b/src/Entities/ChatBoostAdded.php
@@ -1,22 +1,24 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Entities;
/**
- * Class Story
+ * This object represents a service message about a user boosting a chat.
*
- * @link https://core.telegram.org/bots/api#story
+ * @link https://core.telegram.org/bots/api#chatboostadded
+ *
+ * @method int getBoostCount() Number of boosts added by the user
*/
-class Story extends Entity
+class ChatBoostAdded extends Entity
{
}
diff --git a/src/Entities/Message.php b/src/Entities/Message.php
index 8f771a3..0523122 100644
--- a/src/Entities/Message.php
+++ b/src/Entities/Message.php
@@ -1,337 +1,344 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Entities;
use Longman\TelegramBot\Entities\Games\Game;
use Longman\TelegramBot\Entities\Giveaway\Giveaway;
use Longman\TelegramBot\Entities\Giveaway\GiveawayCompleted;
use Longman\TelegramBot\Entities\Giveaway\GiveawayCreated;
use Longman\TelegramBot\Entities\Giveaway\GiveawayWinners;
use Longman\TelegramBot\Entities\Message\Factory as MaybeInaccessibleMessageFactory;
use Longman\TelegramBot\Entities\Message\MaybeInaccessibleMessage;
use Longman\TelegramBot\Entities\MessageOrigin\Factory as MessageOriginFactory;
use Longman\TelegramBot\Entities\MessageOrigin\MessageOrigin;
use Longman\TelegramBot\Entities\Payments\Invoice;
use Longman\TelegramBot\Entities\Payments\SuccessfulPayment;
use Longman\TelegramBot\Entities\TelegramPassport\PassportData;
use Longman\TelegramBot\Entities\Topics\ForumTopicClosed;
use Longman\TelegramBot\Entities\Topics\ForumTopicCreated;
use Longman\TelegramBot\Entities\Topics\ForumTopicEdited;
use Longman\TelegramBot\Entities\Topics\ForumTopicReopened;
use Longman\TelegramBot\Entities\Topics\GeneralForumTopicHidden;
use Longman\TelegramBot\Entities\Topics\GeneralForumTopicUnhidden;
/**
* Class Message
*
* Represents a message
*
* @link https://core.telegram.org/bots/api#message
*
* @method int getMessageId() Unique message identifier
- * @method int getMessageThreadId() Optional. Unique identifier of a message thread to which the message belongs; for supergroups only
+ * @method int getMessageThreadId() Optional. Unique identifier of a message thread to which the message belongs;
+for supergroups only
* @method User getFrom() Optional. Sender, can be empty for messages sent to channels
* @method Chat getSenderChat() Optional. Sender of the message, sent on behalf of a chat. The channel itself for channel messages. The supergroup itself for messages from anonymous group administrators. The linked channel for messages automatically forwarded to the discussion group
+ * @method int getSenderBoostCount() Optional. If the sender of the message boosted the chat, the number of boosts added by the user
* @method int getDate() Date the message was sent in Unix time
* @method Chat getChat() Conversation the message belongs to
* @method MessageOrigin getForwardOrigin() Optional. Information about the original message for forwarded messages
* @method bool getIsTopicMessage() Optional. True, if the message is sent to a forum topic
* @method bool getIsAutomaticForward() Optional. True, if the message is a channel post that was automatically forwarded to the connected discussion group
* @method ReplyToMessage getReplyToMessage() Optional. For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply.
* @method ExternalReplyInfo getExternalReply() Optional. Information about the message that is being replied to, which may come from another chat or forum topic
* @method TextQuote getQuote() Optional. For replies that quote part of the original message, the quoted part of the message
+ * @method Story getReplyToStory() Optional. For replies to a story, the original story
* @method User getViaBot() Optional. Bot through which the message was sent
* @method int getEditDate() Optional. Date the message was last edited in Unix time
* @method bool getHasProtectedContent() Optional. True, if the message can't be forwarded
* @method string getMediaGroupId() Optional. The unique identifier of a media message group this message belongs to
* @method string getAuthorSignature() Optional. Signature of the post author for messages in channels
* @method LinkPreviewOptions getLinkPreviewOptions() Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed
* @method MessageEntity[] getEntities() Optional. For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text
* @method MessageEntity[] getCaptionEntities() Optional. For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption
* @method Audio getAudio() Optional. Message is an audio file, information about the file
* @method Document getDocument() Optional. Message is a general file, information about the file
* @method Animation getAnimation() Optional. Message is an animation, information about the animation. For backward compatibility, when this field is set, the document field will also be set
* @method Game getGame() Optional. Message is a game, information about the game.
* @method PhotoSize[] getPhoto() Optional. Message is a photo, available sizes of the photo
* @method Sticker getSticker() Optional. Message is a sticker, information about the sticker
* @method Story getStory() Optional. Message is a forwarded story
* @method Video getVideo() Optional. Message is a video, information about the video
* @method Voice getVoice() Optional. Message is a voice message, information about the file
* @method VideoNote getVideoNote() Optional. Message is a video note message, information about the video
* @method string getCaption() Optional. Caption for the document, photo or video, 0-200 characters
* @method bool getHasMediaSpoiler() Optional. True, if the message media is covered by a spoiler animation
* @method Contact getContact() Optional. Message is a shared contact, information about the contact
* @method Location getLocation() Optional. Message is a shared location, information about the location
* @method Venue getVenue() Optional. Message is a venue, information about the venue
* @method Poll getPoll() Optional. Message is a native poll, information about the poll
* @method Dice getDice() Optional. Message is a dice with random value, 1-6 for “🎲” and “🎯” base emoji, 1-5 for “🏀” and “⚽” base emoji, 1-64 for “🎰” base emoji
* @method User[] getNewChatMembers() Optional. A new member(s) was added to the group, information about them (one of this members may be the bot itself)
* @method User getLeftChatMember() Optional. A member was removed from the group, information about them (this member may be the bot itself)
* @method string getNewChatTitle() Optional. A chat title was changed to this value
* @method PhotoSize[] getNewChatPhoto() Optional. A chat photo was changed to this value
* @method MessageAutoDeleteTimerChanged getMessageAutoDeleteTimerChanged() Optional. Service message: auto-delete timer settings changed in the chat
* @method bool getDeleteChatPhoto() Optional. Service message: the chat photo was deleted
* @method bool getGroupChatCreated() Optional. Service message: the group has been created
* @method bool getSupergroupChatCreated() Optional. Service message: the supergroup has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a supergroup when it is created. It can only be found in reply_to_message if someone replies to a very first message in a directly created supergroup.
* @method bool getChannelChatCreated() Optional. Service message: the channel has been created. This field can't be received in a message coming through updates, because bot can’t be a member of a channel when it is created. It can only be found in reply_to_message if someone replies to a very first message in a channel.
* @method int getMigrateToChatId() Optional. The group has been migrated to a supergroup with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
* @method int getMigrateFromChatId() Optional. The supergroup has been migrated from a group with the specified identifier. This number may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier.
* @method MaybeInaccessibleMessage getPinnedMessage() Optional. Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply.
* @method Invoice getInvoice() Optional. Message is an invoice for a payment, information about the invoice.
* @method SuccessfulPayment getSuccessfulPayment() Optional. Message is a service message about a successful payment, information about the payment.
* @method UsersShared getUsersShared() Optional. Service message: users were shared with the bot
* @method ChatShared getChatShared() Optional. Service message: a chat was shared with the bot
* @method string getConnectedWebsite() Optional. The domain name of the website on which the user has logged in.
* @method WriteAccessAllowed getWriteAccessAllowed() Optional. Service message: the user allowed the bot added to the attachment menu to write messages
* @method PassportData getPassportData() Optional. Telegram Passport data
* @method ProximityAlertTriggered getProximityAlertTriggered() Optional. Service message. A user in the chat triggered another user's proximity alert while sharing Live Location.
+ * @method ChatBoostAdded getBoostAdded() Optional. Service message: user boosted the chat
* @method ForumTopicCreated getForumTopicCreated() Optional. Service message: forum topic created
* @method ForumTopicEdited getForumTopicEdited() Optional. Service message: forum topic edited
* @method ForumTopicClosed getForumTopicClosed() Optional. Service message: forum topic closed
* @method ForumTopicReopened getForumTopicReopened() Optional. Service message: forum topic reopened
* @method GeneralForumTopicHidden getGeneralForumTopicHidden() Optional. Service message: the 'General' forum topic hidden
* @method GeneralForumTopicUnhidden getGeneralForumTopicUnhidden() Optional. Service message: the 'General' forum topic unhidden
* @method GiveawayCreated getGiveawayCreated() Optional. Service message: a scheduled giveaway was created
* @method Giveaway getGiveaway() Optional. The message is a scheduled giveaway message
* @method GiveawayWinners getGiveawayWinners() Optional. A giveaway with public winners was completed
* @method GiveawayCompleted getGiveawayCompleted() Optional. Service message: a giveaway without public winners was completed
* @method VideoChatScheduled getVideoChatScheduled() Optional. Service message: voice chat scheduled
* @method VideoChatStarted getVideoChatStarted() Optional. Service message: voice chat started
* @method VideoChatEnded getVideoChatEnded() Optional. Service message: voice chat ended
* @method VideoChatParticipantsInvited getVideoChatParticipantsInvited() Optional. Service message: new participants invited to a voice chat
* @method WebAppData getWebAppData() Optional. Service message: data sent by a Web App
* @method InlineKeyboard getReplyMarkup() Optional. Inline keyboard attached to the message. login_url buttons are represented as ordinary url buttons.
*/
class Message extends Entity implements MaybeInaccessibleMessage
{
/**
* {@inheritdoc}
*/
protected function subEntities(): array
{
return [
'from' => User::class,
'sender_chat' => Chat::class,
'chat' => Chat::class,
'forward_origin' => MessageOriginFactory::class,
'reply_to_message' => ReplyToMessage::class,
'external_reply' => ExternalReplyInfo::class,
'quote' => TextQuote::class,
+ 'reply_to_story' => Story::class,
'via_bot' => User::class,
'link_preview_options' => LinkPreviewOptions::class,
'entities' => [MessageEntity::class],
'animation' => Animation::class,
'audio' => Audio::class,
'document' => Document::class,
'photo' => [PhotoSize::class],
'sticker' => Sticker::class,
'story' => Story::class,
'video' => Video::class,
'video_note' => VideoNote::class,
'voice' => Voice::class,
'caption_entities' => [MessageEntity::class],
'contact' => Contact::class,
'dice' => Dice::class,
'game' => Game::class,
'poll' => Poll::class,
'venue' => Venue::class,
'location' => Location::class,
'new_chat_members' => [User::class],
'left_chat_member' => User::class,
'new_chat_photo' => [PhotoSize::class],
'message_auto_delete_timer_changed' => MessageAutoDeleteTimerChanged::class,
'pinned_message' => MaybeInaccessibleMessageFactory::class,
'invoice' => Invoice::class,
'successful_payment' => SuccessfulPayment::class,
'users_shared' => UsersShared::class,
'chat_shared' => ChatShared::class,
'write_access_allowed' => WriteAccessAllowed::class,
'passport_data' => PassportData::class,
'proximity_alert_triggered' => ProximityAlertTriggered::class,
+ 'boost_added' => ChatBoostAdded::class,
'forum_topic_created' => ForumTopicCreated::class,
'forum_topic_edited' => ForumTopicEdited::class,
'forum_topic_closed' => ForumTopicClosed::class,
'forum_topic_reopened' => ForumTopicReopened::class,
'general_forum_topic_hidden' => GeneralForumTopicHidden::class,
'general_forum_topic_unhidden' => GeneralForumTopicUnhidden::class,
'giveaway_created' => GiveawayCreated::class,
'giveaway' => Giveaway::class,
'giveaway_winners' => GiveawayWinners::class,
'giveaway_completed' => GiveawayCompleted::class,
'video_chat_scheduled' => VideoChatScheduled::class,
'video_chat_started' => VideoChatStarted::class,
'video_chat_ended' => VideoChatEnded::class,
'video_chat_participants_invited' => VideoChatParticipantsInvited::class,
'web_app_data' => WebAppData::class,
'reply_markup' => InlineKeyboard::class,
];
}
/**
* return the entire command like /echo or /echo@bot1 if specified
*
* @return string|null
*/
public function getFullCommand(): ?string
{
$text = $this->getProperty('text') ?? '';
if (strpos($text, '/') !== 0) {
return null;
}
- $no_EOL = strtok($text, PHP_EOL);
+ $no_EOL = strtok($text, PHP_EOL);
$no_space = strtok($text, ' ');
//try to understand which separator \n or space divide /command from text
return strlen($no_space) < strlen($no_EOL) ? $no_space : $no_EOL;
}
/**
* Get command
*
* @return string|null
*/
public function getCommand(): ?string
{
if ($command = $this->getProperty('command')) {
return $command;
}
$full_command = $this->getFullCommand() ?? '';
if (strpos($full_command, '/') !== 0) {
return null;
}
$full_command = substr($full_command, 1);
//check if command is followed by bot username
$split_cmd = explode('@', $full_command);
- if (! isset($split_cmd[1])) {
+ if (!isset($split_cmd[1])) {
//command is not followed by name
return $full_command;
}
if (strtolower($split_cmd[1]) === strtolower($this->getBotUsername())) {
//command is addressed to me
return $split_cmd[0];
}
return null;
}
/**
* For text messages, the actual UTF-8 text of the message, 0-4096 characters.
*
- * @param bool $without_cmd
+ * @param bool $without_cmd
*
* @return string|null
*/
public function getText($without_cmd = false): ?string
{
$text = $this->getProperty('text');
if ($without_cmd && $command = $this->getFullCommand()) {
if (strlen($command) + 1 < strlen($text)) {
return substr($text, strlen($command) + 1);
}
return '';
}
return $text;
}
/**
* Bot added in chat
*
* @return bool
*/
public function botAddedInChat(): bool
{
foreach ($this->getNewChatMembers() as $member) {
if ($member instanceof User && $member->getUsername() === $this->getBotUsername()) {
return true;
}
}
return false;
}
/**
* Detect type based on properties.
*
* @return string
*/
public function getType(): string
{
$types = [
'text',
'animation',
'audio',
'document',
'photo',
'sticker',
'video',
'video_note',
'voice',
'contact',
'dice',
'game',
'poll',
'venue',
'location',
'new_chat_members',
'left_chat_member',
'new_chat_title',
'new_chat_photo',
'delete_chat_photo',
'group_chat_created',
'supergroup_chat_created',
'channel_chat_created',
'message_auto_delete_timer_changed',
'migrate_to_chat_id',
'migrate_from_chat_id',
'pinned_message',
'invoice',
'successful_payment',
'users_shared',
'chat_shared',
'write_access_allowed',
'passport_data',
'proximity_alert_triggered',
+ 'boost_added',
'forum_topic_created',
'forum_topic_edited',
'forum_topic_closed',
'forum_topic_reopened',
'general_forum_topic_hidden',
'general_forum_topic_unhidden',
'video_chat_scheduled',
'video_chat_started',
'video_chat_ended',
'video_chat_participants_invited',
'web_app_data',
'reply_markup',
];
$is_command = $this->getCommand() !== null;
foreach ($types as $type) {
if ($this->getProperty($type) !== null) {
if ($is_command && $type === 'text') {
return 'command';
}
return $type;
}
}
return 'message';
}
}
diff --git a/src/Entities/Story.php b/src/Entities/Story.php
index 5647db2..64fc066 100644
--- a/src/Entities/Story.php
+++ b/src/Entities/Story.php
@@ -1,22 +1,33 @@
<?php
/**
* This file is part of the TelegramBot package.
*
* (c) Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Longman\TelegramBot\Entities;
/**
* Class Story
*
* @link https://core.telegram.org/bots/api#story
+ *
+ * @method Chat getChat() Chat that posted the story
+ * @method int getId() Unique identifier for the story in the chat
*/
class Story extends Entity
{
-
+ /**
+ * {@inheritdoc}
+ */
+ protected function subEntities(): array
+ {
+ return [
+ 'chat' => Chat::class,
+ ];
+ }
}
diff --git a/structure.sql b/structure.sql
index cf80615..357501e 100644
--- a/structure.sql
+++ b/structure.sql
@@ -1,438 +1,442 @@
CREATE TABLE IF NOT EXISTS `user` (
`id` bigint COMMENT 'Unique identifier for this user or bot',
`is_bot` tinyint(1) DEFAULT 0 COMMENT 'True, if this user is a bot',
`first_name` CHAR(255) NOT NULL DEFAULT '' COMMENT 'User''s or bot''s first name',
`last_name` CHAR(255) DEFAULT NULL COMMENT 'User''s or bot''s last name',
`username` CHAR(191) DEFAULT NULL COMMENT 'User''s or bot''s username',
`language_code` CHAR(10) DEFAULT NULL COMMENT 'IETF language tag of the user''s language',
`is_premium` tinyint(1) DEFAULT 0 COMMENT 'True, if this user is a Telegram Premium user',
`added_to_attachment_menu` tinyint(1) DEFAULT 0 COMMENT 'True, if this user added the bot to the attachment menu',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date update',
PRIMARY KEY (`id`),
KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat` (
`id` bigint COMMENT 'Unique identifier for this chat',
`type` ENUM('private', 'group', 'supergroup', 'channel') NOT NULL COMMENT 'Type of chat, can be either private, group, supergroup or channel',
`title` CHAR(255) DEFAULT '' COMMENT 'Title, for supergroups, channels and group chats',
`username` CHAR(255) DEFAULT NULL COMMENT 'Username, for private chats, supergroups and channels if available',
`first_name` CHAR(255) DEFAULT NULL COMMENT 'First name of the other party in a private chat',
`last_name` CHAR(255) DEFAULT NULL COMMENT 'Last name of the other party in a private chat',
`is_forum` TINYINT(1) DEFAULT 0 COMMENT 'True, if the supergroup chat is a forum (has topics enabled)',
`all_members_are_administrators` tinyint(1) DEFAULT 0 COMMENT 'True if a all members of this group are admins',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date update',
`old_id` bigint DEFAULT NULL COMMENT 'Unique chat identifier, this is filled when a group is converted to a supergroup',
PRIMARY KEY (`id`),
KEY `old_id` (`old_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `user_chat` (
`user_id` bigint COMMENT 'Unique user identifier',
`chat_id` bigint COMMENT 'Unique user or chat identifier',
PRIMARY KEY (`user_id`, `chat_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `message_reaction` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'The chat containing the message the user reacted to',
`message_id` bigint COMMENT 'Unique identifier of the message inside the chat',
`user_id` bigint NULL COMMENT 'Optional. The user that changed the reaction, if the user isn''t anonymous',
`actor_chat_id` bigint NULL COMMENT 'Optional. The chat on behalf of which the reaction was changed, if the user is anonymous',
`old_reaction` TEXT NOT NULL COMMENT 'Previous list of reaction types that were set by the user',
`new_reaction` TEXT NOT NULL COMMENT 'New list of reaction types that have been set by the user',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
KEY `user_id` (`user_id`),
KEY `actor_chat_id` (`actor_chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
FOREIGN KEY (`actor_chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `message_reaction_count` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'The chat containing the message',
`message_id` bigint COMMENT 'Unique message identifier inside the chat',
`reactions` TEXT NOT NULL COMMENT 'List of reactions that are present on the message',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `inline_query` (
`id` bigint UNSIGNED COMMENT 'Unique identifier for this query',
`user_id` bigint NULL COMMENT 'Unique user identifier',
`location` CHAR(255) NULL DEFAULT NULL COMMENT 'Location of the user',
`query` TEXT NOT NULL COMMENT 'Text of the query',
`offset` CHAR(255) NULL DEFAULT NULL COMMENT 'Offset of the result',
`chat_type` CHAR(255) NULL DEFAULT NULL COMMENT 'Optional. Type of the chat, from which the inline query was sent.',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chosen_inline_result` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`result_id` CHAR(255) NOT NULL DEFAULT '' COMMENT 'The unique identifier for the result that was chosen',
`user_id` bigint NULL COMMENT 'The user that chose the result',
`location` CHAR(255) NULL DEFAULT NULL COMMENT 'Sender location, only for bots that require user location',
`inline_message_id` CHAR(255) NULL DEFAULT NULL COMMENT 'Identifier of the sent inline message',
`query` TEXT NOT NULL COMMENT 'The query that was used to obtain the result',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `message` (
`chat_id` bigint COMMENT 'Unique chat identifier',
`sender_chat_id` bigint COMMENT 'Sender of the message, sent on behalf of a chat',
`id` bigint UNSIGNED COMMENT 'Unique message identifier',
`message_thread_id` bigint(20) DEFAULT NULL COMMENT 'Unique identifier of a message thread to which the message belongs; for supergroups only',
`user_id` bigint NULL COMMENT 'Unique user identifier',
+ `sender_boost_count` bigint NULL COMMENT 'If the sender of the message boosted the chat, the number of boosts added by the user',
`date` timestamp NULL DEFAULT NULL COMMENT 'Date the message was sent in timestamp format',
`forward_from` bigint NULL DEFAULT NULL COMMENT 'Unique user identifier, sender of the original message',
`forward_from_chat` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier, chat the original message belongs to',
`forward_from_message_id` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier of the original message in the channel',
`forward_signature` TEXT NULL DEFAULT NULL COMMENT 'For messages forwarded from channels, signature of the post author if present',
`forward_sender_name` TEXT NULL DEFAULT NULL COMMENT 'Sender''s name for messages forwarded from users who disallow adding a link to their account in forwarded messages',
`forward_date` timestamp NULL DEFAULT NULL COMMENT 'date the original message was sent in timestamp format',
`is_topic_message` tinyint(1) DEFAULT 0 COMMENT 'True, if the message is sent to a forum topic',
`is_automatic_forward` tinyint(1) DEFAULT 0 COMMENT 'True, if the message is a channel post that was automatically forwarded to the connected discussion group',
`reply_to_chat` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier',
`reply_to_message` bigint UNSIGNED DEFAULT NULL COMMENT 'Message that this message is reply to',
`external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic',
+ `quote` TEXT NULL DEFAULT NULL COMMENT 'Optional. For replies that quote part of the original message, the quoted part of the message',
+ `reply_to_story` TEXT NULL DEFAULT NULL COMMENT 'Optional. For replies to a story, the original story',
`via_bot` bigint NULL DEFAULT NULL COMMENT 'Optional. Bot through which the message was sent',
`link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed',
`edit_date` timestamp NULL DEFAULT NULL COMMENT 'Date the message was last edited in Unix time',
`has_protected_content` tinyint(1) DEFAULT 0 COMMENT 'True, if the message can''t be forwarded',
`media_group_id` TEXT COMMENT 'The unique identifier of a media message group this message belongs to',
`author_signature` TEXT COMMENT 'Signature of the post author for messages in channels',
`text` TEXT COMMENT 'For text messages, the actual UTF-8 text of the message max message length 4096 char utf8mb4',
`entities` TEXT COMMENT 'For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text',
`caption_entities` TEXT COMMENT 'For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption',
`audio` TEXT COMMENT 'Audio object. Message is an audio file, information about the file',
`document` TEXT COMMENT 'Document object. Message is a general file, information about the file',
`animation` TEXT COMMENT 'Message is an animation, information about the animation',
`game` TEXT COMMENT 'Game object. Message is a game, information about the game',
`photo` TEXT COMMENT 'Array of PhotoSize objects. Message is a photo, available sizes of the photo',
`sticker` TEXT COMMENT 'Sticker object. Message is a sticker, information about the sticker',
`story` TEXT COMMENT 'Story object. Message is a forwarded story',
`video` TEXT COMMENT 'Video object. Message is a video, information about the video',
`voice` TEXT COMMENT 'Voice Object. Message is a Voice, information about the Voice',
`video_note` TEXT COMMENT 'VoiceNote Object. Message is a Video Note, information about the Video Note',
`caption` TEXT COMMENT 'For message with caption, the actual UTF-8 text of the caption',
`has_media_spoiler` tinyint(1) DEFAULT 0 COMMENT 'True, if the message media is covered by a spoiler animation',
`contact` TEXT COMMENT 'Contact object. Message is a shared contact, information about the contact',
`location` TEXT COMMENT 'Location object. Message is a shared location, information about the location',
`venue` TEXT COMMENT 'Venue object. Message is a Venue, information about the Venue',
`poll` TEXT COMMENT 'Poll object. Message is a native poll, information about the poll',
`dice` TEXT COMMENT 'Message is a dice with random value from 1 to 6',
`new_chat_members` TEXT COMMENT 'List of unique user identifiers, new member(s) were added to the group, information about them (one of these members may be the bot itself)',
`left_chat_member` bigint NULL DEFAULT NULL COMMENT 'Unique user identifier, a member was removed from the group, information about them (this member may be the bot itself)',
`new_chat_title` CHAR(255) DEFAULT NULL COMMENT 'A chat title was changed to this value',
`new_chat_photo` TEXT COMMENT 'Array of PhotoSize objects. A chat photo was change to this value',
`delete_chat_photo` tinyint(1) DEFAULT 0 COMMENT 'Informs that the chat photo was deleted',
`group_chat_created` tinyint(1) DEFAULT 0 COMMENT 'Informs that the group has been created',
`supergroup_chat_created` tinyint(1) DEFAULT 0 COMMENT 'Informs that the supergroup has been created',
`channel_chat_created` tinyint(1) DEFAULT 0 COMMENT 'Informs that the channel chat has been created',
`message_auto_delete_timer_changed` TEXT COMMENT 'MessageAutoDeleteTimerChanged object. Message is a service message: auto-delete timer settings changed in the chat',
`migrate_to_chat_id` bigint NULL DEFAULT NULL COMMENT 'Migrate to chat identifier. The group has been migrated to a supergroup with the specified identifier',
`migrate_from_chat_id` bigint NULL DEFAULT NULL COMMENT 'Migrate from chat identifier. The supergroup has been migrated from a group with the specified identifier',
`pinned_message` TEXT NULL COMMENT 'Message object. Specified message was pinned',
`invoice` TEXT NULL COMMENT 'Message is an invoice for a payment, information about the invoice',
`successful_payment` TEXT NULL COMMENT 'Message is a service message about a successful payment, information about the payment',
`users_shared` TEXT NULL COMMENT 'Optional. Service message: users were shared with the bot',
`chat_shared` TEXT NULL COMMENT 'Optional. Service message: a chat was shared with the bot',
`connected_website` TEXT NULL COMMENT 'The domain name of the website on which the user has logged in.',
`write_access_allowed` TEXT DEFAULT NULL COMMENT 'Service message: the user allowed the bot added to the attachment menu to write messages',
`passport_data` TEXT NULL COMMENT 'Telegram Passport data',
`proximity_alert_triggered` TEXT NULL COMMENT 'Service message. A user in the chat triggered another user''s proximity alert while sharing Live Location.',
+ `boost_added` TEXT NULL COMMENT 'Service message: user boosted the chat',
`forum_topic_created` TEXT DEFAULT NULL COMMENT 'Service message: forum topic created',
`forum_topic_edited` TEXT DEFAULT NULL COMMENT 'Service message: forum topic edited',
`forum_topic_closed` TEXT DEFAULT NULL COMMENT 'Service message: forum topic closed',
`forum_topic_reopened` TEXT DEFAULT NULL COMMENT 'Service message: forum topic reopened',
`general_forum_topic_hidden` TEXT DEFAULT NULL COMMENT 'Service message: the General forum topic hidden',
`general_forum_topic_unhidden` TEXT DEFAULT NULL COMMENT 'Service message: the General forum topic unhidden',
`video_chat_scheduled` TEXT COMMENT 'Service message: video chat scheduled',
`video_chat_started` TEXT COMMENT 'Service message: video chat started',
`video_chat_ended` TEXT COMMENT 'Service message: video chat ended',
`video_chat_participants_invited` TEXT COMMENT 'Service message: new participants invited to a video chat',
`web_app_data` TEXT COMMENT 'Service message: data sent by a Web App',
`reply_markup` TEXT NULL COMMENT 'Inline keyboard attached to the message',
PRIMARY KEY (`chat_id`, `id`),
KEY `user_id` (`user_id`),
KEY `forward_from` (`forward_from`),
KEY `forward_from_chat` (`forward_from_chat`),
KEY `reply_to_chat` (`reply_to_chat`),
KEY `reply_to_message` (`reply_to_message`),
KEY `via_bot` (`via_bot`),
KEY `left_chat_member` (`left_chat_member`),
KEY `migrate_from_chat_id` (`migrate_from_chat_id`),
KEY `migrate_to_chat_id` (`migrate_to_chat_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`forward_from`) REFERENCES `user` (`id`),
FOREIGN KEY (`forward_from_chat`) REFERENCES `chat` (`id`),
FOREIGN KEY (`reply_to_chat`, `reply_to_message`) REFERENCES `message` (`chat_id`, `id`),
FOREIGN KEY (`via_bot`) REFERENCES `user` (`id`),
FOREIGN KEY (`left_chat_member`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `edited_message` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'Unique chat identifier',
`message_id` bigint UNSIGNED COMMENT 'Unique message identifier',
`user_id` bigint NULL COMMENT 'Unique user identifier',
`edit_date` timestamp NULL DEFAULT NULL COMMENT 'Date the message was edited in timestamp format',
`text` TEXT COMMENT 'For text messages, the actual UTF-8 text of the message max message length 4096 char utf8',
`entities` TEXT COMMENT 'For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text',
`caption` TEXT COMMENT 'For message with caption, the actual UTF-8 text of the caption',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
KEY `message_id` (`message_id`),
KEY `user_id` (`user_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`chat_id`, `message_id`) REFERENCES `message` (`chat_id`, `id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `callback_query` (
`id` bigint UNSIGNED COMMENT 'Unique identifier for this query',
`user_id` bigint NULL COMMENT 'Unique user identifier',
`chat_id` bigint NULL COMMENT 'Unique chat identifier',
`message_id` bigint UNSIGNED COMMENT 'Unique message identifier',
`inline_message_id` CHAR(255) NULL DEFAULT NULL COMMENT 'Identifier of the message sent via the bot in inline mode, that originated the query',
`chat_instance` CHAR(255) NOT NULL DEFAULT '' COMMENT 'Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent',
`data` CHAR(255) NOT NULL DEFAULT '' COMMENT 'Data associated with the callback button',
`game_short_name` CHAR(255) NOT NULL DEFAULT '' COMMENT 'Short name of a Game to be returned, serves as the unique identifier for the game',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `chat_id` (`chat_id`),
KEY `message_id` (`message_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
FOREIGN KEY (`chat_id`, `message_id`) REFERENCES `message` (`chat_id`, `id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `shipping_query` (
`id` bigint UNSIGNED COMMENT 'Unique query identifier',
`user_id` bigint COMMENT 'User who sent the query',
`invoice_payload` CHAR(255) NOT NULL DEFAULT '' COMMENT 'Bot specified invoice payload',
`shipping_address` CHAR(255) NOT NULL DEFAULT '' COMMENT 'User specified shipping address',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `pre_checkout_query` (
`id` bigint UNSIGNED COMMENT 'Unique query identifier',
`user_id` bigint COMMENT 'User who sent the query',
`currency` CHAR(3) COMMENT 'Three-letter ISO 4217 currency code',
`total_amount` bigint COMMENT 'Total price in the smallest units of the currency',
`invoice_payload` CHAR(255) NOT NULL DEFAULT '' COMMENT 'Bot specified invoice payload',
`shipping_option_id` CHAR(255) NULL COMMENT 'Identifier of the shipping option chosen by the user',
`order_info` TEXT NULL COMMENT 'Order info provided by the user',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `poll` (
`id` bigint UNSIGNED COMMENT 'Unique poll identifier',
`question` text NOT NULL COMMENT 'Poll question',
`options` text NOT NULL COMMENT 'List of poll options',
`total_voter_count` int UNSIGNED COMMENT 'Total number of users that voted in the poll',
`is_closed` tinyint(1) DEFAULT 0 COMMENT 'True, if the poll is closed',
`is_anonymous` tinyint(1) DEFAULT 1 COMMENT 'True, if the poll is anonymous',
`type` char(255) COMMENT 'Poll type, currently can be “regular” or “quiz”',
`allows_multiple_answers` tinyint(1) DEFAULT 0 COMMENT 'True, if the poll allows multiple answers',
`correct_option_id` int UNSIGNED COMMENT '0-based identifier of the correct answer option. Available only for polls in the quiz mode, which are closed, or was sent (not forwarded) by the bot or to the private chat with the bot.',
`explanation` varchar(255) DEFAULT NULL COMMENT 'Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters',
`explanation_entities` text DEFAULT NULL COMMENT 'Special entities like usernames, URLs, bot commands, etc. that appear in the explanation',
`open_period` int UNSIGNED DEFAULT NULL COMMENT 'Amount of time in seconds the poll will be active after creation',
`close_date` timestamp NULL DEFAULT NULL COMMENT 'Point in time (Unix timestamp) when the poll will be automatically closed',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `poll_answer` (
`poll_id` bigint UNSIGNED COMMENT 'Unique poll identifier',
`user_id` bigint NOT NULL COMMENT 'The user, who changed the answer to the poll',
`option_ids` text NOT NULL COMMENT '0-based identifiers of answer options, chosen by the user. May be empty if the user retracted their vote.',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`poll_id`, `user_id`),
FOREIGN KEY (`poll_id`) REFERENCES `poll` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_member_updated` (
`id` BIGINT UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` BIGINT NOT NULL COMMENT 'Chat the user belongs to',
`user_id` BIGINT NOT NULL COMMENT 'Performer of the action, which resulted in the change',
`date` TIMESTAMP NOT NULL COMMENT 'Date the change was done in Unix time',
`old_chat_member` TEXT NOT NULL COMMENT 'Previous information about the chat member',
`new_chat_member` TEXT NOT NULL COMMENT 'New information about the chat member',
`invite_link` TEXT NULL COMMENT 'Chat invite link, which was used by the user to join the chat; for joining by invite link events only',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_join_request` (
`id` BIGINT UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` BIGINT NOT NULL COMMENT 'Chat to which the request was sent',
`user_id` BIGINT NOT NULL COMMENT 'User that sent the join request',
`date` TIMESTAMP NOT NULL COMMENT 'Date the request was sent in Unix time',
`bio` TEXT NULL COMMENT 'Optional. Bio of the user',
`invite_link` TEXT NULL COMMENT 'Optional. Chat invite link that was used by the user to send the join request',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_boost_updated` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'Chat which was boosted',
`boost` TEXT NOT NULL COMMENT 'Information about the chat boost',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_boost_removed` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'Chat which was boosted',
`boost_id` varchar(200) NOT NULL COMMENT 'Unique identifier of the boost',
`remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed',
`source` TEXT NOT NULL COMMENT 'Source of the removed boost',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `telegram_update` (
`id` bigint UNSIGNED COMMENT 'Update''s unique identifier',
`chat_id` bigint NULL DEFAULT NULL COMMENT 'Unique chat identifier',
`message_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming message of any kind - text, photo, sticker, etc.',
`edited_message_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New version of a message that is known to the bot and was edited',
`channel_post_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming channel post of any kind - text, photo, sticker, etc.',
`edited_channel_post_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New version of a channel post that is known to the bot and was edited',
`message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user',
`message_reaction_count_id` bigint UNSIGNED DEFAULT NULL COMMENT 'Reactions to a message with anonymous reactions were changed',
`inline_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming inline query',
`chosen_inline_result_id` bigint UNSIGNED DEFAULT NULL COMMENT 'The result of an inline query that was chosen by a user and sent to their chat partner',
`callback_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming callback query',
`shipping_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming shipping query. Only for invoices with flexible price',
`pre_checkout_query_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New incoming pre-checkout query. Contains full information about checkout',
`poll_id` bigint UNSIGNED DEFAULT NULL COMMENT 'New poll state. Bots receive only updates about polls, which are sent or stopped by the bot',
`poll_answer_poll_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls that were sent by the bot itself.',
`my_chat_member_updated_id` BIGINT UNSIGNED NULL COMMENT 'The bot''s chat member status was updated in a chat. For private chats, this update is received only when the bot is blocked or unblocked by the user.',
`chat_member_updated_id` BIGINT UNSIGNED NULL COMMENT 'A chat member''s status was updated in a chat. The bot must be an administrator in the chat and must explicitly specify “chat_member” in the list of allowed_updates to receive these updates.',
`chat_join_request_id` BIGINT UNSIGNED NULL COMMENT 'A request to join the chat has been sent',
PRIMARY KEY (`id`),
KEY `message_id` (`message_id`),
KEY `chat_message_id` (`chat_id`, `message_id`),
KEY `edited_message_id` (`edited_message_id`),
KEY `channel_post_id` (`channel_post_id`),
KEY `edited_channel_post_id` (`edited_channel_post_id`),
KEY `inline_query_id` (`inline_query_id`),
KEY `chosen_inline_result_id` (`chosen_inline_result_id`),
KEY `callback_query_id` (`callback_query_id`),
KEY `shipping_query_id` (`shipping_query_id`),
KEY `pre_checkout_query_id` (`pre_checkout_query_id`),
KEY `poll_id` (`poll_id`),
KEY `poll_answer_poll_id` (`poll_answer_poll_id`),
KEY `my_chat_member_updated_id` (`my_chat_member_updated_id`),
KEY `chat_member_updated_id` (`chat_member_updated_id`),
KEY `chat_join_request_id` (`chat_join_request_id`),
FOREIGN KEY (`chat_id`, `message_id`) REFERENCES `message` (`chat_id`, `id`),
FOREIGN KEY (`edited_message_id`) REFERENCES `edited_message` (`id`),
FOREIGN KEY (`chat_id`, `channel_post_id`) REFERENCES `message` (`chat_id`, `id`),
FOREIGN KEY (`edited_channel_post_id`) REFERENCES `edited_message` (`id`),
FOREIGN KEY (`inline_query_id`) REFERENCES `inline_query` (`id`),
FOREIGN KEY (`chosen_inline_result_id`) REFERENCES `chosen_inline_result` (`id`),
FOREIGN KEY (`callback_query_id`) REFERENCES `callback_query` (`id`),
FOREIGN KEY (`shipping_query_id`) REFERENCES `shipping_query` (`id`),
FOREIGN KEY (`pre_checkout_query_id`) REFERENCES `pre_checkout_query` (`id`),
FOREIGN KEY (`poll_id`) REFERENCES `poll` (`id`),
FOREIGN KEY (`poll_answer_poll_id`) REFERENCES `poll_answer` (`poll_id`),
FOREIGN KEY (`my_chat_member_updated_id`) REFERENCES `chat_member_updated` (`id`),
FOREIGN KEY (`chat_member_updated_id`) REFERENCES `chat_member_updated` (`id`),
FOREIGN KEY (`chat_join_request_id`) REFERENCES `chat_join_request` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `conversation` (
`id` bigint(20) unsigned AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`user_id` bigint NULL DEFAULT NULL COMMENT 'Unique user identifier',
`chat_id` bigint NULL DEFAULT NULL COMMENT 'Unique user or chat identifier',
`status` ENUM('active', 'cancelled', 'stopped') NOT NULL DEFAULT 'active' COMMENT 'Conversation state',
`command` varchar(160) DEFAULT '' COMMENT 'Default command to execute',
`notes` text DEFAULT NULL COMMENT 'Data stored from command',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
`updated_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date update',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `chat_id` (`chat_id`),
KEY `status` (`status`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `request_limiter` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` char(255) NULL DEFAULT NULL COMMENT 'Unique chat identifier',
`inline_message_id` char(255) NULL DEFAULT NULL COMMENT 'Identifier of the sent inline message',
`method` char(255) DEFAULT NULL COMMENT 'Request method',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
diff --git a/utils/db-schema-update/0.82.0-unreleased.sql b/utils/db-schema-update/0.82.0-unreleased.sql
index 3fb04f3..537307c 100644
--- a/utils/db-schema-update/0.82.0-unreleased.sql
+++ b/utils/db-schema-update/0.82.0-unreleased.sql
@@ -1,67 +1,71 @@
CREATE TABLE IF NOT EXISTS `message_reaction` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'The chat containing the message the user reacted to',
`message_id` bigint COMMENT 'Unique identifier of the message inside the chat',
`user_id` bigint NULL COMMENT 'Optional. The user that changed the reaction, if the user isn''t anonymous',
`actor_chat_id` bigint NULL COMMENT 'Optional. The chat on behalf of which the reaction was changed, if the user is anonymous',
`old_reaction` TEXT NOT NULL COMMENT 'Previous list of reaction types that were set by the user',
`new_reaction` TEXT NOT NULL COMMENT 'New list of reaction types that have been set by the user',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
KEY `user_id` (`user_id`),
KEY `actor_chat_id` (`actor_chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`),
FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
FOREIGN KEY (`actor_chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `message_reaction_count` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'The chat containing the message',
`message_id` bigint COMMENT 'Unique message identifier inside the chat',
`reactions` TEXT NOT NULL COMMENT 'List of reactions that are present on the message',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_boost_updated` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'Chat which was boosted',
`boost` TEXT NOT NULL COMMENT 'Information about the chat boost',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
CREATE TABLE IF NOT EXISTS `chat_boost_removed` (
`id` bigint UNSIGNED AUTO_INCREMENT COMMENT 'Unique identifier for this entry',
`chat_id` bigint COMMENT 'Chat which was boosted',
`boost_id` varchar(200) NOT NULL COMMENT 'Unique identifier of the boost',
`remove_date` timestamp NOT NULL COMMENT 'Point in time (Unix timestamp) when the boost was removed',
`source` TEXT NOT NULL COMMENT 'Source of the removed boost',
`created_at` timestamp NULL DEFAULT NULL COMMENT 'Entry date creation',
PRIMARY KEY (`id`),
KEY `chat_id` (`chat_id`),
FOREIGN KEY (`chat_id`) REFERENCES `chat` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
ALTER TABLE `message`
ADD COLUMN `external_reply` TEXT NULL DEFAULT NULL COMMENT 'Optional. Information about the message that is being replied to, which may come from another chat or forum topic' AFTER `reply_to_message`,
ADD COLUMN `link_preview_options` TEXT NULL DEFAULT NULL COMMENT 'Optional. Options used for link preview generation for the message, if it is a text message and link preview options were changed' AFTER `via_bot`,
- CHANGE COLUMN `user_shared` `users_shared` TEXT;
+ CHANGE COLUMN `user_shared` `users_shared` TEXT,
+ ADD COLUMN `boost_added` TEXT NULL COMMENT 'Service message: user boosted the chat' AFTER `proximity_alert_triggered`,
+ ADD COLUMN `quote` TEXT NULL DEFAULT NULL COMMENT 'Optional. For replies that quote part of the original message, the quoted part of the message' AFTER `external_reply`,
+ ADD COLUMN `reply_to_story` TEXT NULL DEFAULT NULL COMMENT 'Optional. For replies to a story, the original story' AFTER `quote`,
+ ADD COLUMN `sender_boost_count` bigint NULL COMMENT 'If the sender of the message boosted the chat, the number of boosts added by the user' AFTER `user_id`;
ALTER TABLE `telegram_update`
ADD COLUMN `message_reaction_id` bigint UNSIGNED DEFAULT NULL COMMENT 'A reaction to a message was changed by a user' AFTER `edited_channel_post_id`,
ADD COLUMN `message_reaction_count_id` bigint UNSIGNED DEFAULT NULL COMMENT 'Reactions to a message with anonymous reactions were changed' AFTER `message_reaction_id`;

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 15, 5:35 AM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
150551
Default Alt Text
(220 KB)

Event Timeline