diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6fd0a37..0000000 --- a/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Compiled Lua sources -luac.out - -# luarocks build files -*.src.rock -*.zip -*.tar.gz - -# Object files -*.o -*.os -*.ko -*.obj -*.elf - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo -*.def -*.exp - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ff3ebb6..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tg"] - path = tg - url = https://github.com/SEEDTEAM/tg diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 8cdb845..0000000 --- a/LICENSE +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. - diff --git a/README.md b/README.md index b8945da..11c3dce 100644 --- a/README.md +++ b/README.md @@ -1,506 +1,6 @@ -# [TeleSeed](https://telegram.me/TeleSeed) -[![Join the chat at https://gitter.im/SEEDTEAM/TeleSeed](https://badges.gitter.im/SEEDTEAM/TeleSeed.svg)](https://gitter.im/SEEDTEAM/TeleSeed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +### BlackPlus > [GitHub](https://GitHub.com/Mehdi-HS/BlackPlus) | [Site](BlackPlus.ir) | [Channel](https://telegram.me/black_ch) | [Bot ID](https;//telegram.me/blackplus) -**An advanced and powerful administration bot based on [yagop/telegram-bot](https://github.com/yagop/telegram-bot) licensed under the [GNU General Public License](https://github.com/SEEDTEAM/TeleSeed/blob/master/LICENSE)**. -# Features -* **A powerful antispam system with custom sensitivity for each group** -* **Multiple realms (admin groups)** -* **Recalcitrant to any kind of spamming (X/Y bots, name/photo changers, etc.)** -* **Global banning** -* **Broadcast to all groups** -* **Group links** -* **Kick, ban and unban by reply** -* **Groups, ban and global ban list** -* **Logging anything that happens in a group** -* **Invitation by username** -* **Group administration via private messages** -* **Only mods, owner and admin can add bots** -* **Arabic lock** -* **And more!** -**Table of Contents** -- [TeleSeed](#teleseed) -- [Features](#features) -- [Commands](#commands) - - [Admins commands](#admins-commands) - - [Realm creation](#realm-creation) - - [Group creation](#group-creation) - - [Adding and removing realms](#add-or-remove-realms) - - [Adding and removing groups](#add-or-remove-groups) - - [Leaving groups](#leaving) - - [Everything about groups](#everything-about-groups) - - [Setting descriptions in realm](#setting-description-in-realm) - - [Setting group names in realm](#setting-group-name-in-realm) - - [Setting rules in realm](#setting-rules-in-realm) - - [Locking group names/photos/flood/members in realm](#lock-groups-namefloodphotomember-in-realm) - - [Unlocking group names/photos/flood/members](#unlock-groups-namefloodphotomember) - - [Group settings in realm](#group-setting-in-realm) - - [Adding admins](#add-admin) - - [Removing admins](#remove-admin) - - [Admin/group listing in realm](#adminsgroup-list-in-realm) - - [Broadcasting](#broadcast) - - [Realm help](#realm-help) - - [Global ban commands](#global-ban-commands) - - [Set group owner](#set-group-owner) - - [Bot stats](#bot-stats) - - [Owner and mod commands](#owners-and-mods-commands) - - [Hammer](#hammer) - - [Locking a group's name/members/bots/arabic/flood](#group-namememberarabicfloodbots-lock) - - [Unlocking a group's name/members/bots/arabic/flood](#group-namememberarabicfloodbots-unlock) - - [Cleaning a group's modlist/rules/about/members](#group-modlistrulesaboutmember-clean) - - [Seting a group's rules/about](#set-groups-rulesabout) - - [Setting or changing a group's owner](#setting-or-changing-group-photo) - - [Setting or changing a group's photo](#setting-or-changing-group-photo) - - [Changing a group's name](#changing-group-name) - - [Group links](#group-link) - - [Promoting and demoting mods](#promote-and-demote-mods) - - [Resolving usernames](#resolve-username) - - [Flood sensitivity](#flood-sensitivity) - - [Group rules and about](#group-rules-and-about) - - [Group settings](#group-settings) - - [Modlist](#modlist) - - [Help](#help) - - [Owner](#owner) - - [Save and Get](#save-and-get) - - [Id](#id) - - [Group stats](#group-stats) - - [Member list](#member-list) - - [Group help](#group-help) - - [In private commands](#in-private-commands) - - [Hammer](#hammer) - - [Cleaning](#cleaning) - - [Setting flood sensitivity](#setting-flood-sensitivity) - - [Locking a group's members/name](#lock-groups-membername) - - [Unlocking a group's members/name](#unlock-groups-membername) - - [Group link](#group-link) - - [Changing name/rules](#change-namerulesname) - - [Group log](#group-log) - - [Join](#join) -- [Installation](#installation) - - [One command](#one-command) - - [Realm configuration](#realm-configuration) -- [Support and development](#support-and-development) -- [Special thanks to:](#special-thanks-to) -- [Our team!](#our-team) - -# Commands -## Admins commands -**Only admins and sudo users can run these commands.** -### Group creation ->[!/]creategroup [group name] -> ->>[!/]creategroup SEED ->>>will create a group ->>> ->>>_Only works in realms for admins but, sudo users can use it everywhere_ - -### Realm creation ->[!/]createrealm [realm name] -> ->>[!/]createrealm SEED ->>>will create a realm ->>> ->>>_Only works in realms for admins but, sudo users can use it everywhere_ - -###Add or remove realms ->[!/]add realm ->>This command will add that group -> ->[!/]rem realm ->>This command will remove that group - - -###Add or remove groups ->[!/]add ->>This command will add that group -> ->[!/]rem ->>This command will remove that group - -###Leaving ->[!/]leave ->>Bot will leave that group - -###Everything about groups ->[!/]all ->>This command will return everything about that group -> ->[!/]all [group_id] ->>_Only onwer, admin and sudo users can use this command_ - - -### Setting description in realm -> [!/]setabout [group_id] [text] ->>[!/]setabout 123456789 about ->>>This command will set [text] as description of [group_id] - - -### Setting group name in realm -> [!/]setname [group_id] [text] ->>[!/]setname 123456789 SEED ->>>This command will set [text] as name of [group_id] - -### Setting rules in realm -> [!/]setrules [group_id] [text] ->>[!/]setrules 123456789 rules ! ->>>This command will set [text] as rules of [group_id] - - -### Lock groups name|flood|photo|member in realm -> [!/]lock [group_id] [name|flood|photo|member] ->>[!/]lock 123456789 name ->>>This command will lock name|flood|photo|member of [group_id] - - -### Unlock groups name|flood|photo|member -> [!/]unlock [group_id] [name|flood|photo|member] ->>[!/]unlock 123456789 name ->>>This command will unlock name|flood|photo|member of [group_id] - -## Group setting in realm ->[!/]setting [group_id] ->>[!/]setting 12345678 ->>>This command will return settings of [group_id] - -### Add admin ->[!/]addadmin [username] ->>[!/]addadmin @username ->>>This command will add username as admin ->>> ->>>_Only works in realms_ - -### Remove admin ->[!/]removeadmin [username] -> ->>[!/]removeadmin @username ->>>This command will add username as admin ->>> ->>>_Only works in realms_ [username] - -### Admins|group list in realm ->[!/]list [admins|groups] ->>[!/]list groups ->>>This command will return admins|groups list - -### Broadcast ->[!/]broadcast [text] ->>[!/]broadcast Hello ! ->>>This command will send text to all groups ->>> ->>>_Only sudo users can run this command_ -> ->[!/]bc [group_id] [text] ->>[!/]bc 123456789 Hello ! ->>>This command will send text to [group_id] - -##Global ban commands ->[!/]banall [id] ->>[!/]banall 123456789 ->>>This commands will globally ban [id] -> ->/sync_gbans ->>Sync your global bans with teleseed -> ->[!/]unbanall [id] ->>[!/]unbanall 123456789 ->>>This commands will remove [id] from global bans -> ->[!/]gbanlist ->>This command will return global bans ids -> ->[!/]banlist [group_id] ->>[!/]banlist 123456789 ->>>This command will return banned user of [group_id] - -### Set group owner ->[!/]setgpowner [group_id] [User_id] ->>[!/]setgpowner 123456789 987654321 ->>>This command will set [User_id] as the owner of [group_id] - -### Bot stats ->[!/]stats teleseed ->>This command will return bot stats - -# Realm Help ->[!/]help ->>Get realm commands list - - - - -## owners and mods commands - -_Sudo users and admins can also use this commands in all groups_ - -### Hammer - ->[!/]kick [username|id] ->>[!/]kick @useranme ->>[!/]kick 123456789 ->>>This command will remove that user -> ->[!/]ban [username|id] ->>[!/]ban @username ->>[!/]ban 123456789 ->>>this command will ban and remove that user -> ->[!/]unban [id] ->>[!/]unban 12345678 ->>>This command will unban that user -> ->[!/]banlist ->>This command will return bans list - -### group name|member|arabic|flood|bots lock ->[!/]lock [name|member|arabic|flood|bots] ->>[!/]lock flood ->>>This command will lock name|member|arabic|flood|bots of groups - -### group name|member|arabic|flood|bots unlock ->[!/]unlock [name|member|arabic|flood|bots] ->>[!/]unlock flood ->>>This command will unlock name|member|arabic|flood|bots of groups - -### Group modlist|rules|about|member clean ->[!/]clean [modlist|rules|about|member] ->>[!/]clean modlist ->>>This command will clean modlist|rules|about|member ->>>_/clean member will kick all users except owner,admins and bot and it's for owners only_ - -### Set groups rules|about ->[!/]set [rules|about] [text] ->>[!/]set rules don't spam! ->> ->>No NSFW ->>> This command will set [text] as the rules|about of groups - -### Setting or changing group owner ->[!/]setowner [id] ->>[!/]setowner 123456789 ->>>This command will set id as owner of that group - -### Setting or changing group photo ->[!/]setphoto ->> This command will change or set group photo ->>_also locks photo_ - -### Changing Group name ->[!/]setname [name] ->>[!/]setname SEED ->>>This command will set [name] as name of groups - -### Group link ->[!/]newlink ->>This command will revoke group link -> ->[!/]link ->>This command will return group link - -### Promote and demote mods ->[!/]promote [username] ->>[!/]promote @username ->>>This command will promote @username as moderator -> ->[!/]demote [username] ->>[!/]demote @username ->>> This command will demote @username - -### Resolve username ->[!/]res [username] ->>[!/]res @username ->>>This command will return info about that username - -### Flood sensitivity ->[!/]setflood [value] ->>[!/]setflood 15 ->>> will set flood sensitivity to [value] - -### Group rules and about ->[!/]about ->>This command will return group description -> ->[!/]rules ->>This command will return group rules ->>>_normal users can use it too_ - -### Group settings ->[!/]setting ->>This command will return group settings - -### modlist ->[!/]modlist ->>This command will return group moderators ->>>_normal users can use it too_ - -###Help ->[!/]help - -### Owner ->[!/]owner ->>This command will return owners id - -### Save and get ->[!/]save [title] [text] ->>[!/]save spam Don't spam ! ->>>This command will save text as that title -> ->[!/]get [title] ->>[!/]get spam ->>>This command will return text of that title - -### Id ->[!/]id ->>This command will return user or group id ->>_can be triggered by reply_ ->> ->>_Normal users can use it_ - -### group stats ->[!/]stats ->>This command will return group message statistic in a .txt file -> ->[!/]statslist ->>This command will return group message statistic - -### member list ->[!/]who ->>This command will return member list in a .txt file -> ->[!/]wholist ->>This command will return member list - -# Group Help ->[!/]help ->>Get commands list - - - -## in private commands - -**These commands only works in bots private** - -### Hammer ->[!/]owners group_id [kick|ban|unban] user_id ->>[!/]owners 1234567 kick 1234567 - -### cleaning ->[!/]owners group_id clean [modlist|rules|about] ->>[!/]owners 1234567 clean modlist - -### setting flood sensitivity ->[!/]owners group_id setflood value ->>[!/]owners 1234567 setflood 17 - -### lock groups member|name ->[!/]owners group_id lock [member|name] ->>[!/]owners 1234567 lock member - -#### unlock groups member|name ->[!/]owner group_id unlock [member|name] ->>[!/]owners 1234567 unlock name - -### Group link ->[!/]owners group_id get link ->>[!/]owners 1234567 get link -> ->[!/]owners group_id new link ->>[!/]owners 1234567 new link - -### change name|rules|name ->[!/]changename [group_id] [name] ->>[!/]changename 123456789 SEED -> ->[!/]changrules [group_id] [rules] ->>[!/]changrules 123456789 rules ! -> ->[!/]changeabout [group_id] [about] ->>[!/]changeabout 123456789 about ! - -### Group log ->[!/]loggroup [group_id] ->>[!/]loggroup 123456789 - -### Join ->[!/]oin [group_id] ->> This command will add user in [group_id] - - -**U can use both "/" and "!"** - -# Installation - -```sh -# Install dependencies. -# Tested on Ubuntu 14.04. For other OSs, check out https://github.com/yagop/telegram-bot/wiki/Installation -sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev make unzip git redis-server g++ libjansson-dev libpython-dev expat libexpat1-dev - -# Let's install the bot. -cd $HOME -git clone https://github.com/SEEDTEAM/TeleSeed.git -cd TeleSeed -chmod +x launch.sh -./launch.sh install -./launch.sh # Enter a phone number & confirmation code. -``` -### One command -To install everything in one command (useful for VPS deployment) on Debian-based distros, use: -```sh -#https://github.com/yagop/telegram-bot/wiki/Installation -sudo apt-get update; sudo apt-get upgrade -y --force-yes; sudo apt-get dist-upgrade -y --force-yes; sudo apt-get install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson* libpython-dev make unzip git redis-server g++ -y --force-yes && git clone https://github.com/SEEDTEAM/TeleSeed.git && cd TeleSeed && chmod +x launch.sh && ./launch.sh install && ./launch.sh -``` -### Realm configuration - -After you run the bot for first time, send it `!id`. Get your ID and stop the bot. - -Open ./data/config.lua and add your ID to the "sudo_users" section in the following format: -``` - sudo_users = { - 110626080, - 103649648, - 111020322, - 0, - YourID - } -``` -Then restart the bot. - -Create a realm using the `!createrealm` command. - -# Support and development - -Check out this [tutorial by Telegram Geeks](http://telegramgeeks.com/2016/01/teleseed-tutorial/) for further assistance with setup and installation. - -**Do not contact us** in private for support. -Join our bot development group by sending `/join 56670147` to [@TeleSeed](https://telegram.me/TeleSeed) - -# Special thanks to -[@seyedan25](https://telegram.me/seyedan25) - -For managing [@teleseed](https://telegram.me/TeleSeed) on Telegram. - -[@Vamptacus](https://telegram.me/Vamptacus) - -For graphic designs. - -[topkecleon](https://github.com/topkecleon) - -[Juan Potato](https://github.com/JuanPotato) - -# Our team! - -[Alphonse](https://github.com/hmon) ([Telegram](https://telegram.me/iwals)) - -[I M /-\ N](https://github.com/imandaneshi) ([Telegram](https://telegram.me/imandaneshi)) - -[Siyanew](https://github.com/Siyanew) ([Telegram](https://telegram.me/Siyanew)) - -[Rondoozle](https://github.com/Rondoozle) ([Telegram](https://telegram.me/POTUS)) - -###Our Telegram channels: - -English: [@TeleSeedCH](https://telegram.me/teleseedch) - -Persian: [@IranSeed](https://telegram.me/iranseed) diff --git a/bot/seedbot.lua b/bot/seedbot.lua deleted file mode 100644 index 8dc5ac4..0000000 --- a/bot/seedbot.lua +++ /dev/null @@ -1,520 +0,0 @@ -package.path = package.path .. ';.luarocks/share/lua/5.2/?.lua' - ..';.luarocks/share/lua/5.2/?/init.lua' -package.cpath = package.cpath .. ';.luarocks/lib/lua/5.2/?.so' - -require("./bot/utils") - -VERSION = '2' - --- This function is called when tg receive a msg -function on_msg_receive (msg) - if not started then - return - end - - local receiver = get_receiver(msg) - print (receiver) - - --vardump(msg) - msg = pre_process_service_msg(msg) - if msg_valid(msg) then - msg = pre_process_msg(msg) - if msg then - match_plugins(msg) - if redis:get("bot:markread") then - if redis:get("bot:markread") == "on" then - mark_read(receiver, ok_cb, false) - end - end - end - end -end - -function ok_cb(extra, success, result) -end - -function on_binlog_replay_end() - started = true - postpone (cron_plugins, false, 60*5.0) - - _config = load_config() - - -- load plugins - plugins = {} - load_plugins() -end - -function msg_valid(msg) - -- Don't process outgoing messages - if msg.out then - print('\27[36mNot valid: msg from us\27[39m') - return false - end - - -- Before bot was started - if msg.date < now then - print('\27[36mNot valid: old msg\27[39m') - return false - end - - if msg.unread == 0 then - print('\27[36mNot valid: readed\27[39m') - return false - end - - if not msg.to.id then - print('\27[36mNot valid: To id not provided\27[39m') - return false - end - - if not msg.from.id then - print('\27[36mNot valid: From id not provided\27[39m') - return false - end - - if msg.from.id == our_id then - print('\27[36mNot valid: Msg from our id\27[39m') - return false - end - - if msg.to.type == 'encr_chat' then - print('\27[36mNot valid: Encrypted chat\27[39m') - return false - end - - if msg.from.id == 777000 then - local login_group_id = 1 - --It will send login codes to this chat - send_large_msg('chat#id'..login_group_id, msg.text) - end - - return true -end - --- -function pre_process_service_msg(msg) - if msg.service then - local action = msg.action or {type=""} - -- Double ! to discriminate of normal actions - msg.text = "!!tgservice " .. action.type - - -- wipe the data to allow the bot to read service messages - if msg.out then - msg.out = false - end - if msg.from.id == our_id then - msg.from.id = 0 - end - end - return msg -end - --- Apply plugin.pre_process function -function pre_process_msg(msg) - for name,plugin in pairs(plugins) do - if plugin.pre_process and msg then - print('Preprocess', name) - msg = plugin.pre_process(msg) - end - end - - return msg -end - --- Go over enabled plugins patterns. -function match_plugins(msg) - for name, plugin in pairs(plugins) do - match_plugin(plugin, name, msg) - end -end - --- Check if plugin is on _config.disabled_plugin_on_chat table -local function is_plugin_disabled_on_chat(plugin_name, receiver) - local disabled_chats = _config.disabled_plugin_on_chat - -- Table exists and chat has disabled plugins - if disabled_chats and disabled_chats[receiver] then - -- Checks if plugin is disabled on this chat - for disabled_plugin,disabled in pairs(disabled_chats[receiver]) do - if disabled_plugin == plugin_name and disabled then - local warning = 'Plugin '..disabled_plugin..' is disabled on this chat' - print(warning) - send_msg(receiver, warning, ok_cb, false) - return true - end - end - end - return false -end - -function match_plugin(plugin, plugin_name, msg) - local receiver = get_receiver(msg) - - -- Go over patterns. If one matches it's enough. - for k, pattern in pairs(plugin.patterns) do - local matches = match_pattern(pattern, msg.text) - if matches then - print("msg matches: ", pattern) - - if is_plugin_disabled_on_chat(plugin_name, receiver) then - return nil - end - -- Function exists - if plugin.run then - -- If plugin is for privileged users only - if not warns_user_not_allowed(plugin, msg) then - local result = plugin.run(msg, matches) - if result then - send_large_msg(receiver, result) - end - end - end - -- One patterns matches - return - end - end -end - --- DEPRECATED, use send_large_msg(destination, text) -function _send_msg(destination, text) - send_large_msg(destination, text) -end - --- Save the content of _config to config.lua -function save_config( ) - serialize_to_file(_config, './data/config.lua') - print ('saved config into ./data/config.lua') -end - --- Returns the config from config.lua file. --- If file doesn't exist, create it. -function load_config( ) - local f = io.open('./data/config.lua', "r") - -- If config.lua doesn't exist - if not f then - print ("Created new config file: data/config.lua") - create_config() - else - f:close() - end - local config = loadfile ("./data/config.lua")() - for v,user in pairs(config.sudo_users) do - print("Allowed user: " .. user) - end - return config -end - --- Create a basic config.json file and saves it. -function create_config( ) - -- A simple config with basic plugins and ourselves as privileged user - config = { - enabled_plugins = { - "onservice", - "inrealm", - "ingroup", - "inpm", - "banhammer", - "stats", - "anti_spam", - "owners", - "arabic_lock", - "set", - "get", - "broadcast", - "download_media", - "invite", - "all", - "leave_ban", - "admin" - }, - sudo_users = {110626080,103649648,143723991,111020322,0,tonumber(our_id)},--Sudo users - disabled_channels = {}, - moderation = {data = 'data/moderation.json'}, - about_text = [[Teleseed v2 - Open Source -An advance Administration bot based on yagop/telegram-bot - -https://github.com/SEEDTEAM/TeleSeed - -Admins -@iwals [Founder] -@imandaneshi [Developer] -@Rondoozle [Developer] -@seyedan25 [Manager] - -Special thanks to -awkward_potato -Siyanew -topkecleon -Vamptacus - -Our channels -@teleseedch [English] -@iranseed [persian] -]], - help_text_realm = [[ -Realm Commands: - -!creategroup [Name] -Create a group - -!createrealm [Name] -Create a realm - -!setname [Name] -Set realm name - -!setabout [GroupID] [Text] -Set a group's about text - -!setrules [GroupID] [Text] -Set a group's rules - -!lock [GroupID] [setting] -Lock a group's setting - -!unlock [GroupID] [setting] -Unock a group's setting - -!wholist -Get a list of members in group/realm - -!who -Get a file of members in group/realm - -!type -Get group type - -!kill chat [GroupID] -Kick all memebers and delete group - -!kill realm [RealmID] -Kick all members and delete realm - -!addadmin [id|username] -Promote an admin by id OR username *Sudo only - -!removeadmin [id|username] -Demote an admin by id OR username *Sudo only - -!list groups -Get a list of all groups - -!list realms -Get a list of all realms - -!log -Grt a logfile of current group or realm - -!broadcast [text] -!broadcast Hello ! -Send text to all groups -Only sudo users can run this command - -!bc [group_id] [text] -!bc 123456789 Hello ! -This command will send text to [group_id] - - -**U can use both "/" and "!" - - -*Only admins and sudo can add bots in group - - -*Only admins and sudo can use kick,ban,unban,newlink,setphoto,setname,lock,unlock,set rules,set about and settings commands - -*Only admins and sudo can use res, setowner, commands -]], - help_text = [[ -Commands list : - -!kick [username|id] -You can also do it by reply - -!ban [ username|id] -You can also do it by reply - -!unban [id] -You can also do it by reply - -!who -Members list - -!modlist -Moderators list - -!promote [username] -Promote someone - -!demote [username] -Demote someone - -!kickme -Will kick user - -!about -Group description - -!setphoto -Set and locks group photo - -!setname [name] -Set group name - -!rules -Group rules - -!id -return group id or user id - -!help - -!lock [member|name|bots|leave] -Locks [member|name|bots|leaveing] - -!unlock [member|name|bots|leave] -Unlocks [member|name|bots|leaving] - -!set rules -Set as rules - -!set about -Set as about - -!settings -Returns group settings - -!newlink -create/revoke your group link - -!link -returns group link - -!owner -returns group owner id - -!setowner [id] -Will set id as owner - -!setflood [value] -Set [value] as flood sensitivity - -!stats -Simple message statistics - -!save [value] -Save as [value] - -!get [value] -Returns text of [value] - -!clean [modlist|rules|about] -Will clear [modlist|rules|about] and set it to nil - -!res [username] -returns user id -"!res @username" - -!log -will return group logs - -!banlist -will return group ban list - -**U can use both "/" and "!" - - -*Only owner and mods can add bots in group - - -*Only moderators and owner can use kick,ban,unban,newlink,link,setphoto,setname,lock,unlock,set rules,set about and settings commands - -*Only owner can use res,setowner,promote,demote and log commands - -]] - } - serialize_to_file(config, './data/config.lua') - print('saved config into ./data/config.lua') -end - -function on_our_id (id) - our_id = id -end - -function on_user_update (user, what) - --vardump (user) -end - -function on_chat_update (chat, what) - -end - -function on_secret_chat_update (schat, what) - --vardump (schat) -end - -function on_get_difference_end () -end - --- Enable plugins in config.json -function load_plugins() - for k, v in pairs(_config.enabled_plugins) do - print("Loading plugin", v) - - local ok, err = pcall(function() - local t = loadfile("plugins/"..v..'.lua')() - plugins[v] = t - end) - - if not ok then - print('\27[31mError loading plugin '..v..'\27[39m') - print(tostring(io.popen("lua plugins/"..v..".lua"):read('*all'))) - print('\27[31m'..err..'\27[39m') - end - - end -end - - --- custom add -function load_data(filename) - - local f = io.open(filename) - if not f then - return {} - end - local s = f:read('*all') - f:close() - local data = JSON.decode(s) - - return data - -end - -function save_data(filename, data) - - local s = JSON.encode(data) - local f = io.open(filename, 'w') - f:write(s) - f:close() - -end - --- Call and postpone execution for cron plugins -function cron_plugins() - - for name, plugin in pairs(plugins) do - -- Only plugins with cron function - if plugin.cron ~= nil then - plugin.cron() - end - end - - -- Called again in 2 mins - postpone (cron_plugins, false, 120) -end - --- Start and load values -our_id = 0 -now = os.time() -math.randomseed(now) -started = false diff --git a/bot/utils.lua b/bot/utils.lua deleted file mode 100644 index 2c2498e..0000000 --- a/bot/utils.lua +++ /dev/null @@ -1,958 +0,0 @@ -URL = require "socket.url" -http = require "socket.http" -https = require "ssl.https" -ltn12 = require "ltn12" -serpent = require "serpent" -feedparser = require "feedparser" - -json = (loadfile "./libs/JSON.lua")() -mimetype = (loadfile "./libs/mimetype.lua")() -redis = (loadfile "./libs/redis.lua")() -JSON = (loadfile "./libs/dkjson.lua")() - -http.TIMEOUT = 10 - - -function get_receiver(msg) - if msg.to.type == 'user' then - return 'user#id'..msg.from.id - end - if msg.to.type == 'chat' then - return 'chat#id'..msg.to.id - end - if msg.to.type == 'encr_chat' then - return msg.to.print_name - end -end - -function is_chat_msg( msg ) - if msg.to.type == 'chat' then - return true - end - return false -end - -function string.random(length) - local str = ""; - for i = 1, length do - math.random(97, 122) - str = str..string.char(math.random(97, 122)); - end - return str; -end - -function string:split(sep) - local sep, fields = sep or ":", {} - local pattern = string.format("([^%s]+)", sep) - self:gsub(pattern, function(c) fields[#fields+1] = c end) - return fields -end - --- DEPRECATED -function string.trim(s) - print("string.trim(s) is DEPRECATED use string:trim() instead") - return s:gsub("^%s*(.-)%s*$", "%1") -end - --- Removes spaces -function string:trim() - return self:gsub("^%s*(.-)%s*$", "%1") -end - -function get_http_file_name(url, headers) - -- Eg: foo.var - local file_name = url:match("[^%w]+([%.%w]+)$") - -- Any delimited alphanumeric on the url - file_name = file_name or url:match("[^%w]+(%w+)[^%w]+$") - -- Random name, hope content-type works - file_name = file_name or str:random(5) - - local content_type = headers["content-type"] - - local extension = nil - if content_type then - extension = mimetype.get_mime_extension(content_type) - end - if extension then - file_name = file_name.."."..extension - end - - local disposition = headers["content-disposition"] - if disposition then - -- attachment; filename=CodeCogsEqn.png - file_name = disposition:match('filename=([^;]+)') or file_name - end - - return file_name -end - --- Saves file to /tmp/. If file_name isn't provided, --- will get the text after the last "/" for filename --- and content-type for extension -function download_to_file(url, file_name) - print("url to download: "..url) - - local respbody = {} - local options = { - url = url, - sink = ltn12.sink.table(respbody), - redirect = true - } - - -- nil, code, headers, status - local response = nil - - if url:starts('https') then - options.redirect = false - response = {https.request(options)} - else - response = {http.request(options)} - end - - local code = response[2] - local headers = response[3] - local status = response[4] - - if code ~= 200 then return nil end - - file_name = file_name or get_http_file_name(url, headers) - - local file_path = "/tmp/"..file_name - print("Saved to: "..file_path) - - file = io.open(file_path, "w+") - file:write(table.concat(respbody)) - file:close() - - return file_path -end - -function vardump(value) - print(serpent.block(value, {comment=false})) -end - --- taken from http://stackoverflow.com/a/11130774/3163199 -function scandir(directory) - local i, t, popen = 0, {}, io.popen - for filename in popen('ls -a "'..directory..'"'):lines() do - i = i + 1 - t[i] = filename - end - return t -end - --- http://www.lua.org/manual/5.2/manual.html#pdf-io.popen -function run_command(str) - local cmd = io.popen(str) - local result = cmd:read('*all') - cmd:close() - return result -end - --- User has privileges -function is_sudo(msg) - local var = false - -- Check users id in config - for v,user in pairs(_config.sudo_users) do - if user == msg.from.id then - var = true - end - end - return var -end - --- Returns the name of the sender -function get_name(msg) - local name = msg.from.first_name - if name == nil then - name = msg.from.id - end - return name -end - --- Returns at table of lua files inside plugins -function plugins_names( ) - local files = {} - for k, v in pairs(scandir("plugins")) do - -- Ends with .lua - if (v:match(".lua$")) then - table.insert(files, v) - end - end - return files -end - --- Function name explains what it does. -function file_exists(name) - local f = io.open(name,"r") - if f ~= nil then - io.close(f) - return true - else - return false - end -end - --- Save into file the data serialized for lua. --- Set uglify true to minify the file. -function serialize_to_file(data, file, uglify) - file = io.open(file, 'w+') - local serialized - if not uglify then - serialized = serpent.block(data, { - comment = false, - name = '_' - }) - else - serialized = serpent.dump(data) - end - file:write(serialized) - file:close() -end - --- Returns true if the string is empty -function string:isempty() - return self == nil or self == '' -end - --- Returns true if the string is blank -function string:isblank() - self = self:trim() - return self:isempty() -end - --- DEPRECATED!!!!! -function string.starts(String, Start) - print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead") - return Start == string.sub(String,1,string.len(Start)) -end - --- Returns true if String starts with Start -function string:starts(text) - return text == string.sub(self,1,string.len(text)) -end - --- Send image to user and delete it when finished. --- cb_function and cb_extra are optionals callback -function _send_photo(receiver, file_path, cb_function, cb_extra) - local cb_extra = { - file_path = file_path, - cb_function = cb_function, - cb_extra = cb_extra - } - -- Call to remove with optional callback - send_photo(receiver, file_path, cb_function, cb_extra) -end - --- Download the image and send to receiver, it will be deleted. --- cb_function and cb_extra are optionals callback -function send_photo_from_url(receiver, url, cb_function, cb_extra) - -- If callback not provided - cb_function = cb_function or ok_cb - cb_extra = cb_extra or false - - local file_path = download_to_file(url, false) - if not file_path then -- Error - local text = 'Error downloading the image' - send_msg(receiver, text, cb_function, cb_extra) - else - print("File path: "..file_path) - _send_photo(receiver, file_path, cb_function, cb_extra) - end -end - --- Same as send_photo_from_url but as callback function -function send_photo_from_url_callback(cb_extra, success, result) - local receiver = cb_extra.receiver - local url = cb_extra.url - - local file_path = download_to_file(url, false) - if not file_path then -- Error - local text = 'Error downloading the image' - send_msg(receiver, text, ok_cb, false) - else - print("File path: "..file_path) - _send_photo(receiver, file_path, ok_cb, false) - end -end - --- Send multiple images asynchronous. --- param urls must be a table. -function send_photos_from_url(receiver, urls) - local cb_extra = { - receiver = receiver, - urls = urls, - remove_path = nil - } - send_photos_from_url_callback(cb_extra) -end - --- Use send_photos_from_url. --- This function might be difficult to understand. -function send_photos_from_url_callback(cb_extra, success, result) - -- cb_extra is a table containing receiver, urls and remove_path - local receiver = cb_extra.receiver - local urls = cb_extra.urls - local remove_path = cb_extra.remove_path - - -- The previously image to remove - if remove_path ~= nil then - os.remove(remove_path) - print("Deleted: "..remove_path) - end - - -- Nil or empty, exit case (no more urls) - if urls == nil or #urls == 0 then - return false - end - - -- Take the head and remove from urls table - local head = table.remove(urls, 1) - - local file_path = download_to_file(head, false) - local cb_extra = { - receiver = receiver, - urls = urls, - remove_path = file_path - } - - -- Send first and postpone the others as callback - send_photo(receiver, file_path, send_photos_from_url_callback, cb_extra) -end - --- Callback to remove a file -function rmtmp_cb(cb_extra, success, result) - local file_path = cb_extra.file_path - local cb_function = cb_extra.cb_function or ok_cb - local cb_extra = cb_extra.cb_extra - - if file_path ~= nil then - os.remove(file_path) - print("Deleted: "..file_path) - end - -- Finally call the callback - cb_function(cb_extra, success, result) -end - --- Send document to user and delete it when finished. --- cb_function and cb_extra are optionals callback -function _send_document(receiver, file_path, cb_function, cb_extra) - local cb_extra = { - file_path = file_path, - cb_function = cb_function or ok_cb, - cb_extra = cb_extra or false - } - -- Call to remove with optional callback - send_document(receiver, file_path, rmtmp_cb, cb_extra) -end - --- Download the image and send to receiver, it will be deleted. --- cb_function and cb_extra are optionals callback -function send_document_from_url(receiver, url, cb_function, cb_extra) - local file_path = download_to_file(url, false) - print("File path: "..file_path) - _send_document(receiver, file_path, cb_function, cb_extra) -end - --- Parameters in ?a=1&b=2 style -function format_http_params(params, is_get) - local str = '' - -- If is get add ? to the beginning - if is_get then str = '?' end - local first = true -- Frist param - for k,v in pairs (params) do - if v then -- nil value - if first then - first = false - str = str..k.. "="..v - else - str = str.."&"..k.. "="..v - end - end - end - return str -end - --- Check if user can use the plugin and warns user --- Returns true if user was warned and false if not warned (is allowed) -function warns_user_not_allowed(plugin, msg) - if not user_allowed(plugin, msg) then - local text = 'This plugin requires privileged user' - local receiver = get_receiver(msg) - send_msg(receiver, text, ok_cb, false) - return true - else - return false - end -end - --- Check if user can use the plugin -function user_allowed(plugin, msg) - if plugin.privileged and not is_sudo(msg) then - return false - end - return true -end - - -function send_order_msg(destination, msgs) - local cb_extra = { - destination = destination, - msgs = msgs - } - send_order_msg_callback(cb_extra, true) -end - -function send_order_msg_callback(cb_extra, success, result) - local destination = cb_extra.destination - local msgs = cb_extra.msgs - local file_path = cb_extra.file_path - if file_path ~= nil then - os.remove(file_path) - print("Deleted: " .. file_path) - end - if type(msgs) == 'string' then - send_large_msg(destination, msgs) - elseif type(msgs) ~= 'table' then - return - end - if #msgs < 1 then - return - end - local msg = table.remove(msgs, 1) - local new_cb_extra = { - destination = destination, - msgs = msgs - } - if type(msg) == 'string' then - send_msg(destination, msg, send_order_msg_callback, new_cb_extra) - elseif type(msg) == 'table' then - local typ = msg[1] - local nmsg = msg[2] - new_cb_extra.file_path = nmsg - if typ == 'document' then - send_document(destination, nmsg, send_order_msg_callback, new_cb_extra) - elseif typ == 'image' or typ == 'photo' then - send_photo(destination, nmsg, send_order_msg_callback, new_cb_extra) - elseif typ == 'audio' then - send_audio(destination, nmsg, send_order_msg_callback, new_cb_extra) - elseif typ == 'video' then - send_video(destination, nmsg, send_order_msg_callback, new_cb_extra) - else - send_file(destination, nmsg, send_order_msg_callback, new_cb_extra) - end - end -end - --- Same as send_large_msg_callback but friendly params -function send_large_msg(destination, text) - local cb_extra = { - destination = destination, - text = text - } - send_large_msg_callback(cb_extra, true) -end - --- If text is longer than 4096 chars, send multiple msg. --- https://core.telegram.org/method/messages.sendMessage -function send_large_msg_callback(cb_extra, success, result) - local text_max = 4096 - - local destination = cb_extra.destination - local text = cb_extra.text - local text_len = string.len(text) - local num_msg = math.ceil(text_len / text_max) - - if num_msg <= 1 then - send_msg(destination, text, ok_cb, false) - else - - local my_text = string.sub(text, 1, 4096) - local rest = string.sub(text, 4096, text_len) - - local cb_extra = { - destination = destination, - text = rest - } - - send_msg(destination, my_text, send_large_msg_callback, cb_extra) - end -end - --- Returns a table with matches or nil -function match_pattern(pattern, text, lower_case) - if text then - local matches = {} - if lower_case then - matches = { string.match(text:lower(), pattern) } - else - matches = { string.match(text, pattern) } - end - if next(matches) then - return matches - end - end - -- nil -end - --- Function to read data from files -function load_from_file(file, default_data) - local f = io.open(file, "r+") - -- If file doesn't exists - if f == nil then - -- Create a new empty table - default_data = default_data or {} - serialize_to_file(default_data, file) - print ('Created file', file) - else - print ('Data loaded from file', file) - f:close() - end - return loadfile (file)() -end - --- See http://stackoverflow.com/a/14899740 -function unescape_html(str) - local map = { - ["lt"] = "<", - ["gt"] = ">", - ["amp"] = "&", - ["quot"] = '"', - ["apos"] = "'" - } - new = string.gsub(str, '(&(#?x?)([%d%a]+);)', function(orig, n, s) - var = map[s] or n == "#" and string.char(s) - var = var or n == "#x" and string.char(tonumber(s,16)) - var = var or orig - return var - end) - return new -end - - - ---Check if this chat is realm or not -function is_realm(msg) - local var = false - local realms = 'realms' - local data = load_data(_config.moderation.data) - local chat = msg.to.id - if data[tostring(realms)] then - if data[tostring(realms)][tostring(msg.to.id)] then - var = true - end - return var - end -end ---Check if this chat is a group or not -function is_group(msg) - local var = false - local groups = 'groups' - local data = load_data(_config.moderation.data) - local chat = msg.to.id - if data[tostring(groups)] then - if data[tostring(groups)][tostring(msg.to.id)] then - var = true - end - return var - end -end - - -function savelog(group, logtxt) - -local text = (os.date("[ %c ]=> "..logtxt.."\n \n")) -local file = io.open("./groups/logs/"..group.."log.txt", "a") - -file:write(text) - -file:close() - -end - -function user_print_name(user) - if user.print_name then - return user.print_name - end - local text = '' - if user.first_name then - text = user.last_name..' ' - end - if user.lastname then - text = text..user.last_name - end - return text -end - ---Check if user is the owner of that group or not -function is_owner(msg) - local var = false - local data = load_data(_config.moderation.data) - local user = msg.from.id - - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['set_owner'] then - if data[tostring(msg.to.id)]['set_owner'] == tostring(user) then - var = true - end - end - end - - if data['admins'] then - if data['admins'][tostring(user)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == msg.from.id then - var = true - end - end - return var -end - -function is_owner2(user_id, group_id) - local var = false - local data = load_data(_config.moderation.data) - - if data[tostring(group_id)] then - if data[tostring(group_id)]['set_owner'] then - if data[tostring(group_id)]['set_owner'] == tostring(user_id) then - var = true - end - end - end - - if data['admins'] then - if data['admins'][tostring(user_id)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == user_id then - var = true - end - end - return var -end - ---Check if user is admin or not -function is_admin(msg) - local var = false - local data = load_data(_config.moderation.data) - local user = msg.from.id - local admins = 'admins' - if data[tostring(admins)] then - if data[tostring(admins)][tostring(user)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == msg.from.id then - var = true - end - end - return var -end - -function is_admin2(user_id) - local var = false - local data = load_data(_config.moderation.data) - local user = user_id - local admins = 'admins' - if data[tostring(admins)] then - if data[tostring(admins)][tostring(user)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == user_id then - var = true - end - end - return var -end - - - ---Check if user is the mod of that group or not -function is_momod(msg) - local var = false - local data = load_data(_config.moderation.data) - local user = msg.from.id - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['moderators'] then - if data[tostring(msg.to.id)]['moderators'][tostring(user)] then - var = true - end - end - end - - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['set_owner'] then - if data[tostring(msg.to.id)]['set_owner'] == tostring(user) then - var = true - end - end - end - - if data['admins'] then - if data['admins'][tostring(user)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == msg.from.id then - var = true - end - end - return var -end - -function is_momod2(user_id, group_id) - local var = false - local data = load_data(_config.moderation.data) - local usert = user_id - if data[tostring(group_id)] then - if data[tostring(group_id)]['moderators'] then - if data[tostring(group_id)]['moderators'][tostring(usert)] then - var = true - end - end - end - - if data[tostring(group_id)] then - if data[tostring(group_id)]['set_owner'] then - if data[tostring(group_id)]['set_owner'] == tostring(user_id) then - var = true - end - end - end - - if data['admins'] then - if data['admins'][tostring(user_id)] then - var = true - end - end - for v,user in pairs(_config.sudo_users) do - if user == usert then - var = true - end - end - return var -end - --- Returns the name of the sender -function kick_user(user_id, chat_id) - if tonumber(user_id) == tonumber(our_id) then -- Ignore bot - return - end - if is_owner2(user_id, chat_id) then -- Ignore admins - return - end - local chat = 'chat#id'..chat_id - local user = 'user#id'..user_id - chat_del_user(chat, user, ok_cb, true) -end - --- Ban -function ban_user(user_id, chat_id) - if tonumber(user_id) == tonumber(our_id) then -- Ignore bot - return - end - if is_admin2(user_id) then -- Ignore admins - return - end - -- Save to redis - local hash = 'banned:'..chat_id - redis:sadd(hash, user_id) - -- Kick from chat - kick_user(user_id, chat_id) -end --- Global ban -function banall_user(user_id) - if tonumber(user_id) == tonumber(our_id) then -- Ignore bot - return - end - if is_admin2(user_id) then -- Ignore admins - return - end - -- Save to redis - local hash = 'gbanned' - redis:sadd(hash, user_id) -end --- Global unban -function unbanall_user(user_id) - --Save on redis - local hash = 'gbanned' - redis:srem(hash, user_id) -end - --- Check if user_id is banned in chat_id or not -function is_banned(user_id, chat_id) - --Save on redis - local hash = 'banned:'..chat_id - local banned = redis:sismember(hash, user_id) - return banned or false -end - --- Check if user_id is globally banned or not -function is_gbanned(user_id) - --Save on redis - local hash = 'gbanned' - local banned = redis:sismember(hash, user_id) - return banned or false -end - --- Returns chat_id ban list -function ban_list(chat_id) - local hash = 'banned:'..chat_id - local list = redis:smembers(hash) - local text = "Ban list !\n\n" - for k,v in pairs(list) do - local user_info = redis:hgetall('user:'..v) --- vardump(user_info) - if user_info then - if user_info.username then - user = '@'..user_info.username - elseif user_info.print_name and not user_info.username then - user = string.gsub(user_info.print_name, "_", " ") - else - user = '' - end - text = text..k.." - "..user.." ["..v.."]\n" - end - end - return text -end - --- Returns globally ban list -function banall_list() - local hash = 'gbanned' - local list = redis:smembers(hash) - local text = "global bans !\n\n" - for k,v in pairs(list) do - local user_info = redis:hgetall('user:'..v) --- vardump(user_info) - if user_info then - if user_info.username then - user = '@'..user_info.username - elseif user_info.print_name and not user_info.username then - user = string.gsub(user_info.print_name, "_", " ") - else - user = '' - end - text = text..k.." - "..user.." ["..v.."]\n" - end - end - return text -end - --- /id by reply -function get_message_callback_id(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - send_large_msg(chat, result.from.id) - else - return 'Use This in Your Groups' - end -end - --- kick by reply for mods and owner -function Kick_by_reply(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't kick myself" - end - if is_momod2(result.from.id, result.to.id) then -- Ignore mods,owner,admin - return "you can't kick mods,owner and admins" - end - chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false) - else - return 'Use This in Your Groups' - end -end - --- Kick by reply for admins -function Kick_by_reply_admins(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't kick myself" - end - if is_admin2(result.from.id) then -- Ignore admins - return - end - chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false) - else - return 'Use This in Your Groups' - end -end - ---Ban by reply for admins -function ban_by_reply(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't ban myself" - end - if is_momod2(result.from.id, result.to.id) then -- Ignore mods,owner,admin - return "you can't kick mods,owner and admins" - end - ban_user(result.from.id, result.to.id) - send_large_msg(chat, "User "..result.from.id.." Banned") - else - return 'Use This in Your Groups' - end -end - --- Ban by reply for admins -function ban_by_reply_admins(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't ban myself" - end - if is_admin2(result.from.id) then -- Ignore admins - return - end - ban_user(result.from.id, result.to.id) - send_large_msg(chat, "User "..result.from.id.." Banned") - else - return 'Use This in Your Groups' - end -end - --- Unban by reply -function unban_by_reply(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't unban myself" - end - send_large_msg(chat, "User "..result.from.id.." Unbanned") - -- Save on redis - local hash = 'banned:'..result.to.id - redis:srem(hash, result.from.id) - else - return 'Use This in Your Groups' - end -end -function banall_by_reply(extra, success, result) - if result.to.type == 'chat' then - local chat = 'chat#id'..result.to.id - if tonumber(result.from.id) == tonumber(our_id) then -- Ignore bot - return "I won't banall myself" - end - if is_admin2(result.from.id) then -- Ignore admins - return - end - local name = user_print_name(result.from) - banall_user(result.from.id) - chat_del_user(chat, 'user#id'..result.from.id, ok_cb, false) - send_large_msg(chat, "User "..name.."["..result.from.id.."] hammered") - else - return 'Use This in Your Groups' - end -end diff --git a/data/.gitkeep b/data/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/data/photos/.gitkeep b/data/photos/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/groups/all/[group_id]all.txt b/groups/all/[group_id]all.txt deleted file mode 100644 index f5531c1..0000000 --- a/groups/all/[group_id]all.txt +++ /dev/null @@ -1 +0,0 @@ -[group_id] logs ! diff --git a/groups/lists/[group_id]memberlist.txt b/groups/lists/[group_id]memberlist.txt deleted file mode 100644 index a13454d..0000000 --- a/groups/lists/[group_id]memberlist.txt +++ /dev/null @@ -1 +0,0 @@ -[group_id] memeberlist ! diff --git a/groups/logs/[group_id]log.txt b/groups/logs/[group_id]log.txt deleted file mode 100644 index f5531c1..0000000 --- a/groups/logs/[group_id]log.txt +++ /dev/null @@ -1 +0,0 @@ -[group_id] logs ! diff --git a/groups/logs/[group_id]stats.txt b/groups/logs/[group_id]stats.txt deleted file mode 100644 index 56448df..0000000 --- a/groups/logs/[group_id]stats.txt +++ /dev/null @@ -1 +0,0 @@ -[group_id] stats ! diff --git a/launch.sh b/launch.sh deleted file mode 100755 index b5b74dd..0000000 --- a/launch.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env bash - -THIS_DIR=$(cd $(dirname $0); pwd) -cd $THIS_DIR - -update() { - git pull - git submodule update --init --recursive - install_rocks -} - -# Will install luarocks on THIS_DIR/.luarocks -install_luarocks() { - git clone https://github.com/keplerproject/luarocks.git - cd luarocks - git checkout tags/v2.2.1 # Current stable - - PREFIX="$THIS_DIR/.luarocks" - - ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config - - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - make build && make install - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting.";exit $RET; - fi - - cd .. - rm -rf luarocks -} - -install_rocks() { - ./.luarocks/bin/luarocks install luasocket - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install oauth - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install redis-lua - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install lua-cjson - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install fakeredis - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install xml - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install feedparser - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install serpent - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi -} - -install() { - git pull - git submodule update --init --recursive - patch -i "patches/disable-python-and-libjansson.patch" -p 0 --batch --forward - RET=$?; - - cd tg - if [ $RET -ne 0 ]; then - autoconf -i - fi - ./configure && make - - RET=$?; if [ $RET -ne 0 ]; then - echo "Error. Exiting."; exit $RET; - fi - cd .. - install_luarocks - install_rocks -} - -if [ "$1" = "install" ]; then - install -elif [ "$1" = "update" ]; then - update -else - if [ ! -f ./tg/telegram.h ]; then - echo "tg not found" - echo "Run $0 install" - exit 1 - fi - - if [ ! -f ./tg/bin/telegram-cli ]; then - echo "tg binary not found" - echo "Run $0 install" - exit 1 - fi - - ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/seedbot.lua -l 1 -E $@ -fi \ No newline at end of file diff --git a/libs/JSON.lua b/libs/JSON.lua deleted file mode 100644 index 5f11425..0000000 --- a/libs/JSON.lua +++ /dev/null @@ -1,1053 +0,0 @@ --- -*- coding: utf-8 -*- --- --- Simple JSON encoding and decoding in pure Lua. --- --- Copyright 2010-2014 Jeffrey Friedl --- http://regex.info/blog/ --- --- Latest version: http://regex.info/blog/lua/json --- --- This code is released under a Creative Commons CC-BY "Attribution" License: --- http://creativecommons.org/licenses/by/3.0/deed.en_US --- --- It can be used for any purpose so long as the copyright notice above, --- the web-page links above, and the 'AUTHOR_NOTE' string below are --- maintained. Enjoy. --- -local VERSION = 20141223.14 -- version history at end of file -local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20141223.14 ]-" - --- --- The 'AUTHOR_NOTE' variable exists so that information about the source --- of the package is maintained even in compiled versions. It's also --- included in OBJDEF below mostly to quiet warnings about unused variables. --- -local OBJDEF = { - VERSION = VERSION, - AUTHOR_NOTE = AUTHOR_NOTE, -} - - --- --- Simple JSON encoding and decoding in pure Lua. --- http://www.json.org/ --- --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local lua_value = JSON:decode(raw_json_text) --- --- local raw_json_text = JSON:encode(lua_table_or_value) --- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability --- --- --- --- DECODING (from a JSON string to a Lua table) --- --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local lua_value = JSON:decode(raw_json_text) --- --- If the JSON text is for an object or an array, e.g. --- { "what": "books", "count": 3 } --- or --- [ "Larry", "Curly", "Moe" ] --- --- the result is a Lua table, e.g. --- { what = "books", count = 3 } --- or --- { "Larry", "Curly", "Moe" } --- --- --- The encode and decode routines accept an optional second argument, --- "etc", which is not used during encoding or decoding, but upon error --- is passed along to error handlers. It can be of any type (including nil). --- --- --- --- ERROR HANDLING --- --- With most errors during decoding, this code calls --- --- JSON:onDecodeError(message, text, location, etc) --- --- with a message about the error, and if known, the JSON text being --- parsed and the byte count where the problem was discovered. You can --- replace the default JSON:onDecodeError() with your own function. --- --- The default onDecodeError() merely augments the message with data --- about the text and the location if known (and if a second 'etc' --- argument had been provided to decode(), its value is tacked onto the --- message as well), and then calls JSON.assert(), which itself defaults --- to Lua's built-in assert(), and can also be overridden. --- --- For example, in an Adobe Lightroom plugin, you might use something like --- --- function JSON:onDecodeError(message, text, location, etc) --- LrErrors.throwUserError("Internal Error: invalid JSON data") --- end --- --- or even just --- --- function JSON.assert(message) --- LrErrors.throwUserError("Internal Error: " .. message) --- end --- --- If JSON:decode() is passed a nil, this is called instead: --- --- JSON:onDecodeOfNilError(message, nil, nil, etc) --- --- and if JSON:decode() is passed HTML instead of JSON, this is called: --- --- JSON:onDecodeOfHTMLError(message, text, nil, etc) --- --- The use of the fourth 'etc' argument allows stronger coordination --- between decoding and error reporting, especially when you provide your --- own error-handling routines. Continuing with the the Adobe Lightroom --- plugin example: --- --- function JSON:onDecodeError(message, text, location, etc) --- local note = "Internal Error: invalid JSON data" --- if type(etc) = 'table' and etc.photo then --- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName') --- end --- LrErrors.throwUserError(note) --- end --- --- : --- : --- --- for i, photo in ipairs(photosToProcess) do --- : --- : --- local data = JSON:decode(someJsonText, { photo = photo }) --- : --- : --- end --- --- --- --- --- --- DECODING AND STRICT TYPES --- --- Because both JSON objects and JSON arrays are converted to Lua tables, --- it's not normally possible to tell which original JSON type a --- particular Lua table was derived from, or guarantee decode-encode --- round-trip equivalency. --- --- However, if you enable strictTypes, e.g. --- --- JSON = assert(loadfile "JSON.lua")() --load the routines --- JSON.strictTypes = true --- --- then the Lua table resulting from the decoding of a JSON object or --- JSON array is marked via Lua metatable, so that when re-encoded with --- JSON:encode() it ends up as the appropriate JSON type. --- --- (This is not the default because other routines may not work well with --- tables that have a metatable set, for example, Lightroom API calls.) --- --- --- ENCODING (from a lua table to a JSON string) --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local raw_json_text = JSON:encode(lua_table_or_value) --- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability --- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false }) --- --- On error during encoding, this code calls: --- --- JSON:onEncodeError(message, etc) --- --- which you can override in your local JSON object. --- --- The 'etc' in the error call is the second argument to encode() --- and encode_pretty(), or nil if it wasn't provided. --- --- --- PRETTY-PRINTING --- --- An optional third argument, a table of options, allows a bit of --- configuration about how the encoding takes place: --- --- pretty = JSON:encode(val, etc, { --- pretty = true, -- if false, no other options matter --- indent = " ", -- this provides for a three-space indent per nesting level --- align_keys = false, -- see below --- }) --- --- encode() and encode_pretty() are identical except that encode_pretty() --- provides a default options table if none given in the call: --- --- { pretty = true, align_keys = false, indent = " " } --- --- For example, if --- --- JSON:encode(data) --- --- produces: --- --- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11} --- --- then --- --- JSON:encode_pretty(data) --- --- produces: --- --- { --- "city": "Kyoto", --- "climate": { --- "avg_temp": 16, --- "humidity": "high", --- "snowfall": "minimal" --- }, --- "country": "Japan", --- "wards": 11 --- } --- --- The following three lines return identical results: --- JSON:encode_pretty(data) --- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " }) --- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " }) --- --- An example of setting your own indent string: --- --- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " }) --- --- produces: --- --- { --- | "city": "Kyoto", --- | "climate": { --- | | "avg_temp": 16, --- | | "humidity": "high", --- | | "snowfall": "minimal" --- | }, --- | "country": "Japan", --- | "wards": 11 --- } --- --- An example of setting align_keys to true: --- --- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true }) --- --- produces: --- --- { --- "city": "Kyoto", --- "climate": { --- "avg_temp": 16, --- "humidity": "high", --- "snowfall": "minimal" --- }, --- "country": "Japan", --- "wards": 11 --- } --- --- which I must admit is kinda ugly, sorry. This was the default for --- encode_pretty() prior to version 20141223.14. --- --- --- AMBIGUOUS SITUATIONS DURING THE ENCODING --- --- During the encode, if a Lua table being encoded contains both string --- and numeric keys, it fits neither JSON's idea of an object, nor its --- idea of an array. To get around this, when any string key exists (or --- when non-positive numeric keys exist), numeric keys are converted to --- strings. --- --- For example, --- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) --- produces the JSON object --- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} --- --- To prohibit this conversion and instead make it an error condition, set --- JSON.noKeyConversion = true --- - - - - --- --- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT --- --- assert --- onDecodeError --- onDecodeOfNilError --- onDecodeOfHTMLError --- onEncodeError --- --- If you want to create a separate Lua JSON object with its own error handlers, --- you can reload JSON.lua or use the :new() method. --- ---------------------------------------------------------------------------- - -local default_pretty_indent = " " -local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent } - -local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray -local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject - - -function OBJDEF:newArray(tbl) - return setmetatable(tbl or {}, isArray) -end - -function OBJDEF:newObject(tbl) - return setmetatable(tbl or {}, isObject) -end - -local function unicode_codepoint_as_utf8(codepoint) - -- - -- codepoint is a number - -- - if codepoint <= 127 then - return string.char(codepoint) - - elseif codepoint <= 2047 then - -- - -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8 - -- - local highpart = math.floor(codepoint / 0x40) - local lowpart = codepoint - (0x40 * highpart) - return string.char(0xC0 + highpart, - 0x80 + lowpart) - - elseif codepoint <= 65535 then - -- - -- 1110yyyy 10yyyyxx 10xxxxxx - -- - local highpart = math.floor(codepoint / 0x1000) - local remainder = codepoint - 0x1000 * highpart - local midpart = math.floor(remainder / 0x40) - local lowpart = remainder - 0x40 * midpart - - highpart = 0xE0 + highpart - midpart = 0x80 + midpart - lowpart = 0x80 + lowpart - - -- - -- Check for an invalid character (thanks Andy R. at Adobe). - -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070 - -- - if ( highpart == 0xE0 and midpart < 0xA0 ) or - ( highpart == 0xED and midpart > 0x9F ) or - ( highpart == 0xF0 and midpart < 0x90 ) or - ( highpart == 0xF4 and midpart > 0x8F ) - then - return "?" - else - return string.char(highpart, - midpart, - lowpart) - end - - else - -- - -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx - -- - local highpart = math.floor(codepoint / 0x40000) - local remainder = codepoint - 0x40000 * highpart - local midA = math.floor(remainder / 0x1000) - remainder = remainder - 0x1000 * midA - local midB = math.floor(remainder / 0x40) - local lowpart = remainder - 0x40 * midB - - return string.char(0xF0 + highpart, - 0x80 + midA, - 0x80 + midB, - 0x80 + lowpart) - end -end - -function OBJDEF:onDecodeError(message, text, location, etc) - if text then - if location then - message = string.format("%s at char %d of: %s", message, location, text) - else - message = string.format("%s: %s", message, text) - end - end - - if etc ~= nil then - message = message .. " (" .. OBJDEF:encode(etc) .. ")" - end - - if self.assert then - self.assert(false, message) - else - assert(false, message) - end -end - -OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError -OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError - -function OBJDEF:onEncodeError(message, etc) - if etc ~= nil then - message = message .. " (" .. OBJDEF:encode(etc) .. ")" - end - - if self.assert then - self.assert(false, message) - else - assert(false, message) - end -end - -local function grok_number(self, text, start, etc) - -- - -- Grab the integer part - -- - local integer_part = text:match('^-?[1-9]%d*', start) - or text:match("^-?0", start) - - if not integer_part then - self:onDecodeError("expected number", text, start, etc) - end - - local i = start + integer_part:len() - - -- - -- Grab an optional decimal part - -- - local decimal_part = text:match('^%.%d+', i) or "" - - i = i + decimal_part:len() - - -- - -- Grab an optional exponential part - -- - local exponent_part = text:match('^[eE][-+]?%d+', i) or "" - - i = i + exponent_part:len() - - local full_number_text = integer_part .. decimal_part .. exponent_part - local as_number = tonumber(full_number_text) - - if not as_number then - self:onDecodeError("bad number", text, start, etc) - end - - return as_number, i -end - - -local function grok_string(self, text, start, etc) - - if text:sub(start,start) ~= '"' then - self:onDecodeError("expected string's opening quote", text, start, etc) - end - - local i = start + 1 -- +1 to bypass the initial quote - local text_len = text:len() - local VALUE = "" - while i <= text_len do - local c = text:sub(i,i) - if c == '"' then - return VALUE, i + 1 - end - if c ~= '\\' then - VALUE = VALUE .. c - i = i + 1 - elseif text:match('^\\b', i) then - VALUE = VALUE .. "\b" - i = i + 2 - elseif text:match('^\\f', i) then - VALUE = VALUE .. "\f" - i = i + 2 - elseif text:match('^\\n', i) then - VALUE = VALUE .. "\n" - i = i + 2 - elseif text:match('^\\r', i) then - VALUE = VALUE .. "\r" - i = i + 2 - elseif text:match('^\\t', i) then - VALUE = VALUE .. "\t" - i = i + 2 - else - local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) - if hex then - i = i + 6 -- bypass what we just read - - -- We have a Unicode codepoint. It could be standalone, or if in the proper range and - -- followed by another in a specific range, it'll be a two-code surrogate pair. - local codepoint = tonumber(hex, 16) - if codepoint >= 0xD800 and codepoint <= 0xDBFF then - -- it's a hi surrogate... see whether we have a following low - local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) - if lo_surrogate then - i = i + 6 -- bypass the low surrogate we just read - codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16) - else - -- not a proper low, so we'll just leave the first codepoint as is and spit it out. - end - end - VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint) - - else - - -- just pass through what's escaped - VALUE = VALUE .. text:match('^\\(.)', i) - i = i + 2 - end - end - end - - self:onDecodeError("unclosed string", text, start, etc) -end - -local function skip_whitespace(text, start) - - local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2 - if match_end then - return match_end + 1 - else - return start - end -end - -local grok_one -- assigned later - -local function grok_object(self, text, start, etc) - if text:sub(start,start) ~= '{' then - self:onDecodeError("expected '{'", text, start, etc) - end - - local i = skip_whitespace(text, start + 1) -- +1 to skip the '{' - - local VALUE = self.strictTypes and self:newObject { } or { } - - if text:sub(i,i) == '}' then - return VALUE, i + 1 - end - local text_len = text:len() - while i <= text_len do - local key, new_i = grok_string(self, text, i, etc) - - i = skip_whitespace(text, new_i) - - if text:sub(i, i) ~= ':' then - self:onDecodeError("expected colon", text, i, etc) - end - - i = skip_whitespace(text, i + 1) - - local new_val, new_i = grok_one(self, text, i) - - VALUE[key] = new_val - - -- - -- Expect now either '}' to end things, or a ',' to allow us to continue. - -- - i = skip_whitespace(text, new_i) - - local c = text:sub(i,i) - - if c == '}' then - return VALUE, i + 1 - end - - if text:sub(i, i) ~= ',' then - self:onDecodeError("expected comma or '}'", text, i, etc) - end - - i = skip_whitespace(text, i + 1) - end - - self:onDecodeError("unclosed '{'", text, start, etc) -end - -local function grok_array(self, text, start, etc) - if text:sub(start,start) ~= '[' then - self:onDecodeError("expected '['", text, start, etc) - end - - local i = skip_whitespace(text, start + 1) -- +1 to skip the '[' - local VALUE = self.strictTypes and self:newArray { } or { } - if text:sub(i,i) == ']' then - return VALUE, i + 1 - end - - local VALUE_INDEX = 1 - - local text_len = text:len() - while i <= text_len do - local val, new_i = grok_one(self, text, i) - - -- can't table.insert(VALUE, val) here because it's a no-op if val is nil - VALUE[VALUE_INDEX] = val - VALUE_INDEX = VALUE_INDEX + 1 - - i = skip_whitespace(text, new_i) - - -- - -- Expect now either ']' to end things, or a ',' to allow us to continue. - -- - local c = text:sub(i,i) - if c == ']' then - return VALUE, i + 1 - end - if text:sub(i, i) ~= ',' then - self:onDecodeError("expected comma or '['", text, i, etc) - end - i = skip_whitespace(text, i + 1) - end - self:onDecodeError("unclosed '['", text, start, etc) -end - - -grok_one = function(self, text, start, etc) - -- Skip any whitespace - start = skip_whitespace(text, start) - - if start > text:len() then - self:onDecodeError("unexpected end of string", text, nil, etc) - end - - if text:find('^"', start) then - return grok_string(self, text, start, etc) - - elseif text:find('^[-0123456789 ]', start) then - return grok_number(self, text, start, etc) - - elseif text:find('^%{', start) then - return grok_object(self, text, start, etc) - - elseif text:find('^%[', start) then - return grok_array(self, text, start, etc) - - elseif text:find('^true', start) then - return true, start + 4 - - elseif text:find('^false', start) then - return false, start + 5 - - elseif text:find('^null', start) then - return nil, start + 4 - - else - self:onDecodeError("can't parse JSON", text, start, etc) - end -end - -function OBJDEF:decode(text, etc) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc) - end - - if text == nil then - self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc) - elseif type(text) ~= 'string' then - self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc) - end - - if text:match('^%s*$') then - return nil - end - - if text:match('^%s*<') then - -- Can't be JSON... we'll assume it's HTML - self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc) - end - - -- - -- Ensure that it's not UTF-32 or UTF-16. - -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3), - -- but this package can't handle them. - -- - if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then - self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc) - end - - local success, value = pcall(grok_one, self, text, 1, etc) - - if success then - return value - else - -- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert. - if self.assert then - self.assert(false, value) - else - assert(false, value) - end - -- and if we're still here, return a nil and throw the error message on as a second arg - return nil, value - end -end - -local function backslash_replacement_function(c) - if c == "\n" then - return "\\n" - elseif c == "\r" then - return "\\r" - elseif c == "\t" then - return "\\t" - elseif c == "\b" then - return "\\b" - elseif c == "\f" then - return "\\f" - elseif c == '"' then - return '\\"' - elseif c == '\\' then - return '\\\\' - else - return string.format("\\u%04x", c:byte()) - end -end - -local chars_to_be_escaped_in_JSON_string - = '[' - .. '"' -- class sub-pattern to match a double quote - .. '%\\' -- class sub-pattern to match a backslash - .. '%z' -- class sub-pattern to match a null - .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters - .. ']' - -local function json_string_literal(value) - local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function) - return '"' .. newval .. '"' -end - -local function object_or_array(self, T, etc) - -- - -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON - -- object. If there are only numbers, it's a JSON array. - -- - -- If we'll be converting to a JSON object, we'll want to sort the keys so that the - -- end result is deterministic. - -- - local string_keys = { } - local number_keys = { } - local number_keys_must_be_strings = false - local maximum_number_key - - for key in pairs(T) do - if type(key) == 'string' then - table.insert(string_keys, key) - elseif type(key) == 'number' then - table.insert(number_keys, key) - if key <= 0 or key >= math.huge then - number_keys_must_be_strings = true - elseif not maximum_number_key or key > maximum_number_key then - maximum_number_key = key - end - else - self:onEncodeError("can't encode table with a key of type " .. type(key), etc) - end - end - - if #string_keys == 0 and not number_keys_must_be_strings then - -- - -- An empty table, or a numeric-only array - -- - if #number_keys > 0 then - return nil, maximum_number_key -- an array - elseif tostring(T) == "JSON array" then - return nil - elseif tostring(T) == "JSON object" then - return { } - else - -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects - return nil - end - end - - table.sort(string_keys) - - local map - if #number_keys > 0 then - -- - -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array - -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object. - -- - - if self.noKeyConversion then - self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc) - end - - -- - -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings - -- - map = { } - for key, val in pairs(T) do - map[key] = val - end - - table.sort(number_keys) - - -- - -- Throw numeric keys in there as strings - -- - for _, number_key in ipairs(number_keys) do - local string_key = tostring(number_key) - if map[string_key] == nil then - table.insert(string_keys , string_key) - map[string_key] = T[number_key] - else - self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc) - end - end - end - - return string_keys, nil, map -end - --- --- Encode --- --- 'options' is nil, or a table with possible keys: --- pretty -- if true, return a pretty-printed version --- indent -- a string (usually of spaces) used to indent each nested level --- align_keys -- if true, align all the keys when formatting a table --- -local encode_value -- must predeclare because it calls itself -function encode_value(self, value, parents, etc, options, indent) - - if value == nil then - return 'null' - - elseif type(value) == 'string' then - return json_string_literal(value) - - elseif type(value) == 'number' then - if value ~= value then - -- - -- NaN (Not a Number). - -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option. - -- - return "null" - elseif value >= math.huge then - -- - -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should - -- really be a package option. Note: at least with some implementations, positive infinity - -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is. - -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">=" - -- case first. - -- - return "1e+9999" - elseif value <= -math.huge then - -- - -- Negative infinity. - -- JSON has no INF, so we have to fudge the best we can. This should really be a package option. - -- - return "-1e+9999" - else - return tostring(value) - end - - elseif type(value) == 'boolean' then - return tostring(value) - - elseif type(value) ~= 'table' then - self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc) - - else - -- - -- A table to be converted to either a JSON object or array. - -- - local T = value - - if type(options) ~= 'table' then - options = {} - end - if type(indent) ~= 'string' then - indent = "" - end - - if parents[T] then - self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc) - else - parents[T] = true - end - - local result_value - - local object_keys, maximum_number_key, map = object_or_array(self, T, etc) - if maximum_number_key then - -- - -- An array... - -- - local ITEMS = { } - for i = 1, maximum_number_key do - table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent)) - end - - if options.pretty then - result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]" - else - result_value = "[" .. table.concat(ITEMS, ",") .. "]" - end - - elseif object_keys then - -- - -- An object - -- - local TT = map or T - - if options.pretty then - - local KEYS = { } - local max_key_length = 0 - for _, key in ipairs(object_keys) do - local encoded = encode_value(self, tostring(key), parents, etc, options, indent) - if options.align_keys then - max_key_length = math.max(max_key_length, #encoded) - end - table.insert(KEYS, encoded) - end - local key_indent = indent .. tostring(options.indent or "") - local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "") - local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s" - - local COMBINED_PARTS = { } - for i, key in ipairs(object_keys) do - local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent) - table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val)) - end - result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}" - - else - - local PARTS = { } - for _, key in ipairs(object_keys) do - local encoded_val = encode_value(self, TT[key], parents, etc, options, indent) - local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent) - table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val)) - end - result_value = "{" .. table.concat(PARTS, ",") .. "}" - - end - else - -- - -- An empty array/object... we'll treat it as an array, though it should really be an option - -- - result_value = "[]" - end - - parents[T] = false - return result_value - end -end - - -function OBJDEF:encode(value, etc, options) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onEncodeError("JSON:encode must be called in method format", etc) - end - return encode_value(self, value, {}, etc, options or nil) -end - -function OBJDEF:encode_pretty(value, etc, options) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc) - end - return encode_value(self, value, {}, etc, options or default_pretty_options) -end - -function OBJDEF.__tostring() - return "JSON encode/decode package" -end - -OBJDEF.__index = OBJDEF - -function OBJDEF:new(args) - local new = { } - - if args then - for key, val in pairs(args) do - new[key] = val - end - end - - return setmetatable(new, OBJDEF) -end - -return OBJDEF:new() - --- --- Version history: --- --- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really --- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines --- more flexible, and changed the default encode_pretty() to be more generally useful. --- --- Added a third 'options' argument to the encode() and encode_pretty() routines, to control --- how the encoding takes place. --- --- Updated docs to add assert() call to the loadfile() line, just as good practice so that --- if there is a problem loading JSON.lua, the appropriate error message will percolate up. --- --- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string, --- so that the source of the package, and its version number, are visible in compiled copies. --- --- 20140911.12 Minor lua cleanup. --- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'. --- (Thanks to SmugMug's David Parry for these.) --- --- 20140418.11 JSON nulls embedded within an array were being ignored, such that --- ["1",null,null,null,null,null,"seven"], --- would return --- {1,"seven"} --- It's now fixed to properly return --- {1, nil, nil, nil, nil, nil, "seven"} --- Thanks to "haddock" for catching the error. --- --- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up. --- --- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2", --- and this caused some problems. --- --- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate, --- and had of course diverged (encode_pretty didn't get the fixes that encode got, so --- sometimes produced incorrect results; thanks to Mattie for the heads up). --- --- Handle encoding tables with non-positive numeric keys (unlikely, but possible). --- --- If a table has both numeric and string keys, or its numeric keys are inappropriate --- (such as being non-positive or infinite), the numeric keys are turned into --- string keys appropriate for a JSON object. So, as before, --- JSON:encode({ "one", "two", "three" }) --- produces the array --- ["one","two","three"] --- but now something with mixed key types like --- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) --- instead of throwing an error produces an object: --- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} --- --- To maintain the prior throw-an-error semantics, set --- JSON.noKeyConversion = true --- --- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry. --- --- 20130120.6 Comment update: added a link to the specific page on my blog where this code can --- be found, so that folks who come across the code outside of my blog can find updates --- more easily. --- --- 20111207.5 Added support for the 'etc' arguments, for better error reporting. --- --- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent. --- --- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules: --- --- * When encoding lua for JSON, Sparse numeric arrays are now handled by --- spitting out full arrays, such that --- JSON:encode({"one", "two", [10] = "ten"}) --- returns --- ["one","two",null,null,null,null,null,null,null,"ten"] --- --- In 20100810.2 and earlier, only up to the first non-null value would have been retained. --- --- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999". --- Version 20100810.2 and earlier created invalid JSON in both cases. --- --- * Unicode surrogate pairs are now detected when decoding JSON. --- --- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding --- --- 20100731.1 initial public release --- diff --git a/libs/dkjson.lua b/libs/dkjson.lua deleted file mode 100644 index 8b3f37d..0000000 --- a/libs/dkjson.lua +++ /dev/null @@ -1,809 +0,0 @@ - -- Module options: - local always_try_using_lpeg = true - local register_global_module_table = false - local global_module_name = 'json' - - --[==[ - -David Kolf's JSON module for Lua 5.1/5.2 -======================================== -*Version 2.4* -In the default configuration this module writes no global values, not even -the module table. Import it using - json = require ("dkjson") -In environments where `require` or a similiar function are not available -and you cannot receive the return value of the module, you can set the -option `register_global_module_table` to `true`. The module table will -then be saved in the global variable with the name given by the option -`global_module_name`. -Exported functions and values: -`json.encode (object [, state])` --------------------------------- -Create a string representing the object. `Object` can be a table, -a string, a number, a boolean, `nil`, `json.null` or any object with -a function `__tojson` in its metatable. A table can only use strings -and numbers as keys and its values have to be valid objects as -well. It raises an error for any invalid data types or reference -cycles. -`state` is an optional table with the following fields: - - `indent` - When `indent` (a boolean) is set, the created string will contain - newlines and indentations. Otherwise it will be one long line. - - `keyorder` - `keyorder` is an array to specify the ordering of keys in the - encoded output. If an object has keys which are not in this array - they are written after the sorted keys. - - `level` - This is the initial level of indentation used when `indent` is - set. For each level two spaces are added. When absent it is set - to 0. - - `buffer` - `buffer` is an array to store the strings for the result so they - can be concatenated at once. When it isn't given, the encode - function will create it temporary and will return the - concatenated result. - - `bufferlen` - When `bufferlen` is set, it has to be the index of the last - element of `buffer`. - - `tables` - `tables` is a set to detect reference cycles. It is created - temporary when absent. Every table that is currently processed - is used as key, the value is `true`. - -When `state.buffer` was set, the return value will be `true` on -success. Without `state.buffer` the return value will be a string. - -`json.decode (string [, position [, null]])` --------------------------------------------- - -Decode `string` starting at `position` or at 1 if `position` was -omitted. - -`null` is an optional value to be returned for null values. The -default is `nil`, but you could set it to `json.null` or any other -value. - -The return values are the object or `nil`, the position of the next -character that doesn't belong to the object, and in case of errors -an error message. -Two metatables are created. Every array or object that is decoded gets -a metatable with the `__jsontype` field set to either `array` or -`object`. If you want to provide your own metatables use the syntax - json.decode (string, position, null, objectmeta, arraymeta) -To prevent the assigning of metatables pass `nil`: - json.decode (string, position, null, nil) -`.__jsonorder` -------------------------- -`__jsonorder` can overwrite the `keyorder` for a specific table. -`.__jsontype` ------------------------- -`__jsontype` can be either `"array"` or `"object"`. This value is only -checked for empty tables. (The default for empty tables is `"array"`). -`.__tojson (self, state)` ------------------------------------- -You can provide your own `__tojson` function in a metatable. In this -function you can either add directly to the buffer and return true, -or you can return a string. On errors nil and a message should be -returned. -`json.null` ------------ -You can use this value for setting explicit `null` values. -`json.version` --------------- -Set to `"dkjson 2.4"`. -`json.quotestring (string)` ---------------------------- -Quote a UTF-8 string and escape critical characters using JSON -escape sequences. This function is only necessary when you build -your own `__tojson` functions. -`json.addnewline (state)` -------------------------- -When `state.indent` is set, add a newline to `state.buffer` and spaces -according to `state.level`. -LPeg support ------------- -When the local configuration variable `always_try_using_lpeg` is set, -this module tries to load LPeg to replace the `decode` function. The -speed increase is significant. You can get the LPeg module at - . -When LPeg couldn't be loaded, the pure Lua functions stay active. - -In case you don't want this module to require LPeg on its own, -disable the option `always_try_using_lpeg` in the options section at -the top of the module. -In this case you can later load LPeg support using -### `json.use_lpeg ()` -Require the LPeg module and replace the functions `quotestring` and -and `decode` with functions that use LPeg patterns. -This function returns the module table, so you can load the module -using: - json = require "dkjson".use_lpeg() -Alternatively you can use `pcall` so the JSON module still works when -LPeg isn't found. - - json = require "dkjson" - pcall (json.use_lpeg) - -### `json.using_lpeg` - -This variable is set to `true` when LPeg was loaded successfully. - ---------------------------------------------------------------------- - -Contact -------- - -You can contact the author by sending an e-mail to 'david' at the -domain 'dkolf.de'. - ---------------------------------------------------------------------- - -*Copyright (C) 2010-2013 David Heiko Kolf* - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - - \ No newline at end of file diff --git a/libs/mimetype.lua b/libs/mimetype.lua deleted file mode 100644 index 4ff6c29..0000000 --- a/libs/mimetype.lua +++ /dev/null @@ -1,101 +0,0 @@ --- Thanks to https://github.com/catwell/lua-toolbox/blob/master/mime.types -do - -local mimetype = {} - --- TODO: Add more? -local types = { - ["text/html"] = "html", - ["text/css"] = "css", - ["text/xml"] = "xml", - ["image/gif"] = "gif", - ["image/jpeg"] = "jpg", - ["application/x-javascript"] = "js", - ["application/atom+xml"] = "atom", - ["application/rss+xml"] = "rss", - ["text/mathml"] = "mml", - ["text/plain"] = "txt", - ["text/vnd.sun.j2me.app-descriptor"] = "jad", - ["text/vnd.wap.wml"] = "wml", - ["text/x-component"] = "htc", - ["image/png"] = "png", - ["image/tiff"] = "tiff", - ["image/vnd.wap.wbmp"] = "wbmp", - ["image/x-icon"] = "ico", - ["image/x-jng"] = "jng", - ["image/x-ms-bmp"] = "bmp", - ["image/svg+xml"] = "svg", - ["image/webp"] = "webp", - ["application/java-archive"] = "jar", - ["application/mac-binhex40"] = "hqx", - ["application/msword"] = "doc", - ["application/pdf"] = "pdf", - ["application/postscript"] = "ps", - ["application/rtf"] = "rtf", - ["application/vnd.ms-excel"] = "xls", - ["application/vnd.ms-powerpoint"] = "ppt", - ["application/vnd.wap.wmlc"] = "wmlc", - ["application/vnd.google-earth.kml+xml"] = "kml", - ["application/vnd.google-earth.kmz"] = "kmz", - ["application/x-7z-compressed"] = "7z", - ["application/x-cocoa"] = "cco", - ["application/x-java-archive-diff"] = "jardiff", - ["application/x-java-jnlp-file"] = "jnlp", - ["application/x-makeself"] = "run", - ["application/x-perl"] = "pl", - ["application/x-pilot"] = "prc", - ["application/x-rar-compressed"] = "rar", - ["application/x-redhat-package-manager"] = "rpm", - ["application/x-sea"] = "sea", - ["application/x-shockwave-flash"] = "swf", - ["application/x-stuffit"] = "sit", - ["application/x-tcl"] = "tcl", - ["application/x-x509-ca-cert"] = "crt", - ["application/x-xpinstall"] = "xpi", - ["application/xhtml+xml"] = "xhtml", - ["application/zip"] = "zip", - ["application/octet-stream"] = "bin", - ["audio/midi"] = "mid", - ["audio/mpeg"] = "mp3", - ["audio/ogg"] = "ogg", - ["audio/x-m4a"] = "m4a", - ["audio/x-realaudio"] = "ra", - ["video/3gpp"] = "3gpp", - ["video/mp4"] = "mp4", - ["video/mpeg"] = "mpeg", - ["video/quicktime"] = "mov", - ["video/webm"] = "webm", - ["video/x-flv"] = "flv", - ["video/x-m4v"] = "m4v", - ["video/x-mng"] = "mng", - ["video/x-ms-asf"] = "asf", - ["video/x-ms-wmv"] = "wmv", - ["video/x-msvideo"] = "avi" -} - --- Returns the common file extension from a content-type -function mimetype.get_mime_extension(content_type) - return types[content_type] -end - --- Returns the mimetype and subtype -function mimetype.get_content_type(extension) - for k,v in pairs(types) do - if v == extension then - return k - end - end -end - --- Returns the mimetype without the subtype -function mimetype.get_content_type_no_sub(extension) - for k,v in pairs(types) do - if v == extension then - -- Before / - return k:match('([%w-]+)/') - end - end -end - -return mimetype -end \ No newline at end of file diff --git a/libs/redis.lua b/libs/redis.lua deleted file mode 100644 index c09142b..0000000 --- a/libs/redis.lua +++ /dev/null @@ -1,47 +0,0 @@ -local Redis = require 'redis' -local FakeRedis = require 'fakeredis' - -local params = { - host = '127.0.0.1', - port = 6379, -} - --- Overwrite HGETALL -Redis.commands.hgetall = Redis.command('hgetall', { - response = function(reply, command, ...) - local new_reply = { } - for i = 1, #reply, 2 do new_reply[reply[i]] = reply[i + 1] end - return new_reply - end -}) - -local redis = nil - --- Won't launch an error if fails -local ok = pcall(function() - redis = Redis.connect(params) -end) - -if not ok then - - local fake_func = function() - print('\27[31mCan\'t connect with Redis, install/configure it!\27[39m') - end - fake_func() - fake = FakeRedis.new() - - print('\27[31mRedis addr: '..params.host..'\27[39m') - print('\27[31mRedis port: '..params.port..'\27[39m') - - redis = setmetatable({fakeredis=true}, { - __index = function(a, b) - if b ~= 'data' and fake[b] then - fake_func(b) - end - return fake[b] or fake_func - end }) - -end - - -return redis \ No newline at end of file diff --git a/patches/disable-python-and-libjansson.patch b/patches/disable-python-and-libjansson.patch deleted file mode 100644 index 1093164..0000000 --- a/patches/disable-python-and-libjansson.patch +++ /dev/null @@ -1,130 +0,0 @@ ---- tg/configure.ac 2015-10-24 14:23:51.964259062 +0200 -+++ tg/configure.ac 2015-10-24 14:05:10.111062758 +0200 -@@ -61,93 +61,43 @@ - ],[ - ]) - -+# liblua is required - AC_MSG_CHECKING([for liblua]) --AC_ARG_ENABLE(liblua,[--enable-liblua/--disable-liblua], -- [ -- if test "x$enableval" = "xno" ; then -- AC_MSG_RESULT([disabled]) -- else -- AC_MSG_RESULT([enabled]) -- AX_PROG_LUA([],[], -- [ -- AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) -- AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) -- [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] -- [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] -- AC_DEFINE(USE_LUA,1,[use lua]) -- ], -- [ -- AC_MSG_ERROR([No lua found. Try --disable-liblua]) -- ]) -- fi -- ],[ -- AC_MSG_RESULT([enabled]) -- AX_PROG_LUA([],[], -- [ -- AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Try --disable-liblua])]) -- AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Try --disable-liblua])]) -- [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] -- [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] -- AC_DEFINE(USE_LUA,1,[use lua]) -- ], -- [ -- AC_MSG_ERROR([No lua found. Try --disable-liblua]) -- ]) -- ]) -- --AC_MSG_CHECKING([for python]) --AC_ARG_ENABLE(python,[--enable-python/--disable-python], -+AC_MSG_RESULT([enabled]) -+AX_PROG_LUA([],[], - [ -- if test "x$enableval" = "xno" ; then -- AC_MSG_RESULT([disabled]) -- else -- AC_MSG_RESULT([enabled]) -- -- AX_PYTHON() -- AC_SUBST([PYTHON_FOUND]) -- if test $PYTHON_FOUND = no ; then -- AC_MSG_ERROR([No supported python lib version found. Try --disable-python]) -- else -- AC_SUBST([PYTHON_LIBS]) -- AC_SUBST([PYTHON_CFLAGS]) -- EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}" -- CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}" -- AC_DEFINE(USE_PYTHON,1,[use python]) -- fi -- fi -- ],[ -- AC_MSG_RESULT([enabled]) -- -- AX_PYTHON() -- AC_SUBST([PYTHON_FOUND]) -- if test $PYTHON_FOUND = no ; then -- AC_MSG_ERROR([No supported python lib version found. Try --disable-python]) -- else -- AC_SUBST([PYTHON_LIBS]) -- AC_SUBST([PYTHON_CFLAGS]) -- EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}" -- CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}" -- AC_DEFINE(USE_PYTHON,1,[use python]) -- fi -+ AX_LUA_HEADERS([],[AC_MSG_ERROR([No lua headers found. Install them])]) -+ AX_LUA_LIBS([],[AC_MSG_ERROR([No lua libs found. Install them])]) -+ [EXTRA_LIBS="${EXTRA_LIBS} ${LUA_LIB}" ; ] -+ [CPPFLAGS="${CPPFLAGS} ${LUA_INCLUDE}" ; ] -+ AC_DEFINE(USE_LUA,1,[use lua]) -+ ], -+ [ -+ AC_MSG_ERROR([No lua found. Install lua]) - ]) - -+# Optional -+AC_MSG_CHECKING([for python]) -+AX_PYTHON() -+AC_SUBST([PYTHON_FOUND]) -+if test $PYTHON_FOUND = no ; then -+ AC_MSG_RESULT([disabled]) -+else -+ AC_SUBST([PYTHON_LIBS]) -+ AC_SUBST([PYTHON_CFLAGS]) -+ EXTRA_LIBS="${EXTRA_LIBS} -l${PYTHON_LIB}" -+ CPPFLAGS="${CPPFLAGS} -I${PYTHON_INCLUDE_DIR}" -+ AC_DEFINE(USE_PYTHON,1,[use python]) -+fi - -- -+# Optional - AC_MSG_CHECKING([for libjansson]) --AC_ARG_ENABLE(json,[--enable-json/--disable-json], -- [ -- if test "x$enableval" = "xno" ; then -- AC_MSG_RESULT([disabled]) -- else -- AC_MSG_RESULT([enabled]) -- AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json])) -- AC_DEFINE(USE_JSON,1,[use json]) -- fi -- ],[ -+AC_CHECK_LIB([jansson],[json_array_set_new], -+ [ - AC_MSG_RESULT([enabled]) -- AC_CHECK_LIB([jansson],[json_array_set_new],[],AC_MSG_ERROR([No libjansson found. Try --disable-json])) - AC_DEFINE(USE_JSON,1,[use json]) -- ]) -+ ], -+ [AC_MSG_RESULT([disabled])]) - - #check for custom prog name - AC_MSG_CHECKING([progname]) -@@ -193,4 +143,3 @@ - AC_SUBST(EXTRA_LIBS) - AC_CONFIG_FILES([Makefile]) - AC_OUTPUT -- diff --git a/plugins/admin.lua b/plugins/admin.lua deleted file mode 100644 index b30014a..0000000 --- a/plugins/admin.lua +++ /dev/null @@ -1,209 +0,0 @@ -local function set_bot_photo(msg, success, result) - local receiver = get_receiver(msg) - if success then - local file = 'data/photos/bot.jpg' - print('File downloaded to:', result) - os.rename(result, file) - print('File moved to:', file) - set_profile_photo(file, ok_cb, false) - send_large_msg(receiver, 'Photo changed!', ok_cb, false) - redis:del("bot:photo") - else - print('Error downloading: '..msg.id) - send_large_msg(receiver, 'Failed, please try again!', ok_cb, false) - end -end -local function parsed_url(link) - local parsed_link = URL.parse(link) - local parsed_path = URL.parse_path(parsed_link.path) - return parsed_path[2] -end -local function get_contact_list_callback (cb_extra, success, result) - local text = " " - for k,v in pairs(result) do - if v.print_name and v.id and v.phone then - text = text..string.gsub(v.print_name , "_" , " ").." ["..v.id.."] = "..v.phone.."\n" - end - end - local file = io.open("contact_list.txt", "w") - file:write(text) - file:flush() - file:close() - send_document("user#id"..cb_extra.target,"contact_list.txt", ok_cb, false)--.txt format - local file = io.open("contact_list.json", "w") - file:write(json:encode_pretty(result)) - file:flush() - file:close() - send_document("user#id"..cb_extra.target,"contact_list.json", ok_cb, false)--json format -end -local function user_info_callback(cb_extra, success, result) - result.access_hash = nil - result.flags = nil - result.phone = nil - if result.username then - result.username = '@'..result.username - end - result.print_name = result.print_name:gsub("_","") - local text = serpent.block(result, {comment=false}) - text = text:gsub("[{}]", "") - text = text:gsub('"', "") - text = text:gsub(",","") - if cb_extra.msg.to.type == "chat" then - send_large_msg("chat#id"..cb_extra.msg.to.id, text) - else - send_large_msg("user#id"..cb_extra.msg.to.id, text) - end -end -local function get_dialog_list_callback(cb_extra, success, result) - local text = "" - for k,v in pairs(result) do - if v.peer then - if v.peer.type == "chat" then - text = text.."group{"..v.peer.title.."}["..v.peer.id.."]("..v.peer.members_num..")" - else - if v.peer.print_name and v.peer.id then - text = text.."user{"..v.peer.print_name.."}["..v.peer.id.."]" - end - if v.peer.username then - text = text.."("..v.peer.username..")" - end - if v.peer.phone then - text = text.."'"..v.peer.phone.."'" - end - end - end - if v.message then - text = text..'\nlast msg >\nmsg id = '..v.message.id - if v.message.text then - text = text .. "\n text = "..v.message.text - end - if v.message.action then - text = text.."\n"..serpent.block(v.message.action, {comment=false}) - end - if v.message.from then - if v.message.from.print_name then - text = text.."\n From > \n"..string.gsub(v.message.from.print_name, "_"," ").."["..v.message.from.id.."]" - end - if v.message.from.username then - text = text.."( "..v.message.from.username.." )" - end - if v.message.from.phone then - text = text.."' "..v.message.from.phone.." '" - end - end - end - text = text.."\n\n" - end - local file = io.open("dialog_list.txt", "w") - file:write(text) - file:flush() - file:close() - send_document("user#id"..cb_extra.target,"dialog_list.txt", ok_cb, false)--.txt format - local file = io.open("dialog_list.json", "w") - file:write(json:encode_pretty(result)) - file:flush() - file:close() - send_document("user#id"..cb_extra.target,"dialog_list.json", ok_cb, false)--json format -end -local function run(msg,matches) - local data = load_data(_config.moderation.data) - local receiver = get_receiver(msg) - local group = msg.to.id - if not is_admin(msg) then - return - end - if msg.media then - if msg.media.type == 'photo' and redis:get("bot:photo") then - if redis:get("bot:photo") == 'waiting' then - load_photo(msg.id, set_bot_photo, msg) - end - end - end - if matches[1] == "setbotphoto" then - redis:set("bot:photo", "waiting") - return 'Please send me bot photo now' - end - if matches[1] == "markread" then - if matches[2] == "on" then - redis:set("bot:markread", "on") - return "Mark read > on" - end - if matches[2] == "off" then - redis:del("bot:markread") - return "Mark read > off" - end - return - end - if matches[1] == "pm" then - send_large_msg("user#id"..matches[2],matches[3]) - return "Msg sent" - end - if matches[1] == "block" then - if is_admin2(matches[2]) then - return "You can't block admins" - end - block_user("user#id"..matches[2],ok_cb,false) - return "User blocked" - end - if matches[1] == "unblock" then - unblock_user("user#id"..matches[2],ok_cb,false) - return "User unblocked" - end - if matches[1] == "import" then--join by group link - local hash = parsed_url(matches[2]) - import_chat_link(hash,ok_cb,false) - end - if matches[1] == "contactlist" then - get_contact_list(get_contact_list_callback, {target = msg.from.id}) - return "I've sent contact list with both json and text format to your private" - end - if matches[1] == "addcontact" and matches[2] then add_contact(matches[2],matches[3],matches[4],ok_cb,false) - return "Number "..matches[2].." add from contact list" - end - if matches[1] == "delcontact" then - del_contact("user#id"..matches[2],ok_cb,false) - return "User "..matches[2].." removed from contact list" - end - if matches[1] == "dialoglist" then - get_dialog_list(get_dialog_list_callback, {target = msg.from.id}) - return "I've sent dialog list with both json and text format to your private" - end - if matches[1] == "whois" then - user_info("user#id"..matches[2],user_info_callback,{msg=msg}) - end - if matches[1] == "sync_gbans" then - if not is_sudo(msg) then-- Sudo only - return - end - local url = "http://seedteam.org/Teleseed/Global_bans.json" - local SEED_gbans = http.request(url) - local jdat = json:decode(SEED_gbans) - for k,v in pairs(jdat) do - redis:hset('user:'..v, 'print_name', k) - banall_user(v) - print(k, v.." Globally banned") - end - end - return -end -return { - patterns = { - "^[!/](pm) (%d+) (.*)$", - "^[!/](import) (.*)$", - "^[!/](unblock) (%d+)$", - "^[!/](block) (%d+)$", - "^[!/](markread) (on)$", - "^[!/](markread) (off)$", - "^[!/](setbotphoto)$", - "%[(photo)%]", - "^[!/](contactlist)$", - "^[!/](dialoglist)$", - "^[!/](delcontact) (%d+)$", - "^[!/](addcontact) (.*) (.*) (.*)$", - "^[!/](whois) (%d+)$", - "^/(sync_gbans)$"--sync your global bans with seed - }, - run = run, -} ---By @imandaneshi :) ---https://github.com/SEEDTEAM/TeleSeed/blob/master/plugins/admin.lua diff --git a/plugins/all.lua b/plugins/all.lua deleted file mode 100644 index fe4751c..0000000 --- a/plugins/all.lua +++ /dev/null @@ -1,156 +0,0 @@ -do -data = load_data(_config.moderation.data) -local function get_msgs_user_chat(user_id, chat_id) - local user_info = {} - local uhash = 'user:'..user_id - local user = redis:hgetall(uhash) - local um_hash = 'msgs:'..user_id..':'..chat_id - user_info.msgs = tonumber(redis:get(um_hash) or 0) - user_info.name = user_print_name(user)..' ['..user_id..']' - return user_info -end -local function chat_stats(chat_id) - local hash = 'chat:'..chat_id..':users' - local users = redis:smembers(hash) - local users_info = {} - for i = 1, #users do - local user_id = users[i] - local user_info = get_msgs_user_chat(user_id, chat_id) - table.insert(users_info, user_info) - end - table.sort(users_info, function(a, b) - if a.msgs and b.msgs then - return a.msgs > b.msgs - end - end) - local text = 'Chat stats:\n' - for k,user in pairs(users_info) do - text = text..user.name..' = '..user.msgs..'\n' - end - return text -end - -local function get_group_type(target) - local data = load_data(_config.moderation.data) - local group_type = data[tostring(target)]['group_type'] - if not group_type or group_type == nil then - return 'No group type available.' - end - return group_type -end -local function show_group_settings(target) - local data = load_data(_config.moderation.data) - if data[tostring(target)] then - if data[tostring(target)]['settings']['flood_msg_max'] then - NUM_MSG_MAX = tonumber(data[tostring(target)]['settings']['flood_msg_max']) - print('custom'..NUM_MSG_MAX) - else - NUM_MSG_MAX = 5 - end - end - local settings = data[tostring(target)]['settings'] - local text = "Lock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nflood sensitivity : "..NUM_MSG_MAX - return text -end - -local function get_description(target) - local data = load_data(_config.moderation.data) - local data_cat = 'description' - if not data[tostring(target)][data_cat] then - return 'No description available.' - end - local about = data[tostring(target)][data_cat] - return about -end - -local function get_rules(target) - local data = load_data(_config.moderation.data) - local data_cat = 'rules' - if not data[tostring(target)][data_cat] then - return 'No rules available.' - end - local rules = data[tostring(target)][data_cat] - return rules -end - - -local function modlist(target) - local data = load_data(_config.moderation.data) - local groups = 'groups' - if not data[tostring(groups)] or not data[tostring(groups)][tostring(target)] then - return 'Group is not added or is Realm.' - end - if next(data[tostring(target)]['moderators']) == nil then - return 'No moderator in this group.' - end - local i = 1 - local message = '\nList of moderators :\n' - for k,v in pairs(data[tostring(target)]['moderators']) do - message = message ..i..' - @'..v..' [' ..k.. '] \n' - i = i + 1 - end - return message -end - -local function get_link(target) - local data = load_data(_config.moderation.data) - local group_link = data[tostring(target)]['settings']['set_link'] - if not group_link or group_link == nil then - return "No link" - end - return "Group link:\n"..group_link -end - -local function all(target, receiver) - local text = "All the things I know about this group\n\n" - local group_type = get_group_type(target) - text = text.."Group Type: \n"..group_type - local settings = show_group_settings(target) - text = text.."\n\nGroup settings: \n"..settings - local rules = get_rules(target) - text = text.."\n\nRules: \n"..rules - local description = get_description(target) - text = text.."\n\nAbout: \n"..description - local modlist = modlist(target) - text = text.."\n\nMods: \n"..modlist - local link = get_link(target) - text = text.."\n\nLink: \n"..link - local stats = chat_stats(target) - text = text.."\n\n"..stats - local ban_list = ban_list(target) - text = text.."\n\n"..ban_list - local file = io.open("./groups/all/"..target.."all.txt", "w") - file:write(text) - file:flush() - file:close() - send_document(receiver,"./groups/all/"..target.."all.txt", ok_cb, false) - return -end - -function run(msg, matches) - if matches[1] == "all" and matches[2] and is_owner2(msg.from.id, matches[2]) then - local receiver = get_receiver(msg) - local target = matches[2] - return all(target, receiver) - end - if not is_owner(msg) then - return - end - if matches[1] == "all" and not matches[2] then - local receiver = get_receiver(msg) - if not is_owner(msg) then - return - end - return all(msg.to.id, receiver) - end -end - - -return { - patterns = { - "^[!/](all)$", - "^[!/](all) (%d+)$" - }, - run = run -} -end diff --git a/plugins/anti_spam.lua b/plugins/anti_spam.lua deleted file mode 100644 index 689857c..0000000 --- a/plugins/anti_spam.lua +++ /dev/null @@ -1,134 +0,0 @@ - ---An empty table for solving multiple kicking problem(thanks to @topkecleon ) -kicktable = {} - -do - -local TIME_CHECK = 2 -- seconds -local data = load_data(_config.moderation.data) --- Save stats, ban user -local function pre_process(msg) - -- Ignore service msg - if msg.service then - return msg - end - if msg.from.id == our_id then - return msg - end - - -- Save user on Redis - if msg.from.type == 'user' then - local hash = 'user:'..msg.from.id - print('Saving user', hash) - if msg.from.print_name then - redis:hset(hash, 'print_name', msg.from.print_name) - end - if msg.from.first_name then - redis:hset(hash, 'first_name', msg.from.first_name) - end - if msg.from.last_name then - redis:hset(hash, 'last_name', msg.from.last_name) - end - if msg.from.username then - redis:hset(hash, 'username', msg.from.username) - end - end - - -- Save stats on Redis - if msg.to.type == 'chat' then - -- User is on chat - local hash = 'chat:'..msg.to.id..':users' - redis:sadd(hash, msg.from.id) - end - - - - -- Total user msgs - local hash = 'msgs:'..msg.from.id..':'..msg.to.id - redis:incr(hash) - - --Load moderation data - local data = load_data(_config.moderation.data) - if data[tostring(msg.to.id)] then - --Check if flood is one or off - if data[tostring(msg.to.id)]['settings']['flood'] == 'no' then - return msg - end - end - - -- Check flood - if msg.from.type == 'user' then - local hash = 'user:'..msg.from.id..':msgs' - local msgs = tonumber(redis:get(hash) or 0) - local data = load_data(_config.moderation.data) - local NUM_MSG_MAX = 5 - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then - NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max'])--Obtain group flood sensitivity - end - end - local max_msg = NUM_MSG_MAX * 1 - if msgs > max_msg then - local user = msg.from.id - -- Ignore mods,owner and admins - if is_momod(msg) then - return msg - end - local chat = msg.to.id - local user = msg.from.id - -- Return end if user was kicked before - if kicktable[user] == true then - return - end - kick_user(user, chat) - if msg.to.type == "user" then - block_user("user#id"..msg.from.id,ok_cb,false)--Block user if spammed in private - end - local name = user_print_name(msg.from) - --save it to log file - savelog(msg.to.id, name.." ["..msg.from.id.."] spammed and kicked ! ") - -- incr it on redis - local gbanspam = 'gban:spam'..msg.from.id - redis:incr(gbanspam) - local gbanspam = 'gban:spam'..msg.from.id - local gbanspamonredis = redis:get(gbanspam) - --Check if user has spammed is group more than 4 times - if gbanspamonredis then - if tonumber(gbanspamonredis) == 4 and not is_owner(msg) then - --Global ban that user - banall_user(msg.from.id) - local gbanspam = 'gban:spam'..msg.from.id - --reset the counter - redis:set(gbanspam, 0) - local username = " " - if msg.from.username ~= nil then - username = msg.from.username - end - local name = user_print_name(msg.from) - --Send this to that chat - send_large_msg("chat#id"..msg.to.id, "User [ "..name.." ]"..msg.from.id.." Globally banned (spamming)") - local log_group = 1 --set log group caht id - --send it to log group - send_large_msg("chat#id"..log_group, "User [ "..name.." ] ( @"..username.." )"..msg.from.id.." Globally banned from ( "..msg.to.print_name.." ) [ "..msg.to.id.." ] (spamming)") - end - end - kicktable[user] = true - msg = nil - end - redis:setex(hash, TIME_CHECK, msgs+1) - end - return msg -end - -local function cron() - --clear that table on the top of the plugins - kicktable = {} -end - -return { - patterns = {}, - cron = cron, - pre_process = pre_process -} - -end diff --git a/plugins/arabic_lock.lua b/plugins/arabic_lock.lua deleted file mode 100644 index 86e462f..0000000 --- a/plugins/arabic_lock.lua +++ /dev/null @@ -1,36 +0,0 @@ - -antiarabic = {}-- An empty table for solving multiple kicking problem - -do -local function run(msg, matches) - if is_momod(msg) then -- Ignore mods,owner,admins - return - end - local data = load_data(_config.moderation.data) - if data[tostring(msg.to.id)]['settings']['lock_arabic'] then - if data[tostring(msg.to.id)]['settings']['lock_arabic'] == 'yes' then - if antiarabic[msg.from.id] == true then - return - end - send_large_msg("chat#id".. msg.to.id , "Arabic is not allowed here") - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] kicked (arabic was locked) ") - chat_del_user('chat#id'..msg.to.id,'user#id'..msg.from.id,ok_cb,false) - antiarabic[msg.from.id] = true - return - end - end - return -end -local function cron() - antiarabic = {} -- Clear antiarabic table -end -return { - patterns = { - "([\216-\219][\128-\191])" - }, - run = run, - cron = cron -} - -end diff --git a/plugins/banhammer.lua b/plugins/banhammer.lua deleted file mode 100644 index eda9676..0000000 --- a/plugins/banhammer.lua +++ /dev/null @@ -1,331 +0,0 @@ - -local function pre_process(msg) - -- SERVICE MESSAGE - if msg.action and msg.action.type then - local action = msg.action.type - -- Check if banned user joins chat by link - if action == 'chat_add_user_link' then - local user_id = msg.from.id - print('Checking invited user '..user_id) - local banned = is_banned(user_id, msg.to.id) - if banned or is_gbanned(user_id) then -- Check it with redis - print('User is banned!') - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] is banned and kicked ! ")-- Save to logs - kick_user(user_id, msg.to.id) - end - end - -- Check if banned user joins chat - if action == 'chat_add_user' then - local user_id = msg.action.user.id - print('Checking invited user '..user_id) - local banned = is_banned(user_id, msg.to.id) - if banned or is_gbanned(user_id) then -- Check it with redis - print('User is banned!') - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] added a banned user >"..msg.action.user.id)-- Save to logs - kick_user(user_id, msg.to.id) - local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id - redis:incr(banhash) - local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id - local banaddredis = redis:get(banhash) - if banaddredis then - if tonumber(banaddredis) == 4 and not is_owner(msg) then - kick_user(msg.from.id, msg.to.id)-- Kick user who adds ban ppl more than 3 times - end - if tonumber(banaddredis) == 8 and not is_owner(msg) then - ban_user(msg.from.id, msg.to.id)-- Kick user who adds ban ppl more than 7 times - local banhash = 'addedbanuser:'..msg.to.id..':'..msg.from.id - redis:set(banhash, 0)-- Reset the Counter - end - end - end - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['settings'] then - if data[tostring(msg.to.id)]['settings']['lock_bots'] then - bots_protection = data[tostring(msg.to.id)]['settings']['lock_bots'] - end - end - end - if msg.action.user.username ~= nil then - if string.sub(msg.action.user.username:lower(), -3) == 'bot' and not is_momod(msg) and bots_protection == "yes" then --- Will kick bots added by normal users - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] added a bot > @".. msg.action.user.username)-- Save to logs - kick_user(msg.action.user.id, msg.to.id) - end - end - end - -- No further checks - return msg - end - -- banned user is talking ! - if msg.to.type == 'chat' then - local data = load_data(_config.moderation.data) - local group = msg.to.id - local texttext = 'groups' - --if not data[tostring(texttext)][tostring(msg.to.id)] and not is_realm(msg) then -- Check if this group is one of my groups or not - --chat_del_user('chat#id'..msg.to.id,'user#id'..our_id,ok_cb,false) - --return - --end - local user_id = msg.from.id - local chat_id = msg.to.id - local banned = is_banned(user_id, chat_id) - if banned or is_gbanned(user_id) then -- Check it with redis - print('Banned user talking!') - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] banned user is talking !")-- Save to logs - kick_user(user_id, chat_id) - msg.text = '' - end - end - return msg -end - -local function kick_ban_res(extra, success, result) ---vardump(result) ---vardump(extra) - local member_id = result.id - local user_id = member_id - local member = result.username - local chat_id = extra.chat_id - local from_id = extra.from_id - local get_cmd = extra.get_cmd - local receiver = "chat#id"..chat_id - if get_cmd == "kick" then - if member_id == from_id then - return send_large_msg(receiver, "You can't kick yourself") - end - if is_momod2(member_id, chat_id) and not is_admin2(sender) then - return send_large_msg(receiver, "You can't kick mods/owner/admins") - end - return kick_user(member_id, chat_id) - elseif get_cmd == 'ban' then - if is_momod2(member_id, chat_id) and not is_admin2(sender) then - return send_large_msg(receiver, "You can't ban mods/owner/admins") - end - send_large_msg(receiver, 'User @'..member..' ['..member_id..'] banned') - return ban_user(member_id, chat_id) - elseif get_cmd == 'unban' then - send_large_msg(receiver, 'User @'..member..' ['..member_id..'] unbanned') - local hash = 'banned:'..chat_id - redis:srem(hash, member_id) - return 'User '..user_id..' unbanned' - elseif get_cmd == 'banall' then - send_large_msg(receiver, 'User @'..member..' ['..member_id..'] globally banned') - return banall_user(member_id, chat_id) - elseif get_cmd == 'unbanall' then - send_large_msg(receiver, 'User @'..member..' ['..member_id..'] un-globally banned') - return unbanall_user(member_id, chat_id) - end -end - -local function run(msg, matches) - if matches[1]:lower() == 'id' then - if msg.to.type == "user" then - return "Bot ID: "..msg.to.id.. "\n\nYour ID: "..msg.from.id - end - if type(msg.reply_id) ~= "nil" then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] used /id ") - id = get_message(msg.reply_id,get_message_callback_id, false) - elseif matches[1]:lower() == 'id' then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] used /id ") - return "Group ID for " ..string.gsub(msg.to.print_name, "_", " ").. ":\n\n"..msg.to.id - end - end - if matches[1]:lower() == 'kickme' then-- /kickme - local receiver = get_receiver(msg) - if msg.to.type == 'chat' then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] left using kickme ")-- Save to logs - chat_del_user("chat#id"..msg.to.id, "user#id"..msg.from.id, ok_cb, false) - end - end - - if not is_momod(msg) then -- Ignore normal users - return - end - - if matches[1]:lower() == "banlist" then -- Ban list ! - local chat_id = msg.to.id - if matches[2] and is_admin(msg) then - chat_id = matches[2] - end - return ban_list(chat_id) - end - if matches[1]:lower() == 'ban' then-- /ban - if type(msg.reply_id)~="nil" and is_momod(msg) then - if is_admin(msg) then - local msgr = get_message(msg.reply_id,ban_by_reply_admins, false) - else - msgr = get_message(msg.reply_id,ban_by_reply, false) - end - end - local user_id = matches[2] - local chat_id = msg.to.id - if string.match(matches[2], '^%d+$') then - if tonumber(matches[2]) == tonumber(our_id) then - return - end - if not is_admin(msg) and is_momod2(matches[2], msg.to.id) then - return "you can't ban mods/owner/admins" - end - if tonumber(matches[2]) == tonumber(msg.from.id) then - return "You can't ban your self !" - end - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] baned user ".. matches[2]) - ban_user(user_id, chat_id) - else - local cbres_extra = { - chat_id = msg.to.id, - get_cmd = 'ban', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - res_user(username, kick_ban_res, cbres_extra) - end - end - - - if matches[1]:lower() == 'unban' then -- /unban - if type(msg.reply_id)~="nil" and is_momod(msg) then - local msgr = get_message(msg.reply_id,unban_by_reply, false) - end - local user_id = matches[2] - local chat_id = msg.to.id - local targetuser = matches[2] - if string.match(targetuser, '^%d+$') then - local user_id = targetuser - local hash = 'banned:'..chat_id - redis:srem(hash, user_id) - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] unbaned user ".. matches[2]) - return 'User '..user_id..' unbanned' - else - local cbres_extra = { - chat_id = msg.to.id, - get_cmd = 'unban', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - res_user(username, kick_ban_res, cbres_extra) - end - end - -if matches[1]:lower() == 'kick' then - if type(msg.reply_id)~="nil" and is_momod(msg) then - if is_admin(msg) then - local msgr = get_message(msg.reply_id,Kick_by_reply_admins, false) - else - msgr = get_message(msg.reply_id,Kick_by_reply, false) - end - end - - if string.match(matches[2], '^%d+$') then - if tonumber(matches[2]) == tonumber(our_id) then - return - end - if not is_admin(msg) and is_momod2(matches[2], msg.to.id) then - return "you can't kick mods/owner/admins" - end - if tonumber(matches[2]) == tonumber(msg.from.id) then - return "You can't kick your self !" - end - local user_id = matches[2] - local chat_id = msg.to.id - name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] kicked user ".. matches[2]) - kick_user(user_id, chat_id) - else - local cbres_extra = { - chat_id = msg.to.id, - get_cmd = 'kick', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - res_user(username, kick_ban_res, cbres_extra) - end -end - - - if not is_admin(msg) then - return - end - - if matches[1]:lower() == 'banall' then -- Global ban - if type(msg.reply_id) ~="nil" and is_admin(msg) then - return get_message(msg.reply_id,banall_by_reply, false) - end - local user_id = matches[2] - local chat_id = msg.to.id - local targetuser = matches[2] - if string.match(targetuser, '^%d+$') then - if tonumber(matches[2]) == tonumber(our_id) then - return false - end - banall_user(targetuser) - return 'User ['..user_id..' ] globally banned' - else - local cbres_extra = { - chat_id = msg.to.id, - get_cmd = 'banall', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - res_user(username, kick_ban_res, cbres_extra) - end - end - if matches[1]:lower() == 'unbanall' then -- Global unban - local user_id = matches[2] - local chat_id = msg.to.id - if string.match(matches[2], '^%d+$') then - if tonumber(matches[2]) == tonumber(our_id) then - return false - end - unbanall_user(user_id) - return 'User ['..user_id..' ] removed from global ban list' - else - local cbres_extra = { - chat_id = msg.to.id, - get_cmd = 'unbanall', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - res_user(username, kick_ban_res, cbres_extra) - end - end - if matches[1]:lower() == "gbanlist" then -- Global ban list - return banall_list() - end -end - -return { - patterns = { - "^[!/]([Bb]anall) (.*)$", - "^[!/]([Bb]anall)$", - "^[!/]([Bb]anlist) (.*)$", - "^[!/]([Bb]anlist)$", - "^[!/]([Gg]banlist)$", - "^[!/]([Bb]an) (.*)$", - "^[!/]([Kk]ick)$", - "^[!/]([Uu]nban) (.*)$", - "^[!/]([Uu]nbanall) (.*)$", - "^[!/]([Uu]nbanall)$", - "^[!/]([Kk]ick) (.*)$", - "^[!/]([Kk]ickme)$", - "^[!/]([Bb]an)$", - "^[!/]([Uu]nban)$", - "^[!/]([Ii]d)$", - "^!!tgservice (.+)$" - }, - run = run, - pre_process = pre_process -} - diff --git a/plugins/broadcast.lua b/plugins/broadcast.lua deleted file mode 100644 index eea356e..0000000 --- a/plugins/broadcast.lua +++ /dev/null @@ -1,25 +0,0 @@ -local function run(msg, matches) - if matches[1] == 'bc' and is_admin(msg) then - local response = matches[3] - send_large_msg("chat#id"..matches[2], response) - end - if matches[1] == 'broadcast' then - if is_sudo(msg) then -- Only sudo ! - local data = load_data(_config.moderation.data) - local groups = 'groups' - local response = matches[2] - for k,v in pairs(data[tostring(groups)]) do - chat_id = v - local receiver = 'chat#id'..chat_id - send_large_msg(receiver, response) - end - end - end -end -return { - patterns = { - "^[!/](broadcast) +(.+)$", - "^[!/](bc) (%d+) (.*)$" - }, - run = run -} diff --git a/plugins/download_media.lua b/plugins/download_media.lua deleted file mode 100644 index 37e1167..0000000 --- a/plugins/download_media.lua +++ /dev/null @@ -1,33 +0,0 @@ -local function callback(extra, success, result) -- Calback for load_photo in line 17 - if success then - print('File downloaded to:', result) - else - print('Error downloading: '..extra) - end -end - -local function run(msg, matches) - if not is_momod(msg) then -- Will download images only from mods,owner and admins - return - end - if msg.media then - if msg.media.type == 'photo' then - load_photo(msg.id, callback, msg.id) - end - end -end - -local function pre_process(msg) - if not msg.text and msg.media then - msg.text = '['..msg.media.type..']' - end - return msg -end - -return { - run = run, - patterns = { - '%[(photo)%]' - }, - pre_process = pre_process -} diff --git a/plugins/get.lua b/plugins/get.lua deleted file mode 100644 index 5ca47d5..0000000 --- a/plugins/get.lua +++ /dev/null @@ -1,37 +0,0 @@ -local function get_variables_hash(msg) - if msg.to.type == 'chat' then - return 'chat:'..msg.to.id..':variables' - end -end - -local function get_value(msg, var_name) - local hash = get_variables_hash(msg) - if hash then - local value = redis:hget(hash, var_name) - if not value then - return - else - return var_name..' :\n'..value - end - end -end - -local function run(msg, matches) - if not is_momod(msg) then -- only for mods,owner and admins - return - end - if matches[2] then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] used /get ".. matches[2])-- save to logs - return get_value(msg, matches[2]) - else - return - end -end - -return { - patterns = { - "^([!/]get) (.+)$" - }, - run = run -} diff --git a/plugins/ingroup.lua b/plugins/ingroup.lua deleted file mode 100644 index 5606327..0000000 --- a/plugins/ingroup.lua +++ /dev/null @@ -1,1267 +0,0 @@ -do - --- Check Member -local function check_member_autorealm(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Group configuration - data[tostring(msg.to.id)] = { - group_type = 'Realm', - settings = { - set_name = string.gsub(msg.to.print_name, '_', ' '), - lock_name = 'yes', - lock_photo = 'no', - lock_member = 'no', - flood = 'yes' - } - } - save_data(_config.moderation.data, data) - local realms = 'realms' - if not data[tostring(realms)] then - data[tostring(realms)] = {} - save_data(_config.moderation.data, data) - end - data[tostring(realms)][tostring(msg.to.id)] = msg.to.id - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Welcome to your new realm !') - end - end -end -local function check_member_realm_add(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Group configuration - data[tostring(msg.to.id)] = { - group_type = 'Realm', - settings = { - set_name = string.gsub(msg.to.print_name, '_', ' '), - lock_name = 'yes', - lock_photo = 'no', - lock_member = 'no', - flood = 'yes' - } - } - save_data(_config.moderation.data, data) - local realms = 'realms' - if not data[tostring(realms)] then - data[tostring(realms)] = {} - save_data(_config.moderation.data, data) - end - data[tostring(realms)][tostring(msg.to.id)] = msg.to.id - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Realm has been added!') - end - end -end -function check_member_group(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Group configuration - data[tostring(msg.to.id)] = { - group_type = 'Group', - moderators = {}, - set_owner = member_id , - settings = { - set_name = string.gsub(msg.to.print_name, '_', ' '), - lock_name = 'yes', - lock_photo = 'no', - lock_member = 'no', - flood = 'yes', - } - } - save_data(_config.moderation.data, data) - local groups = 'groups' - if not data[tostring(groups)] then - data[tostring(groups)] = {} - save_data(_config.moderation.data, data) - end - data[tostring(groups)][tostring(msg.to.id)] = msg.to.id - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'You have been promoted as the owner.') - end - end -end -local function check_member_modadd(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Group configuration - data[tostring(msg.to.id)] = { - group_type = 'Group', - moderators = {}, - set_owner = member_id , - settings = { - set_name = string.gsub(msg.to.print_name, '_', ' '), - lock_name = 'yes', - lock_photo = 'no', - lock_member = 'no', - flood = 'yes', - } - } - save_data(_config.moderation.data, data) - local groups = 'groups' - if not data[tostring(groups)] then - data[tostring(groups)] = {} - save_data(_config.moderation.data, data) - end - data[tostring(groups)][tostring(msg.to.id)] = msg.to.id - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Group is added and you have been promoted as the owner ') - end - end -end -local function automodadd(msg) - local data = load_data(_config.moderation.data) - if msg.action.type == 'chat_created' then - receiver = get_receiver(msg) - chat_info(receiver, check_member_group,{receiver=receiver, data=data, msg = msg}) - end -end -local function autorealmadd(msg) - local data = load_data(_config.moderation.data) - if msg.action.type == 'chat_created' then - receiver = get_receiver(msg) - chat_info(receiver, check_member_autorealm,{receiver=receiver, data=data, msg = msg}) - end -end -local function check_member_realmrem(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Realm configuration removal - data[tostring(msg.to.id)] = nil - save_data(_config.moderation.data, data) - local realms = 'realms' - if not data[tostring(realms)] then - data[tostring(realms)] = nil - save_data(_config.moderation.data, data) - end - data[tostring(realms)][tostring(msg.to.id)] = nil - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Realm has been removed!') - end - end -end -local function check_member_modrem(cb_extra, success, result) - local receiver = cb_extra.receiver - local data = cb_extra.data - local msg = cb_extra.msg - for k,v in pairs(result.members) do - local member_id = v.id - if member_id ~= our_id then - -- Group configuration removal - data[tostring(msg.to.id)] = nil - save_data(_config.moderation.data, data) - local groups = 'groups' - if not data[tostring(groups)] then - data[tostring(groups)] = nil - save_data(_config.moderation.data, data) - end - data[tostring(groups)][tostring(msg.to.id)] = nil - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Group has been removed') - end - end -end ---End Check Member -local function show_group_settingsmod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local data = load_data(_config.moderation.data) - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then - NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max']) - print('custom'..NUM_MSG_MAX) - else - NUM_MSG_MAX = 5 - end - end - local bots_protection = "Yes" - if data[tostring(msg.to.id)]['settings']['lock_bots'] then - bots_protection = data[tostring(msg.to.id)]['settings']['lock_bots'] - end - local leave_ban = "no" - if data[tostring(msg.to.id)]['settings']['leave_ban'] then - leave_ban = data[tostring(msg.to.id)]['settings']['leave_ban'] - end - local settings = data[tostring(target)]['settings'] - local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nLock group leave : "..leave_ban.."\nflood sensitivity : "..NUM_MSG_MAX.."\nBot protection : "..bots_protection--"\nPublic: "..public - return text -end - -local function set_descriptionmod(msg, data, target, about) - if not is_momod(msg) then - return "For moderators only!" - end - local data_cat = 'description' - data[tostring(target)][data_cat] = about - save_data(_config.moderation.data, data) - return 'Set group description to:\n'..about -end -local function get_description(msg, data) - local data_cat = 'description' - if not data[tostring(msg.to.id)][data_cat] then - return 'No description available.' - end - local about = data[tostring(msg.to.id)][data_cat] - local about = string.gsub(msg.to.print_name, "_", " ")..':\n\n'..about - return 'About '..about -end -local function lock_group_arabic(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_arabic_lock = data[tostring(target)]['settings']['lock_arabic'] - if group_arabic_lock == 'yes' then - return 'Arabic is already locked' - else - data[tostring(target)]['settings']['lock_arabic'] = 'yes' - save_data(_config.moderation.data, data) - return 'Arabic has been locked' - end -end - -local function unlock_group_arabic(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_arabic_lock = data[tostring(target)]['settings']['lock_arabic'] - if group_arabic_lock == 'no' then - return 'Arabic is already unlocked' - else - data[tostring(target)]['settings']['lock_arabic'] = 'no' - save_data(_config.moderation.data, data) - return 'Arabic has been unlocked' - end -end - -local function lock_group_bots(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_bots_lock = data[tostring(target)]['settings']['lock_bots'] - if group_bots_lock == 'yes' then - return 'Bots protection is already enabled' - else - data[tostring(target)]['settings']['lock_bots'] = 'yes' - save_data(_config.moderation.data, data) - return 'Bots protection has been enabled' - end -end - -local function unlock_group_bots(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_bots_lock = data[tostring(target)]['settings']['lock_bots'] - if group_bots_lock == 'no' then - return 'Bots protection is already disabled' - else - data[tostring(target)]['settings']['lock_bots'] = 'no' - save_data(_config.moderation.data, data) - return 'Bots protection has been disabled' - end -end - -local function lock_group_namemod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'yes' then - return 'Group name is already locked' - else - data[tostring(target)]['settings']['lock_name'] = 'yes' - save_data(_config.moderation.data, data) - rename_chat('chat#id'..target, group_name_set, ok_cb, false) - return 'Group name has been locked' - end -end -local function unlock_group_namemod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'no' then - return 'Group name is already unlocked' - else - data[tostring(target)]['settings']['lock_name'] = 'no' - save_data(_config.moderation.data, data) - return 'Group name has been unlocked' - end -end -local function lock_group_floodmod(msg, data, target) - if not is_owner(msg) then - return "Only admins can do it for now" - end - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'yes' then - return 'Group flood is locked' - else - data[tostring(target)]['settings']['flood'] = 'yes' - save_data(_config.moderation.data, data) - return 'Group flood has been locked' - end -end - -local function unlock_group_floodmod(msg, data, target) - if not is_owner(msg) then - return "Only admins can do it for now" - end - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'no' then - return 'Group flood is not locked' - else - data[tostring(target)]['settings']['flood'] = 'no' - save_data(_config.moderation.data, data) - return 'Group flood has been unlocked' - end -end - -local function lock_group_membermod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'yes' then - return 'Group members are already locked' - else - data[tostring(target)]['settings']['lock_member'] = 'yes' - save_data(_config.moderation.data, data) - end - return 'Group members has been locked' -end - -local function unlock_group_membermod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'no' then - return 'Group members are not locked' - else - data[tostring(target)]['settings']['lock_member'] = 'no' - save_data(_config.moderation.data, data) - return 'Group members has been unlocked' - end -end - - -local function set_public_membermod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_member_lock = data[tostring(target)]['settings']['public'] - if group_member_lock == 'yes' then - return 'Group is already public' - else - data[tostring(target)]['settings']['public'] = 'yes' - save_data(_config.moderation.data, data) - end - return 'Group is now: public' -end - -local function unset_public_membermod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_member_lock = data[tostring(target)]['settings']['public'] - if group_member_lock == 'no' then - return 'Group is not public' - else - data[tostring(target)]['settings']['public'] = 'no' - save_data(_config.moderation.data, data) - return 'Group is now: not public' - end -end - -local function lock_group_leave(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local leave_ban = data[tostring(msg.to.id)]['settings']['leave_ban'] - if leave_ban == 'yes' then - return 'Leaving users will be banned' - else - data[tostring(msg.to.id)]['settings']['leave_ban'] = 'yes' - save_data(_config.moderation.data, data) - end - return 'Leaving users will be banned' -end - -local function unlock_group_leave(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local leave_ban = data[tostring(msg.to.id)]['settings']['leave_ban'] - if leave_ban == 'no' then - return 'Leaving users will not be banned' - else - data[tostring(msg.to.id)]['settings']['leave_ban'] = 'no' - save_data(_config.moderation.data, data) - return 'Leaving users will not be banned' - end -end - -local function unlock_group_photomod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local group_photo_lock = data[tostring(target)]['settings']['lock_photo'] - if group_photo_lock == 'no' then - return 'Group photo is not locked' - else - data[tostring(target)]['settings']['lock_photo'] = 'no' - save_data(_config.moderation.data, data) - return 'Group photo has been unlocked' - end -end - -local function set_rulesmod(msg, data, target) - if not is_momod(msg) then - return "For moderators only!" - end - local data_cat = 'rules' - data[tostring(target)][data_cat] = rules - save_data(_config.moderation.data, data) - return 'Set group rules to:\n'..rules -end -local function modadd(msg) - -- superuser and admins only (because sudo are always has privilege) - if not is_admin(msg) then - return "You're not admin" - end - local data = load_data(_config.moderation.data) - if is_group(msg) then - return 'Group is already added.' - end - receiver = get_receiver(msg) - chat_info(receiver, check_member_modadd,{receiver=receiver, data=data, msg = msg}) -end -local function realmadd(msg) - -- superuser and admins only (because sudo are always has privilege) - if not is_admin(msg) then - return "You're not admin" - end - local data = load_data(_config.moderation.data) - if is_realm(msg) then - return 'Realm is already added.' - end - receiver = get_receiver(msg) - chat_info(receiver, check_member_realm_add,{receiver=receiver, data=data, msg = msg}) -end --- Global functions -function modrem(msg) - -- superuser and admins only (because sudo are always has privilege) - if not is_admin(msg) then - return "You're not admin" - end - local data = load_data(_config.moderation.data) - if not is_group(msg) then - return 'Group is not added.' - end - receiver = get_receiver(msg) - chat_info(receiver, check_member_modrem,{receiver=receiver, data=data, msg = msg}) -end - -function realmrem(msg) - -- superuser and admins only (because sudo are always has privilege) - if not is_admin(msg) then - return "You're not admin" - end - local data = load_data(_config.moderation.data) - if not is_realm(msg) then - return 'Realm is not added.' - end - receiver = get_receiver(msg) - chat_info(receiver, check_member_realmrem,{receiver=receiver, data=data, msg = msg}) -end -local function get_rules(msg, data) - local data_cat = 'rules' - if not data[tostring(msg.to.id)][data_cat] then - return 'No rules available.' - end - local rules = data[tostring(msg.to.id)][data_cat] - local rules = 'Chat rules:\n'..rules - return rules -end - -local function set_group_photo(msg, success, result) - local data = load_data(_config.moderation.data) - local receiver = get_receiver(msg) - if success then - local file = 'data/photos/chat_photo_'..msg.to.id..'.jpg' - print('File downloaded to:', result) - os.rename(result, file) - print('File moved to:', file) - chat_set_photo (receiver, file, ok_cb, false) - data[tostring(msg.to.id)]['settings']['set_photo'] = file - save_data(_config.moderation.data, data) - data[tostring(msg.to.id)]['settings']['lock_photo'] = 'yes' - save_data(_config.moderation.data, data) - send_large_msg(receiver, 'Photo saved!', ok_cb, false) - else - print('Error downloading: '..msg.id) - send_large_msg(receiver, 'Failed, please try again!', ok_cb, false) - end -end - -local function promote(receiver, member_username, member_id) - local data = load_data(_config.moderation.data) - local group = string.gsub(receiver, 'chat#id', '') - if not data[group] then - return send_large_msg(receiver, 'Group is not added.') - end - if data[group]['moderators'][tostring(member_id)] then - return send_large_msg(receiver, member_username..' is already a moderator.') - end - data[group]['moderators'][tostring(member_id)] = member_username - save_data(_config.moderation.data, data) - return send_large_msg(receiver, member_username..' has been promoted.') -end - -local function promote_by_reply(extra, success, result) - local msg = result - local full_name = (msg.from.first_name or '')..' '..(msg.from.last_name or '') - if msg.from.username then - member_username = '@'.. msg.from.username - else - member_username = full_name - end - local member_id = msg.from.id - if msg.to.type == 'chat' then - return promote(get_receiver(msg), member_username, member_id) - end -end - -local function demote(receiver, member_username, member_id) - local data = load_data(_config.moderation.data) - local group = string.gsub(receiver, 'chat#id', '') - if not data[group] then - return send_large_msg(receiver, 'Group is not added.') - end - if not data[group]['moderators'][tostring(member_id)] then - return send_large_msg(receiver, member_username..' is not a moderator.') - end - data[group]['moderators'][tostring(member_id)] = nil - save_data(_config.moderation.data, data) - return send_large_msg(receiver, member_username..' has been demoted.') -end - -local function demote_by_reply(extra, success, result) - local msg = result - local full_name = (msg.from.first_name or '')..' '..(msg.from.last_name or '') - if msg.from.username then - member_username = '@'..msg.from.username - else - member_username = full_name - end - local member_id = msg.from.id - if msg.to.type == 'chat' then - return demote(get_receiver(msg), member_username, member_id) - end -end - -local function setowner_by_reply(extra, success, result) - local msg = result - local receiver = get_receiver(msg) - local data = load_data(_config.moderation.data) - local name_log = msg.from.print_name:gsub("_", " ") - data[tostring(msg.to.id)]['set_owner'] = tostring(msg.from.id) - save_data(_config.moderation.data, data) - savelog(msg.to.id, name_log.." ["..msg.from.id.."] setted ["..msg.from.id.."] as owner") - local text = msg.from.print_name:gsub("_", " ").." is the owner now" - return send_large_msg(receiver, text) -end - -local function promote_demote_res(extra, success, result) ---vardump(result) ---vardump(extra) - local member_id = result.id - local member_username = "@"..result.username - local chat_id = extra.chat_id - local mod_cmd = extra.mod_cmd - local receiver = "chat#id"..chat_id - if mod_cmd == 'promote' then - return promote(receiver, member_username, member_id) - elseif mod_cmd == 'demote' then - return demote(receiver, member_username, member_id) - end -end - -local function modlist(msg) - local data = load_data(_config.moderation.data) - local groups = "groups" - if not data[tostring(groups)][tostring(msg.to.id)] then - return 'Group is not added.' - end - -- determine if table is empty - if next(data[tostring(msg.to.id)]['moderators']) == nil then --fix way - return 'No moderator in this group.' - end - local i = 1 - local message = '\nList of moderators for ' .. string.gsub(msg.to.print_name, '_', ' ') .. ':\n' - for k,v in pairs(data[tostring(msg.to.id)]['moderators']) do - message = message ..i..' - '..v..' [' ..k.. '] \n' - i = i + 1 - end - return message -end - -local function callbackres(extra, success, result) ---vardump(result) - local user = result.id - local name = string.gsub(result.print_name, "_", " ") - local chat = 'chat#id'..extra.chatid - send_large_msg(chat, user..'\n'..name) - return user -end - - -local function help() - local help_text = tostring(_config.help_text) - return help_text -end - -local function cleanmember(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - for k,v in pairs(result.members) do - kick_user(v.id, result.id) - end -end - -local function killchat(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - for k,v in pairs(result.members) do - kick_user_any(v.id, result.id) - end -end - -local function killrealm(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - for k,v in pairs(result.members) do - kick_user_any(v.id, result.id) - end -end - -local function user_msgs(user_id, chat_id) - local user_info - local uhash = 'user:'..user_id - local user = redis:hgetall(uhash) - local um_hash = 'msgs:'..user_id..':'..chat_id - user_info = tonumber(redis:get(um_hash) or 0) - return user_info -end - -local function kick_zero(cb_extra, success, result) - local chat_id = cb_extra.chat_id - local chat = "chat#id"..chat_id - local ci_user - local re_user - for k,v in pairs(result.members) do - local si = false - ci_user = v.id - local hash = 'chat:'..chat_id..':users' - local users = redis:smembers(hash) - for i = 1, #users do - re_user = users[i] - if tonumber(ci_user) == tonumber(re_user) then - si = true - end - end - if not si then - if ci_user ~= our_id then - if not is_momod2(ci_user, chat_id) then - chat_del_user(chat, 'user#id'..ci_user, ok_cb, true) - end - end - end - end -end - -local function kick_inactive(chat_id, num, receiver) - local hash = 'chat:'..chat_id..':users' - local users = redis:smembers(hash) - -- Get user info - for i = 1, #users do - local user_id = users[i] - local user_info = user_msgs(user_id, chat_id) - local nmsg = user_info - if tonumber(nmsg) < tonumber(num) then - if not is_momod2(user_id, chat_id) then - chat_del_user('chat#id'..chat_id, 'user#id'..user_id, ok_cb, true) - end - end - end - return chat_info(receiver, kick_zero, {chat_id = chat_id}) -end - -local function run(msg, matches) - local data = load_data(_config.moderation.data) - local receiver = get_receiver(msg) - local name_log = user_print_name(msg.from) - local group = msg.to.id - if msg.media then - if msg.media.type == 'photo' and data[tostring(msg.to.id)]['settings']['set_photo'] == 'waiting' and is_chat_msg(msg) and is_momod(msg) then - load_photo(msg.id, set_group_photo, msg) - end - end - if matches[1] == 'add' and not matches[2] then - if is_realm(msg) then - return 'Error: Already a realm.' - end - print("group "..msg.to.print_name.."("..msg.to.id..") added") - return modadd(msg) - end - if matches[1] == 'add' and matches[2] == 'realm' then - if is_group(msg) then - return 'Error: Already a group.' - end - print("group "..msg.to.print_name.."("..msg.to.id..") added as a realm") - return realmadd(msg) - end - if matches[1] == 'rem' and not matches[2] then - print("group "..msg.to.print_name.."("..msg.to.id..") removed") - return modrem(msg) - end - if matches[1] == 'rem' and matches[2] == 'realm' then - print("group "..msg.to.print_name.."("..msg.to.id..") removed as a realm") - return realmrem(msg) - end - if matches[1] == 'chat_created' and msg.from.id == 0 and group_type == "group" then - return automodadd(msg) - end - if matches[1] == 'chat_created' and msg.from.id == 0 and group_type == "realm" then - return autorealmadd(msg) - end - - if msg.to.id and data[tostring(msg.to.id)] then - local settings = data[tostring(msg.to.id)]['settings'] - if matches[1] == 'chat_add_user' then - if not msg.service then - return "Are you trying to troll me?" - end - local group_member_lock = settings.lock_member - local user = 'user#id'..msg.action.user.id - local chat = 'chat#id'..msg.to.id - if group_member_lock == 'yes' and not is_owner2(msg.action.user.id, msg.to.id) then - chat_del_user(chat, user, ok_cb, true) - elseif group_member_lock == 'yes' and tonumber(msg.from.id) == tonumber(our_id) then - return nil - elseif group_member_lock == 'no' then - return nil - end - end - if matches[1] == 'chat_del_user' then - if not msg.service then - -- return "Are you trying to troll me?" - end - local user = 'user#id'..msg.action.user.id - local chat = 'chat#id'..msg.to.id - savelog(msg.to.id, name_log.." ["..msg.from.id.."] deleted user "..user) - end - if matches[1] == 'chat_delete_photo' then - if not msg.service then - return "Are you trying to troll me?" - end - local group_photo_lock = settings.lock_photo - if group_photo_lock == 'yes' then - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - redis:incr(picturehash) - --- - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - local picprotectionredis = redis:get(picturehash) - if picprotectionredis then - if tonumber(picprotectionredis) == 4 and not is_owner(msg) then - kick_user(msg.from.id, msg.to.id) - end - if tonumber(picprotectionredis) == 8 and not is_owner(msg) then - ban_user(msg.from.id, msg.to.id) - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - redis:set(picturehash, 0) - end - end - - savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to deleted picture but failed ") - chat_set_photo(receiver, settings.set_photo, ok_cb, false) - elseif group_photo_lock == 'no' then - return nil - end - end - if matches[1] == 'chat_change_photo' and msg.from.id ~= 0 then - if not msg.service then - return "Are you trying to troll me?" - end - local group_photo_lock = settings.lock_photo - if group_photo_lock == 'yes' then - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - redis:incr(picturehash) - --- - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - local picprotectionredis = redis:get(picturehash) - if picprotectionredis then - if tonumber(picprotectionredis) == 4 and not is_owner(msg) then - kick_user(msg.from.id, msg.to.id) - end - if tonumber(picprotectionredis) == 8 and not is_owner(msg) then - ban_user(msg.from.id, msg.to.id) - local picturehash = 'picture:changed:'..msg.to.id..':'..msg.from.id - redis:set(picturehash, 0) - end - end - - savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to change picture but failed ") - chat_set_photo(receiver, settings.set_photo, ok_cb, false) - elseif group_photo_lock == 'no' then - return nil - end - end - if matches[1] == 'chat_rename' then - if not msg.service then - return "Are you trying to troll me?" - end - local group_name_set = settings.set_name - local group_name_lock = settings.lock_name - local to_rename = 'chat#id'..msg.to.id - if group_name_lock == 'yes' then - if group_name_set ~= tostring(msg.to.print_name) then - local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id - redis:incr(namehash) - local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id - local nameprotectionredis = redis:get(namehash) - if nameprotectionredis then - if tonumber(nameprotectionredis) == 4 and not is_owner(msg) then - kick_user(msg.from.id, msg.to.id) - end - if tonumber(nameprotectionredis) == 8 and not is_owner(msg) then - ban_user(msg.from.id, msg.to.id) - local namehash = 'name:changed:'..msg.to.id..':'..msg.from.id - redis:set(namehash, 0) - end - end - - savelog(msg.to.id, name_log.." ["..msg.from.id.."] tried to change name but failed ") - rename_chat(to_rename, group_name_set, ok_cb, false) - end - elseif group_name_lock == 'no' then - return nil - end - end - if matches[1] == 'setname' and is_momod(msg) then - local new_name = string.gsub(matches[2], '_', ' ') - data[tostring(msg.to.id)]['settings']['set_name'] = new_name - save_data(_config.moderation.data, data) - local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] - local to_rename = 'chat#id'..msg.to.id - rename_chat(to_rename, group_name_set, ok_cb, false) - - savelog(msg.to.id, "Group { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]") - end - if matches[1] == 'setphoto' and is_momod(msg) then - data[tostring(msg.to.id)]['settings']['set_photo'] = 'waiting' - save_data(_config.moderation.data, data) - return 'Please send me new group photo now' - end - if matches[1] == 'promote' and not matches[2] then - if not is_owner(msg) then - return "Only the owner can prmote new moderators" - end - if type(msg.reply_id)~="nil" then - msgr = get_message(msg.reply_id, promote_by_reply, false) - end - end - if matches[1] == 'promote' and matches[2] then - if not is_momod(msg) then - return - end - if not is_owner(msg) then - return "Only owner can promote" - end - local member = matches[2] - savelog(msg.to.id, name_log.." ["..msg.from.id.."] promoted @".. member) - local cbres_extra = { - chat_id = msg.to.id, - mod_cmd = 'promote', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - return res_user(username, promote_demote_res, cbres_extra) - end - if matches[1] == 'demote' and not matches[2] then - if not is_owner(msg) then - return "Only the owner can demote moderators" - end - if type(msg.reply_id)~="nil" then - msgr = get_message(msg.reply_id, demote_by_reply, false) - end - end - if matches[1] == 'demote' and matches[2] then - if not is_momod(msg) then - return - end - if not is_owner(msg) then - return "Only owner can demote" - end - if string.gsub(matches[2], "@", "") == msg.from.username and not is_owner(msg) then - return "You can't demote yourself" - end - local member = matches[2] - savelog(msg.to.id, name_log.." ["..msg.from.id.."] demoted @".. member) - local cbres_extra = { - chat_id = msg.to.id, - mod_cmd = 'demote', - from_id = msg.from.id - } - local username = matches[2] - local username = string.gsub(matches[2], '@', '') - return res_user(username, promote_demote_res, cbres_extra) - end - if matches[1] == 'modlist' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group modlist") - return modlist(msg) - end - if matches[1] == 'about' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group description") - return get_description(msg, data) - end - if matches[1] == 'rules' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group rules") - return get_rules(msg, data) - end - if matches[1] == 'set' then - if matches[2] == 'rules' then - rules = matches[3] - local target = msg.to.id - savelog(msg.to.id, name_log.." ["..msg.from.id.."] has changed group rules to ["..matches[3].."]") - return set_rulesmod(msg, data, target) - end - if matches[2] == 'about' then - local data = load_data(_config.moderation.data) - local target = msg.to.id - local about = matches[3] - savelog(msg.to.id, name_log.." ["..msg.from.id.."] has changed group description to ["..matches[3].."]") - return set_descriptionmod(msg, data, target, about) - end - end - if matches[1] == 'lock' then - local target = msg.to.id - if matches[2] == 'name' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked name ") - return lock_group_namemod(msg, data, target) - end - if matches[2] == 'member' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked member ") - return lock_group_membermod(msg, data, target) - end - if matches[2] == 'flood' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked flood ") - return lock_group_floodmod(msg, data, target) - end - if matches[2] == 'arabic' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked arabic ") - return lock_group_arabic(msg, data, target) - end - if matches[2] == 'bots' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked bots ") - return lock_group_bots(msg, data, target) - end - if matches[2] == 'leave' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] locked leaving ") - return lock_group_leave(msg, data, target) - end - end - if matches[1] == 'unlock' then - local target = msg.to.id - if matches[2] == 'name' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked name ") - return unlock_group_namemod(msg, data, target) - end - if matches[2] == 'member' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked member ") - return unlock_group_membermod(msg, data, target) - end - if matches[2] == 'photo' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked photo ") - return unlock_group_photomod(msg, data, target) - end - if matches[2] == 'flood' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked flood ") - return unlock_group_floodmod(msg, data, target) - end - if matches[2] == 'arabic' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked arabic ") - return unlock_group_arabic(msg, data, target) - end - if matches[2] == 'bots' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked bots ") - return unlock_group_bots(msg, data, target) - end - if matches[2] == 'leave' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] unlocked leaving ") - return unlock_group_leave(msg, data, target) - end - end - if matches[1] == 'settings' then - local target = msg.to.id - savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group settings ") - return show_group_settingsmod(msg, data, target) - end - - --[[if matches[1] == 'public' then - local target = msg.to.id - if matches[2] == 'yes' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] set group to: public") - return set_public_membermod(msg, data, target) - end - if matches[2] == 'no' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] set group to: not public") - return unset_public_membermod(msg, data, target) - end - end]] - - if matches[1] == 'newlink' and not is_realm(msg) then - if not is_momod(msg) then - return "For moderators only!" - end - local function callback (extra , success, result) - local receiver = 'chat#'..msg.to.id - if success == 0 then - return send_large_msg(receiver, '*Error: Invite link failed* \nReason: Not creator.') - end - send_large_msg(receiver, "Created a new link") - data[tostring(msg.to.id)]['settings']['set_link'] = result - save_data(_config.moderation.data, data) - end - local receiver = 'chat#'..msg.to.id - savelog(msg.to.id, name_log.." ["..msg.from.id.."] revoked group link ") - return export_chat_link(receiver, callback, true) - end - if matches[1] == 'link' then - if not is_momod(msg) then - return "For moderators only!" - end - local group_link = data[tostring(msg.to.id)]['settings']['set_link'] - if not group_link then - return "Create a link using /newlink first !" - end - savelog(msg.to.id, name_log.." ["..msg.from.id.."] requested group link ["..group_link.."]") - return "Group link:\n"..group_link - end - if matches[1] == 'setowner' and matches[2] then - if not is_owner(msg) then - return "For owner only!" - end - data[tostring(msg.to.id)]['set_owner'] = matches[2] - save_data(_config.moderation.data, data) - savelog(msg.to.id, name_log.." ["..msg.from.id.."] set ["..matches[2].."] as owner") - local text = matches[2].." added as owner" - return text - end - if matches[1] == 'setowner' and not matches[2] then - if not is_owner(msg) then - return "only for the owner!" - end - if type(msg.reply_id)~="nil" then - msgr = get_message(msg.reply_id, setowner_by_reply, false) - end - end - if matches[1] == 'owner' then - local group_owner = data[tostring(msg.to.id)]['set_owner'] - local user_info = redis:hgetall('user:'..group_owner) - if not group_owner then - return "no owner,ask admins in support groups to set owner for your group" - end - savelog(msg.to.id, name_log.." ["..msg.from.id.."] used /owner") - if user_info.username then - return "Group onwer is @"..user_info.username.." ["..group_owner.."]" - else - return "Group owner is ["..group_owner..']' - end - end - if matches[1] == 'setgpowner' then - local receiver = "chat#id"..matches[2] - if not is_admin(msg) then - return "For admins only!" - end - data[tostring(matches[2])]['set_owner'] = matches[3] - save_data(_config.moderation.data, data) - local text = matches[3].." added as owner" - send_large_msg(receiver, text) - return - end - if matches[1] == 'setflood' then - if not is_momod(msg) then - return "For moderators only!" - end - if tonumber(matches[2]) < 5 or tonumber(matches[2]) > 20 then - return "Wrong number,range is [5-20]" - end - local flood_max = matches[2] - data[tostring(msg.to.id)]['settings']['flood_msg_max'] = flood_max - save_data(_config.moderation.data, data) - savelog(msg.to.id, name_log.." ["..msg.from.id.."] set flood to ["..matches[2].."]") - return 'Group flood has been set to '..matches[2] - end - if matches[1] == 'clean' then - if not is_owner(msg) then - return "Only owner can clean" - end - if matches[2] == 'member' then - if not is_owner(msg) then - return "Only admins can clean members" - end - local receiver = get_receiver(msg) - chat_info(receiver, cleanmember, {receiver=receiver}) - end - if matches[2] == 'modlist' then - if next(data[tostring(msg.to.id)]['moderators']) == nil then --fix way - return 'No moderator in this group.' - end - local message = '\nList of moderators for ' .. string.gsub(msg.to.print_name, '_', ' ') .. ':\n' - for k,v in pairs(data[tostring(msg.to.id)]['moderators']) do - data[tostring(msg.to.id)]['moderators'][tostring(k)] = nil - save_data(_config.moderation.data, data) - end - savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned modlist") - end - if matches[2] == 'rules' then - local data_cat = 'rules' - data[tostring(msg.to.id)][data_cat] = nil - save_data(_config.moderation.data, data) - savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned rules") - end - if matches[2] == 'about' then - local data_cat = 'description' - data[tostring(msg.to.id)][data_cat] = nil - save_data(_config.moderation.data, data) - savelog(msg.to.id, name_log.." ["..msg.from.id.."] cleaned about") - end - end - if matches[1] == 'kill' and matches[2] == 'chat' then - if not is_admin(msg) then - return nil - end - if not is_realm(msg) then - local receiver = get_receiver(msg) - return modrem(msg), - print("Closing Group..."), - chat_info(receiver, killchat, {receiver=receiver}) - else - return 'This is a realm' - end - end - if matches[1] == 'kill' and matches[2] == 'realm' then - if not is_admin(msg) then - return nil - end - if not is_group(msg) then - local receiver = get_receiver(msg) - return realmrem(msg), - print("Closing Realm..."), - chat_info(receiver, killrealm, {receiver=receiver}) - else - return 'This is a group' - end - end - if matches[1] == 'help' then - if not is_momod(msg) or is_realm(msg) then - return - end - savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /help") - return help() - end - if matches[1] == 'res' and is_momod(msg) then - local cbres_extra = { - chatid = msg.to.id - } - local username = matches[2] - local username = username:gsub("@","") - savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /res "..username) - return res_user(username, callbackres, cbres_extra) - end - if matches[1] == 'kickinactive' then - --send_large_msg('chat#id'..msg.to.id, 'I\'m in matches[1]') - if not is_momod(msg) then - return 'Only a moderator can kick inactive users' - end - local num = 1 - if matches[2] then - num = matches[2] - end - local chat_id = msg.to.id - local receiver = get_receiver(msg) - return kick_inactive(chat_id, num, receiver) - end - end -end - -return { - patterns = { - "^[!/](add)$", - "^[!/](add) (realm)$", - "^[!/](rem)$", - "^[!/](rem) (realm)$", - "^[!/](rules)$", - "^[!/](about)$", - "^[!/](setname) (.*)$", - "^[!/](setphoto)$", - "^[!/](promote) (.*)$", - "^[!/](promote)", - "^[!/](help)$", - "^[!/](clean) (.*)$", - "^[!/](kill) (chat)$", - "^[!/](kill) (realm)$", - "^[!/](demote) (.*)$", - "^[!/](demote)", - "^[!/](set) ([^%s]+) (.*)$", - "^[!/](lock) (.*)$", - "^[!/](setowner) (%d+)$", - "^[!/](setowner)", - "^[!/](owner)$", - "^[!/](res) (.*)$", - "^[!/](setgpowner) (%d+) (%d+)$",-- (group id) (owner id) - "^[!/](unlock) (.*)$", - "^[!/](setflood) (%d+)$", - "^[!/](settings)$", --- "^[!/](public) (.*)$", - "^[!/](modlist)$", - "^[!/](newlink)$", - "^[!/](link)$", - "^[!/](kickinactive)$", - "^[!/](kickinactive) (%d+)$", - "%[(photo)%]", - "^!!tgservice (.+)$", - }, - run = run -} -end - - diff --git a/plugins/inpm.lua b/plugins/inpm.lua deleted file mode 100644 index 5c031f6..0000000 --- a/plugins/inpm.lua +++ /dev/null @@ -1,90 +0,0 @@ -do -local function pairsByKeys (t, f) - local a = {} - for n in pairs(t) do table.insert(a, n) end - table.sort(a, f) - local i = 0 -- iterator variable - local iter = function () -- iterator function - i = i + 1 - if a[i] == nil then return nil - else return a[i], t[a[i]] - end - end - return iter - end - -local function chat_list(msg) - local data = load_data(_config.moderation.data) - local groups = 'groups' - if not data[tostring(groups)] then - return 'No groups at the moment' - end - local message = 'List of Groups:\n*Use /join (ID) to join*\n\n ' - for k,v in pairs(data[tostring(groups)]) do - local settings = data[tostring(v)]['settings'] - for m,n in pairsByKeys(settings) do - if m == 'set_name' then - name = n - end - end - - message = message .. 'šŸ‘„ '.. name .. ' (ID: ' .. v .. ')\n\n ' - end - local file = io.open("./groups/lists/listed_groups.txt", "w") - file:write(message) - file:flush() - file:close() - return message -end - -local function run(msg, matches) - if msg.to.type ~= 'chat' or is_sudo(msg) or is_admin(msg) and is_realm(msg) then - local data = load_data(_config.moderation.data) - if matches[1] == 'join' and data[tostring(matches[2])] then - if is_banned(msg.from.id, matches[2]) then - return 'You are banned.' - end - if is_gbanned(msg.from.id) then - return 'You are globally banned.' - end - if data[tostring(matches[2])]['settings']['lock_member'] == 'yes' and not is_owner2(msg.from.id, matches[2]) then - return 'Group is private.' - end - local chat_id = "chat#id"..matches[2] - local user_id = "user#id"..msg.from.id - chat_add_user(chat_id, user_id, ok_cb, false) - local group_name = data[tostring(matches[2])]['settings']['set_name'] - return "Added you to chat:\n\nšŸ‘„"..group_name.." (ID:"..matches[2]..")" - elseif matches[1] == 'join' and not data[tostring(matches[2])] then - - return "Chat not found." - end - if matches[1] == 'chats'then - if is_admin(msg) and msg.to.type == 'chat' then - return chat_list(msg) - elseif msg.to.type ~= 'chat' then - return chat_list(msg) - end - end - if matches[1] == 'chatlist'then - if is_admin(msg) and msg.to.type == 'chat' then - send_document("chat#id"..msg.from.id, "./groups/lists/listed_groups.txt", ok_cb, false) - elseif msg.to.type ~= 'chat' then - send_document("user#id"..msg.from.id, "./groups/lists/listed_groups.txt", ok_cb, false) - end - end -end -end - -return { - patterns = { - "^[/!](chats)$", - "^[/!](chatlist)$", - "^[/!](join) (.*)$", - "^[/!](kickme) (.*)$", - "^!!tgservice (chat_add_user)$" - }, - run = run, -} -end - diff --git a/plugins/inrealm.lua b/plugins/inrealm.lua deleted file mode 100644 index 3388fa7..0000000 --- a/plugins/inrealm.lua +++ /dev/null @@ -1,687 +0,0 @@ --- data saved to moderation.json --- check moderation plugin -do - -local function create_group(msg) - -- superuser and admins only (because sudo are always has privilege) - if is_sudo(msg) or is_realm(msg) and is_admin(msg) then - local group_creator = msg.from.print_name - create_group_chat (group_creator, group_name, ok_cb, false) - return 'Group [ '..string.gsub(group_name, '_', ' ')..' ] has been created.' - end -end - -local function create_realm(msg) - -- superuser and admins only (because sudo are always has privilege) - if is_sudo(msg) or is_realm(msg) and is_admin(msg) then - local group_creator = msg.from.print_name - create_group_chat (group_creator, group_name, ok_cb, false) - return 'Realm [ '..string.gsub(group_name, '_', ' ')..' ] has been created.' - end -end - - -local function killchat(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - for k,v in pairs(result.members) do - kick_user_any(v.id, result.id) - end -end - -local function killrealm(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - for k,v in pairs(result.members) do - kick_user_any(v.id, result.id) - end -end - -local function get_group_type(msg) - local data = load_data(_config.moderation.data) - if data[tostring(msg.to.id)] then - if not data[tostring(msg.to.id)]['group_type'] then - return 'No group type available.' - end - local group_type = data[tostring(msg.to.id)]['group_type'] - return group_type - else - return 'Chat type not found.' - end -end - -local function callbackres(extra, success, result) ---vardump(result) - local user = result.id - local name = string.gsub(result.print_name, "_", " ") - local chat = 'chat#id'..extra.chatid - send_large_msg(chat, user..'\n'..name) - return user -end - -local function set_description(msg, data, target, about) - if not is_admin(msg) then - return "For admins only!" - end - local data_cat = 'description' - data[tostring(target)][data_cat] = about - save_data(_config.moderation.data, data) - return 'Set group description to:\n'..about -end - -local function set_rules(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local data_cat = 'rules' - data[tostring(target)][data_cat] = rules - save_data(_config.moderation.data, data) - return 'Set group rules to:\n'..rules -end --- lock/unlock group name. bot automatically change group name when locked -local function lock_group_name(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'yes' then - return 'Group name is already locked' - else - data[tostring(target)]['settings']['lock_name'] = 'yes' - save_data(_config.moderation.data, data) - rename_chat('chat#id'..target, group_name_set, ok_cb, false) - return 'Group name has been locked' - end -end - -local function unlock_group_name(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'no' then - return 'Group name is already unlocked' - else - data[tostring(target)]['settings']['lock_name'] = 'no' - save_data(_config.moderation.data, data) - return 'Group name has been unlocked' - end -end ---lock/unlock group member. bot automatically kick new added user when locked -local function lock_group_member(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'yes' then - return 'Group members are already locked' - else - data[tostring(target)]['settings']['lock_member'] = 'yes' - save_data(_config.moderation.data, data) - end - return 'Group members has been locked' -end - -local function unlock_group_member(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'no' then - return 'Group members are not locked' - else - data[tostring(target)]['settings']['lock_member'] = 'no' - save_data(_config.moderation.data, data) - return 'Group members has been unlocked' - end -end - ---lock/unlock group photo. bot automatically keep group photo when locked -local function lock_group_photo(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_photo_lock = data[tostring(target)]['settings']['lock_photo'] - if group_photo_lock == 'yes' then - return 'Group photo is already locked' - else - data[tostring(target)]['settings']['set_photo'] = 'waiting' - save_data(_config.moderation.data, data) - end - return 'Please send me the group photo now' -end - -local function unlock_group_photo(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_photo_lock = data[tostring(target)]['settings']['lock_photo'] - if group_photo_lock == 'no' then - return 'Group photo is not locked' - else - data[tostring(target)]['settings']['lock_photo'] = 'no' - save_data(_config.moderation.data, data) - return 'Group photo has been unlocked' - end -end - -local function lock_group_flood(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'yes' then - return 'Group flood is locked' - else - data[tostring(target)]['settings']['flood'] = 'yes' - save_data(_config.moderation.data, data) - return 'Group flood has been locked' - end -end - -local function unlock_group_flood(msg, data, target) - if not is_admin(msg) then - return "For admins only!" - end - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'no' then - return 'Group flood is not locked' - else - data[tostring(target)]['settings']['flood'] = 'no' - save_data(_config.moderation.data, data) - return 'Group flood has been unlocked' - end -end --- show group settings -local function show_group_settings(msg, data, target) - local data = load_data(_config.moderation.data, data) - if not is_admin(msg) then - return "For admins only!" - end - local settings = data[tostring(target)]['settings'] - local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member - return text -end - -local function returnids(cb_extra, success, result) - - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - local text = 'Users in '..string.gsub(chatname,"_"," ")..' ('..result.id..'):'..'\n'..'' - for k,v in pairs(result.members) do - if v.print_name then - local username = "" - text = text .. "- " .. string.gsub(v.print_name,"_"," ") .. " (" .. v.id .. ") \n" - end - end - send_large_msg(receiver, text) - local file = io.open("./groups/lists/"..result.id.."memberlist.txt", "w") - file:write(text) - file:flush() - file:close() -end - -local function returnidsfile(cb_extra, success, result) - local receiver = cb_extra.receiver - local chat_id = "chat#id"..result.id - local chatname = result.print_name - local text = 'Users in '..string.gsub(chatname,"_"," ")..' ('..result.id..'):'..'\n'..'' - for k,v in pairs(result.members) do - if v.print_name then - local username = "" - text = text .. "- " .. string.gsub(v.print_name,"_"," ") .. " (" .. v.id .. ") \n" - end - end - local file = io.open("./groups/lists/"..result.id.."memberlist.txt", "w") - file:write(text) - file:flush() - file:close() - send_document("chat#id"..result.id,"./groups/lists/"..result.id.."memberlist.txt", ok_cb, false) -end - -local function admin_promote(msg, admin_id) - if not is_sudo(msg) then - return "Access denied!" - end - local admins = 'admins' - if not data[tostring(admins)] then - data[tostring(admins)] = {} - save_data(_config.moderation.data, data) - end - if data[tostring(admins)][tostring(admin_id)] then - return admin_name..' is already an admin.' - end - data[tostring(admins)][tostring(admin_id)] = admin_id - save_data(_config.moderation.data, data) - return admin_id..' has been promoted as admin.' -end - -local function admin_demote(msg, admin_id) - if not is_sudo(msg) then - return "Access denied!" - end - local data = load_data(_config.moderation.data) - local admins = 'admins' - if not data[tostring(admins)] then - data[tostring(admins)] = {} - save_data(_config.moderation.data, data) - end - if not data[tostring(admins)][tostring(admin_id)] then - return admin_id..' is not an admin.' - end - data[tostring(admins)][tostring(admin_id)] = nil - save_data(_config.moderation.data, data) - return admin_id..' has been demoted from admin.' -end - -local function admin_list(msg) - local data = load_data(_config.moderation.data) - local admins = 'admins' - if not data[tostring(admins)] then - data[tostring(admins)] = {} - save_data(_config.moderation.data, data) - end - local message = 'List for Realm admins:\n' - for k,v in pairs(data[tostring(admins)]) do - message = message .. '- (at)' .. v .. ' [' .. k .. '] ' ..'\n' - end - return message -end - -local function groups_list(msg) - local data = load_data(_config.moderation.data) - local groups = 'groups' - if not data[tostring(groups)] then - return 'No groups at the moment' - end - local message = 'List of groups:\n' - for k,v in pairs(data[tostring(groups)]) do - local settings = data[tostring(v)]['settings'] - for m,n in pairs(settings) do - if m == 'set_name' then - name = n - end - end - local group_owner = "No owner" - if data[tostring(v)]['set_owner'] then - group_owner = tostring(data[tostring(v)]['set_owner']) - end - local group_link = "No link" - if data[tostring(v)]['settings']['set_link'] then - group_link = data[tostring(v)]['settings']['set_link'] - end - - message = message .. '- '.. name .. ' (' .. v .. ') ['..group_owner..'] \n {'..group_link.."}\n" - - - end - local file = io.open("./groups/lists/groups.txt", "w") - file:write(message) - file:flush() - file:close() - return message - -end -local function realms_list(msg) - local data = load_data(_config.moderation.data) - local realms = 'realms' - if not data[tostring(realms)] then - return 'No Realms at the moment' - end - local message = 'List of Realms:\n' - for k,v in pairs(data[tostring(realms)]) do - local settings = data[tostring(v)]['settings'] - for m,n in pairs(settings) do - if m == 'set_name' then - name = n - end - end - local group_owner = "No owner" - if data[tostring(v)]['admins_in'] then - group_owner = tostring(data[tostring(v)]['admins_in']) - end - local group_link = "No link" - if data[tostring(v)]['settings']['set_link'] then - group_link = data[tostring(v)]['settings']['set_link'] - end - message = message .. '- '.. name .. ' (' .. v .. ') ['..group_owner..'] \n {'..group_link.."}\n" - end - local file = io.open("./groups/lists/realms.txt", "w") - file:write(message) - file:flush() - file:close() - return message -end -local function admin_user_promote(receiver, member_username, member_id) - local data = load_data(_config.moderation.data) - if not data['admins'] then - data['admins'] = {} - save_data(_config.moderation.data, data) - end - if data['admins'][tostring(member_id)] then - return send_large_msg(receiver, member_username..' is already as admin.') - end - data['admins'][tostring(member_id)] = member_username - save_data(_config.moderation.data, data) - return send_large_msg(receiver, '@'..member_username..' has been promoted as admin.') -end - -local function admin_user_demote(receiver, member_username, member_id) - local data = load_data(_config.moderation.data) - if not data['admins'] then - data['admins'] = {} - save_data(_config.moderation.data, data) - end - if not data['admins'][tostring(member_id)] then - return send_large_msg(receiver, member_username..' is not an admin.') - end - data['admins'][tostring(member_id)] = nil - save_data(_config.moderation.data, data) - return send_large_msg(receiver, 'Admin '..member_username..' has been demoted.') -end - - -local function username_id(cb_extra, success, result) - local mod_cmd = cb_extra.mod_cmd - local receiver = cb_extra.receiver - local member = cb_extra.member - local text = 'No user @'..member..' in this group.' - for k,v in pairs(result.members) do - vusername = v.username - if vusername == member then - member_username = member - member_id = v.id - if mod_cmd == 'addadmin' then - return admin_user_promote(receiver, member_username, member_id) - elseif mod_cmd == 'removeadmin' then - return admin_user_demote(receiver, member_username, member_id) - end - end - end - send_large_msg(receiver, text) -end - -local function set_log_group(msg) - if not is_admin(msg) then - return - end - local log_group = data[tostring(groups)][tostring(msg.to.id)]['log_group'] - if log_group == 'yes' then - return 'Log group is already set' - else - data[tostring(groups)][tostring(msg.to.id)]['log_group'] = 'yes' - save_data(_config.moderation.data, data) - return 'Log group has been set' - end -end - -local function unset_log_group(msg) - if not is_admin(msg) then - return - end - local log_group = data[tostring(groups)][tostring(msg.to.id)]['log_group'] - if log_group == 'no' then - return 'Log group is already disabled' - else - data[tostring(groups)][tostring(msg.to.id)]['log_group'] = 'no' - save_data(_config.moderation.data, data) - return 'log group has been disabled' - end -end - -local function help() - local help_text = tostring(_config.help_text_realm) - return help_text -end - -function run(msg, matches) - --vardump(msg) - local name_log = user_print_name(msg.from) - if matches[1] == 'log' and is_owner(msg) then - savelog(msg.to.id, "log file created by owner") - send_document("chat#id"..msg.to.id,"./groups/"..msg.to.id.."log.txt", ok_cb, false) - end - - if matches[1] == 'who' and is_momod(msg) then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] requested member list ") - local receiver = get_receiver(msg) - chat_info(receiver, returnidsfile, {receiver=receiver}) - end - if matches[1] == 'wholist' and is_momod(msg) then - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] requested member list in a file") - local receiver = get_receiver(msg) - chat_info(receiver, returnids, {receiver=receiver}) - end - - if matches[1] == 'creategroup' and matches[2] then - group_name = matches[2] - group_type = 'group' - return create_group(msg) - end - - if not is_sudo(msg) or not is_admin(msg) and not is_realm(msg) then - return --Do nothing - end - - if matches[1] == 'createrealm' and matches[2] then - group_name = matches[2] - group_type = 'realm' - return create_realm(msg) - end - - local data = load_data(_config.moderation.data) - local receiver = get_receiver(msg) - if matches[2] then if data[tostring(matches[2])] then - local settings = data[tostring(matches[2])]['settings'] - if matches[1] == 'setabout' and matches[2] then - local target = matches[2] - local about = matches[3] - return set_description(msg, data, target, about) - end - if matches[1] == 'setrules' then - rules = matches[3] - local target = matches[2] - return set_rules(msg, data, target) - end - if matches[1] == 'lock' then --group lock * - local target = matches[2] - if matches[3] == 'name' then - return lock_group_name(msg, data, target) - end - if matches[3] == 'member' then - return lock_group_member(msg, data, target) - end - if matches[3] == 'photo' then - return lock_group_photo(msg, data, target) - end - if matches[3] == 'flood' then - return lock_group_flood(msg, data, target) - end - end - if matches[1] == 'unlock' then --group unlock * - local target = matches[2] - if matches[3] == 'name' then - return unlock_group_name(msg, data, target) - end - if matches[3] == 'member' then - return unlock_group_member(msg, data, target) - end - if matches[3] == 'photo' then - return unlock_group_photo(msg, data, target) - end - if matches[3] == 'flood' then - return unlock_group_flood(msg, data, target) - end - end - if matches[1] == 'settings' and data[tostring(matches[2])]['settings'] then - local target = matches[2] - return show_group_settings(msg, data, target) - end - - if matches[1] == 'setname' and is_realm(msg) then - local new_name = string.gsub(matches[2], '_', ' ') - data[tostring(msg.to.id)]['settings']['set_name'] = new_name - save_data(_config.moderation.data, data) - local group_name_set = data[tostring(msg.to.id)]['settings']['set_name'] - local to_rename = 'chat#id'..msg.to.id - rename_chat(to_rename, group_name_set, ok_cb, false) - savelog(msg.to.id, "Realm { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]") - end - if matches[1] == 'setgpname' and is_admin(msg) then - local new_name = string.gsub(matches[3], '_', ' ') - data[tostring(matches[2])]['settings']['set_name'] = new_name - save_data(_config.moderation.data, data) - local group_name_set = data[tostring(matches[2])]['settings']['set_name'] - local to_rename = 'chat#id'..matches[2] - rename_chat(to_rename, group_name_set, ok_cb, false) - savelog(msg.to.id, "Group { "..msg.to.print_name.." } name changed to [ "..new_name.." ] by "..name_log.." ["..msg.from.id.."]") - end - - end - end - if matches[1] == 'help' and is_realm(msg) then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /help") - return help() - end - if matches[1] == 'set' then - if matches[2] == 'loggroup' then - savelog(msg.to.id, name_log.." ["..msg.from.id.."] set as log group") - return set_log_group(msg) - end - end - if matches[1] == 'kill' and matches[2] == 'chat' then - if not is_admin(msg) then - return nil - end - if is_realm(msg) then - local receiver = 'chat#id'..matches[3] - return modrem(msg), - print("Closing Group: "..receiver), - chat_info(receiver, killchat, {receiver=receiver}) - else - return 'Error: Group '..matches[3]..' not found' - end - end - if matches[1] == 'kill' and matches[2] == 'realm' then - if not is_admin(msg) then - return nil - end - if is_realm(msg) then - local receiver = 'chat#id'..matches[3] - return realmrem(msg), - print("Closing realm: "..receiver), - chat_info(receiver, killrealm, {receiver=receiver}) - else - return 'Error: Realm '..matches[3]..' not found' - end - end - if matches[1] == 'chat_add_user' then - if not msg.service then - return "Are you trying to troll me?" - end - local user = 'user#id'..msg.action.user.id - local chat = 'chat#id'..msg.to.id - if not is_admin(msg) then - chat_del_user(chat, user, ok_cb, true) - end - end - if matches[1] == 'addadmin' then - if string.match(matches[2], '^%d+$') then - local admin_id = matches[2] - print("user "..admin_id.." has been promoted as admin") - return admin_promote(msg, admin_id) - else - local member = string.gsub(matches[2], "@", "") - local mod_cmd = "addadmin" - chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member}) - end - end - if matches[1] == 'removeadmin' then - if string.match(matches[2], '^%d+$') then - local admin_id = matches[2] - print("user "..admin_id.." has been demoted") - return admin_demote(msg, admin_id) - else - local member = string.gsub(matches[2], "@", "") - local mod_cmd = "removeadmin" - chat_info(receiver, username_id, {mod_cmd= mod_cmd, receiver=receiver, member=member}) - end - end - if matches[1] == 'type'then - local group_type = get_group_type(msg) - return group_type - end - if matches[1] == 'list' and matches[2] == 'admins' then - return admin_list(msg) - end - if matches[1] == 'list' and matches[2] == 'groups' then - if msg.to.type == 'chat' then - groups_list(msg) - send_document("chat#id"..msg.to.id, "./groups/lists/groups.txt", ok_cb, false) - return "Group list created" --group_list(msg) - elseif msg.to.type == 'user' then - groups_list(msg) - send_document("user#id"..msg.from.id, "./groups/lists/groups.txt", ok_cb, false) - return "Group list created" --group_list(msg) - end - end - if matches[1] == 'list' and matches[2] == 'realms' then - if msg.to.type == 'chat' then - realms_list(msg) - send_document("chat#id"..msg.to.id, "./groups/lists/realms.txt", ok_cb, false) - return "Realms list created" --realms_list(msg) - elseif msg.to.type == 'user' then - realms_list(msg) - send_document("user#id"..msg.from.id, "./groups/lists/realms.txt", ok_cb, false) - return "Realms list created" --realms_list(msg) - end - end - if matches[1] == 'res' and is_momod(msg) then - local cbres_extra = { - chatid = msg.to.id - } - local username = matches[2] - local username = username:gsub("@","") - savelog(msg.to.id, name_log.." ["..msg.from.id.."] Used /res "..username) - return res_user(username, callbackres, cbres_extra) - end -end - - - -return { - patterns = { - "^[!/](creategroup) (.*)$", - "^[!/](createrealm) (.*)$", - "^[!/](setabout) (%d+) (.*)$", - "^[!/](setrules) (%d+) (.*)$", - "^[!/](setname) (.*)$", - "^[!/](setgpname) (%d+) (.*)$", - "^[!/](setname) (%d+) (.*)$", - "^[!/](lock) (%d+) (.*)$", - "^[!/](unlock) (%d+) (.*)$", - "^[!/](setting) (%d+)$", - "^[!/](wholist)$", - "^[!/](who)$", - "^[!/](type)$", - "^[!/](kill) (chat) (%d+)$", - "^[!/](kill) (realm) (%d+)$", - "^[!/](addadmin) (.*)$", -- sudoers only - "^[!/](removeadmin) (.*)$", -- sudoers only - "^[!/](list) (.*)$", - "^[!/](log)$", - "^[!/](help)$", - "^!!tgservice (.+)$", - }, - run = run -} -end - - diff --git a/plugins/invite.lua b/plugins/invite.lua deleted file mode 100644 index 45c07fd..0000000 --- a/plugins/invite.lua +++ /dev/null @@ -1,41 +0,0 @@ -do -local function callbackres(extra, success, result) -- Callback for res_user in line 27 - local user = 'user#id'..result.id - local chat = 'chat#id'..extra.chatid - if is_banned(result.id, extra.chatid) then -- Ignore bans - send_large_msg(chat, 'User is banned.') - elseif is_gbanned(result.id) then -- Ignore globall bans - send_large_msg(chat, 'User is globaly banned.') - else - chat_add_user(chat, user, ok_cb, false) -- Add user on chat - end -end -function run(msg, matches) - local data = load_data(_config.moderation.data) - if not is_realm(msg) then - if data[tostring(msg.to.id)] and data[tostring(msg.to.id)]['settings']['lock_member'] == 'yes' and not is_admin(msg) then - return 'Group is private.' - end - end - if msg.to.type ~= 'chat' then - return - end - if not is_momod(msg) then - return - end - --if not is_admin(msg) then -- For admins only ! - --return 'Only admins can invite.' - --end - local cbres_extra = {chatid = msg.to.id} - local username = matches[1] - local username = username:gsub("@","") - res_user(username, callbackres, cbres_extra) -end -return { - patterns = { - "^[!/]invite (.*)$" - }, - run = run -} - -end diff --git a/plugins/leave_ban.lua b/plugins/leave_ban.lua deleted file mode 100644 index 6a69a7f..0000000 --- a/plugins/leave_ban.lua +++ /dev/null @@ -1,26 +0,0 @@ -local function run(msg, matches) - local data = load_data(_config.moderation.data) - if msg.action and msg.action.type then - local action = msg.action.type - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['settings'] then - if data[tostring(msg.to.id)]['settings']['leave_ban'] then - leave_ban = data[tostring(msg.to.id)]['settings']['leave_ban'] - end - end - end - if action == 'chat_del_user' and not is_momod2(msg.action.user.id) and leave_ban == 'yes' then - local user_id = msg.action.user.id - local chat_id = msg.to.id - ban_user(user_id, chat_id) - end - end - end - - -return { - patterns = { - "^!!tgservice (.*)$" - }, - run = run -} diff --git a/plugins/onservice.lua b/plugins/onservice.lua deleted file mode 100644 index 5463399..0000000 --- a/plugins/onservice.lua +++ /dev/null @@ -1,22 +0,0 @@ -do --- Will leave the group if be added -local function run(msg, matches) -local bot_id = our_id -- your bot id - -- like local bot_id = 1234567 - if matches[1] == 'leave' and is_admin(msg) then - chat_del_user("chat#id"..msg.to.id, 'user#id'..bot_id, ok_cb, false) - elseif msg.action.type == "chat_add_user" and msg.action.user.id == tonumber(bot_id) and not is_sudo(msg) then - send_large_msg("chat#id"..msg.to.id, 'this is not one of my groups.', ok_cb, false) - chat_del_user("chat#id"..msg.to.id, 'user#id'..bot_id, ok_cb, false) - block_user("user#id"..msg.from.id,ok_cb,false) - end -end - -return { - patterns = { - "^[!/](leave)$", - "^!!tgservice (.+)$", - }, - run = run -} -end diff --git a/plugins/owners.lua b/plugins/owners.lua deleted file mode 100644 index af2ac57..0000000 --- a/plugins/owners.lua +++ /dev/null @@ -1,317 +0,0 @@ - - -local function lock_group_namemod(msg, data, target) - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'yes' then - return 'Group name is already locked' - else - data[tostring(target)]['settings']['lock_name'] = 'yes' - save_data(_config.moderation.data, data) - rename_chat('chat#id'..target, group_name_set, ok_cb, false) - return 'Group name has been locked' - end -end - -local function unlock_group_namemod(msg, data, target) - local group_name_set = data[tostring(target)]['settings']['set_name'] - local group_name_lock = data[tostring(target)]['settings']['lock_name'] - if group_name_lock == 'no' then - return 'Group name is already unlocked' - else - data[tostring(target)]['settings']['lock_name'] = 'no' - save_data(_config.moderation.data, data) - return 'Group name has been unlocked' - end -end - -local function lock_group_floodmod(msg, data, target) - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'yes' then - return 'Group flood is locked' - else - data[tostring(target)]['settings']['flood'] = 'yes' - save_data(_config.moderation.data, data) - return 'Group flood has been locked' - end -end - -local function unlock_group_floodmod(msg, data, target) - local group_flood_lock = data[tostring(target)]['settings']['flood'] - if group_flood_lock == 'no' then - return 'Group flood is not locked' - else - data[tostring(target)]['settings']['flood'] = 'no' - save_data(_config.moderation.data, data) - return 'Group flood has been unlocked' - end -end - -local function lock_group_membermod(msg, data, target) - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'yes' then - return 'Group members are already locked' - else - data[tostring(target)]['settings']['lock_member'] = 'yes' - save_data(_config.moderation.data, data) - end - return 'Group members has been locked' -end - -local function unlock_group_membermod(msg, data, target) - local group_member_lock = data[tostring(target)]['settings']['lock_member'] - if group_member_lock == 'no' then - return 'Group members are not locked' - else - data[tostring(target)]['settings']['lock_member'] = 'no' - save_data(_config.moderation.data, data) - return 'Group members has been unlocked' - end -end - -local function unlock_group_photomod(msg, data, target) - local group_photo_lock = data[tostring(target)]['settings']['lock_photo'] - if group_photo_lock == 'no' then - return 'Group photo is not locked' - else - data[tostring(target)]['settings']['lock_photo'] = 'no' - save_data(_config.moderation.data, data) - return 'Group photo has been unlocked' - end -end - -local function show_group_settingsmod(msg, data, target) - local data = load_data(_config.moderation.data) - if data[tostring(msg.to.id)] then - if data[tostring(msg.to.id)]['settings']['flood_msg_max'] then - NUM_MSG_MAX = tonumber(data[tostring(msg.to.id)]['settings']['flood_msg_max']) - print('custom'..NUM_MSG_MAX) - else - NUM_MSG_MAX = 5 - end - end - local settings = data[tostring(target)]['settings'] - local text = "Group settings:\nLock group name : "..settings.lock_name.."\nLock group photo : "..settings.lock_photo.."\nLock group member : "..settings.lock_member.."\nflood sensitivity : "..NUM_MSG_MAX - return text -end - -local function set_rules(target, rules) - local data = load_data(_config.moderation.data) - local data_cat = 'rules' - data[tostring(target)][data_cat] = rules - save_data(_config.moderation.data, data) - return 'Set group rules to:\n'..rules -end - -local function set_description(target, about) - local data = load_data(_config.moderation.data) - local data_cat = 'description' - data[tostring(target)][data_cat] = about - save_data(_config.moderation.data, data) - return 'Set group description to:\n'..about -end - -local function run(msg, matches) - if msg.to.type ~= 'chat' then - local chat_id = matches[1] - local receiver = get_receiver(msg) - local data = load_data(_config.moderation.data) - if matches[2] == 'ban' then - local chat_id = matches[1] - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - if tonumber(matches[3]) == tonumber(our_id) then return false end - local user_id = matches[3] - if tonumber(matches[3]) == tonumber(msg.from.id) then - return "You can't ban yourself" - end - ban_user(matches[3], matches[1]) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] banned user ".. matches[3]) - return 'User '..user_id..' banned' - end - if matches[2] == 'unban' then - if tonumber(matches[3]) == tonumber(our_id) then return false end - local chat_id = matches[1] - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local user_id = matches[3] - if tonumber(matches[3]) == tonumber(msg.from.id) then - return "You can't unban yourself" - end - local hash = 'banned:'..matches[1] - redis:srem(hash, user_id) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] unbanned user ".. matches[3]) - return 'User '..user_id..' unbanned' - end - if matches[2] == 'kick' then - local chat_id = matches[1] - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - if tonumber(matches[3]) == tonumber(our_id) then return false end - local user_id = matches[3] - if tonumber(matches[3]) == tonumber(msg.from.id) then - return "You can't kick yourself" - end - kick_user(matches[3], matches[1]) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] kicked user ".. matches[3]) - return 'User '..user_id..' kicked' - end - if matches[2] == 'clean' then - if matches[3] == 'modlist' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - for k,v in pairs(data[tostring(matches[1])]['moderators']) do - data[tostring(matches[1])]['moderators'][tostring(k)] = nil - save_data(_config.moderation.data, data) - end - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] cleaned modlist") - end - if matches[3] == 'rules' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local data_cat = 'rules' - data[tostring(matches[1])][data_cat] = nil - save_data(_config.moderation.data, data) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] cleaned rules") - end - if matches[3] == 'about' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local data_cat = 'description' - data[tostring(matches[1])][data_cat] = nil - save_data(_config.moderation.data, data) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] cleaned about") - end - end - if matches[2] == "setflood" then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - if tonumber(matches[3]) < 5 or tonumber(matches[3]) > 20 then - return "Wrong number,range is [5-20]" - end - local flood_max = matches[3] - data[tostring(matches[1])]['settings']['flood_msg_max'] = flood_max - save_data(_config.moderation.data, data) - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] set flood to ["..matches[3].."]") - return 'Group flood has been set to '..matches[3] - end - if matches[2] == 'lock' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local target = matches[1] - if matches[3] == 'name' then - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] locked name ") - return lock_group_namemod(msg, data, target) - end - if matches[3] == 'member' then - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] locked member ") - return lock_group_membermod(msg, data, target) - end - end - if matches[2] == 'unlock' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local target = matches[1] - if matches[3] == 'name' then - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] unlocked name ") - return unlock_group_namemod(msg, data, target) - end - if matches[3] == 'member' then - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] unlocked member ") - return unlock_group_membermod(msg, data, target) - end - end - if matches[2] == 'new' then - if matches[3] == 'link' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local function callback (extra , success, result) - local receiver = 'chat#'..matches[1] - vardump(result) - data[tostring(matches[1])]['settings']['set_link'] = result - save_data(_config.moderation.data, data) - return - end - local receiver = 'chat#'..matches[1] - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] revoked group link ") - export_chat_link(receiver, callback, true) - return "Created a new new link ! \n owner can get it by /owners "..matches[1].." get link" - end - end - if matches[2] == 'get' then - if matches[3] == 'link' then - if not is_owner2(msg.from.id, chat_id) then - return "You are not the owner of this group" - end - local group_link = data[tostring(matches[1])]['settings']['set_link'] - if not group_link then - return "Create a link using /newlink first !" - end - local name = user_print_name(msg.from) - savelog(matches[1], name.." ["..msg.from.id.."] requested group link ["..group_link.."]") - return "Group link:\n"..group_link - end - end - if matches[1] == 'changeabout' and matches[2] and is_owner2(msg.from.id, matches[2]) then - local target = matches[2] - local about = matches[3] - local name = user_print_name(msg.from) - savelog(matches[2], name.." ["..msg.from.id.."] has changed group description to ["..matches[3].."]") - return set_description(target, about) - end - if matches[1] == 'changerules' and is_owner2(msg.from.id, matches[2]) then - local rules = matches[3] - local target = matches[2] - local name = user_print_name(msg.from) - savelog(matches[2], name.." ["..msg.from.id.."] has changed group rules to ["..matches[3].."]") - return set_rules(target, rules) - end - if matches[1] == 'changename' and is_owner2(msg.from.id, matches[2]) then - local new_name = string.gsub(matches[3], '_', ' ') - data[tostring(matches[2])]['settings']['set_name'] = new_name - save_data(_config.moderation.data, data) - local group_name_set = data[tostring(matches[2])]['settings']['set_name'] - local to_rename = 'chat#id'..matches[2] - local name = user_print_name(msg.from) - savelog(matches[2], "Group {} name changed to [ "..new_name.." ] by "..name.." ["..msg.from.id.."]") - rename_chat(to_rename, group_name_set, ok_cb, false) - end - if matches[1] == 'loggroup' and matches[2] and is_owner2(msg.from.id, matches[2]) then - savelog(matches[2], "------") - send_document("user#id".. msg.from.id,"./groups/logs/"..matches[2].."log.txt", ok_cb, false) - end - end -end -return { - patterns = { - "^[!/]owners (%d+) ([^%s]+) (.*)$", - "^[!/]owners (%d+) ([^%s]+)$", - "^[!/](changeabout) (%d+) (.*)$", - "^[!/](changerules) (%d+) (.*)$", - "^[!/](changename) (%d+) (.*)$", - "^[!/](loggroup) (%d+)$" - }, - run = run -} diff --git a/plugins/set.lua b/plugins/set.lua deleted file mode 100644 index 5ed46ea..0000000 --- a/plugins/set.lua +++ /dev/null @@ -1,32 +0,0 @@ -local function save_value(msg, name, value) - if (not name or not value) then - return "Usage: !set var_name value" - end - local hash = nil - if msg.to.type == 'chat' then - hash = 'chat:'..msg.to.id..':variables' - end - if hash then - redis:hset(hash, name, value) - return "Saved "..name - end -end -local function run(msg, matches) - if not is_momod(msg) then - return "For moderators only!" - end - local name = string.sub(matches[1], 1, 50) - local value = string.sub(matches[2], 1, 1000) - local name1 = user_print_name(msg.from) - savelog(msg.to.id, name1.." ["..msg.from.id.."] saved ["..name.."] as > "..value ) - local text = save_value(msg, name, value) - return text -end - -return { - patterns = { - "^[!/]save ([^%s]+) (.+)$" - }, - run = run -} - diff --git a/plugins/stats.lua b/plugins/stats.lua deleted file mode 100644 index 7583136..0000000 --- a/plugins/stats.lua +++ /dev/null @@ -1,150 +0,0 @@ -do - --- Returns a table with `name` and `msgs` -local function get_msgs_user_chat(user_id, chat_id) - local user_info = {} - local uhash = 'user:'..user_id - local user = redis:hgetall(uhash) - local um_hash = 'msgs:'..user_id..':'..chat_id - user_info.msgs = tonumber(redis:get(um_hash) or 0) - user_info.name = user_print_name(user)..' ['..user_id..']' - return user_info -end - -local function chat_stats(chat_id) - -- Users on chat - local hash = 'chat:'..chat_id..':users' - local users = redis:smembers(hash) - local users_info = {} - -- Get user info - for i = 1, #users do - local user_id = users[i] - local user_info = get_msgs_user_chat(user_id, chat_id) - table.insert(users_info, user_info) - end - -- Sort users by msgs number - table.sort(users_info, function(a, b) - if a.msgs and b.msgs then - return a.msgs > b.msgs - end - end) - local text = 'users in this chat \n' - for k,user in pairs(users_info) do - text = text..user.name..' = '..user.msgs..'\n' - end - local file = io.open("./groups/lists/"..chat_id.."stats.txt", "w") - file:write(text) - file:flush() - file:close() - send_document("chat#id"..chat_id,"./groups/lists/"..chat_id.."stats.txt", ok_cb, false) - return --text -end - -local function chat_stats2(chat_id) - -- Users on chat - local hash = 'chat:'..chat_id..':users' - local users = redis:smembers(hash) - local users_info = {} - - -- Get user info - for i = 1, #users do - local user_id = users[i] - local user_info = get_msgs_user_chat(user_id, chat_id) - table.insert(users_info, user_info) - end - - -- Sort users by msgs number - table.sort(users_info, function(a, b) - if a.msgs and b.msgs then - return a.msgs > b.msgs - end - end) - - local text = 'users in this chat \n' - for k,user in pairs(users_info) do - text = text..user.name..' = '..user.msgs..'\n' - end - return text -end --- Save stats, ban user -local function bot_stats() - - local redis_scan = [[ - local cursor = '0' - local count = 0 - - repeat - local r = redis.call("SCAN", cursor, "MATCH", KEYS[1]) - cursor = r[1] - count = count + #r[2] - until cursor == '0' - return count]] - - -- Users - local hash = 'msgs:*:'..our_id - local r = redis:eval(redis_scan, 1, hash) - local text = 'Users: '..r - - hash = 'chat:*:users' - r = redis:eval(redis_scan, 1, hash) - text = text..'\nGroups: '..r - return text -end -local function run(msg, matches) - if matches[1]:lower() == 'teleseed' then -- Put everything you like :) - local about = _config.about_text - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] used /teleseed ") - return about - end - if matches[1]:lower() == "statslist" then - if not is_momod(msg) then - return "For mods only !" - end - local chat_id = msg.to.id - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] requested group stats ") - return chat_stats2(chat_id) - end - if matches[1]:lower() == "stats" then - if not matches[2] then - if not is_momod(msg) then - return "For mods only !" - end - if msg.to.type == 'chat' then - local chat_id = msg.to.id - local name = user_print_name(msg.from) - savelog(msg.to.id, name.." ["..msg.from.id.."] requested group stats ") - return chat_stats(chat_id) - else - return - end - end - if matches[2] == "teleseed" then -- Put everything you like :) - if not is_admin(msg) then - return "For admins only !" - else - return bot_stats() - end - end - if matches[2] == "group" then - if not is_admin(msg) then - return "For admins only !" - else - return chat_stats(matches[3]) - end - end - end -end -return { - patterns = { - "^[!/]([Ss]tats)$", - "^[!/]([Ss]tatslist)$", - "^[!/]([Ss]tats) (group) (%d+)", - "^[!/]([Ss]tats) (teleseed)",-- Put everything you like :) - "^[!/]([Tt]eleseed)"-- Put everything you like :) - }, - run = run -} - -end