First commit
This commit is contained in:
parent
2c6a54d435
commit
3ead60b88d
|
@ -0,0 +1,12 @@
|
||||||
|
bot_token = ""
|
||||||
|
|
||||||
|
api_id = ""
|
||||||
|
api_hash = ""
|
||||||
|
|
||||||
|
group_id = ""
|
||||||
|
log_group_id = ""
|
||||||
|
|
||||||
|
vt_api = ""
|
||||||
|
|
||||||
|
db_url = "sqlite://db.db"
|
||||||
|
telegram_api_server = "127.0.0.1:5326"
|
|
@ -0,0 +1,630 @@
|
||||||
|
Copyright (C) 2021 Hack4th5tR
|
||||||
|
|
||||||
|
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 3 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.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. 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
|
||||||
|
them 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 prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. 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.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey 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;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If 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 convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU 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 that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
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.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import logging
|
||||||
|
from aiogram import executor
|
||||||
|
from database import models
|
||||||
|
|
||||||
|
from load import dp, bot
|
||||||
|
from load import loop,tgc
|
||||||
|
|
||||||
|
import handlers
|
||||||
|
import config
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
|
||||||
|
|
||||||
|
WEBAPP_HOST = '127.0.0.1'
|
||||||
|
WEBAPP_PORT = 3001
|
||||||
|
|
||||||
|
# Don`t touch anything!
|
||||||
|
WEBHOOK_HOST = f'http://{WEBAPP_HOST}:{WEBAPP_PORT}'
|
||||||
|
WEBHOOK_PATH = f'/bot{config.token}/'
|
||||||
|
WEBHOOK_URL = f"{WEBHOOK_HOST}{WEBHOOK_PATH}"
|
||||||
|
|
||||||
|
async def on_startup(dp):
|
||||||
|
from utils.notify_start import notify_started_bot
|
||||||
|
await notify_started_bot(bot)
|
||||||
|
|
||||||
|
from utils.default_commands import set_default_commands
|
||||||
|
await set_default_commands(dp)
|
||||||
|
|
||||||
|
await bot.set_webhook(WEBHOOK_URL)
|
||||||
|
|
||||||
|
# Connect to client
|
||||||
|
await tgc._connect()
|
||||||
|
|
||||||
|
async def on_shutdown(dp):
|
||||||
|
await bot.delete_webhook()
|
||||||
|
|
||||||
|
# Close Redis connection.
|
||||||
|
await dp.storage.close()
|
||||||
|
await dp.storage.wait_closed()
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
models.build()
|
||||||
|
|
||||||
|
if config.use_webhook:
|
||||||
|
executor.start_webhook(
|
||||||
|
dispatcher=dp,
|
||||||
|
webhook_path=WEBHOOK_PATH,
|
||||||
|
on_startup=on_startup,
|
||||||
|
on_shutdown=on_shutdown,
|
||||||
|
loop = loop,
|
||||||
|
skip_updates=True,
|
||||||
|
host=WEBAPP_HOST,
|
||||||
|
port=WEBAPP_PORT,
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
executor.start_polling(dp,skip_updates=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -0,0 +1 @@
|
||||||
|
from .config import *
|
|
@ -0,0 +1,36 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from aiogram import Dispatcher,Bot
|
||||||
|
from environs import Env
|
||||||
|
|
||||||
|
env = Env()
|
||||||
|
env.read_env()
|
||||||
|
|
||||||
|
use_webhook = True
|
||||||
|
|
||||||
|
# bot token
|
||||||
|
token = env.str("bot_token")
|
||||||
|
|
||||||
|
group_id = env.str("group_id")
|
||||||
|
telegram_log_chat_id = env.str("log_group_id")
|
||||||
|
|
||||||
|
# Telegram Application
|
||||||
|
api_id = env.str("api_id")
|
||||||
|
api_hash = env.str("api_hash")
|
||||||
|
|
||||||
|
# Virus Total API
|
||||||
|
vt_api = env.str("vt_api")
|
||||||
|
|
||||||
|
with open("config/roles.json","r") as jsonfile:
|
||||||
|
roles = json.load(jsonfile)
|
||||||
|
|
||||||
|
db_url = env.str("db_url")
|
||||||
|
|
||||||
|
# telegram-bot-api-service
|
||||||
|
telegram_api_server = env.str("telegram_api_server").split(":")
|
||||||
|
telegram_api_server = {
|
||||||
|
"ip":telegram_api_server[0],
|
||||||
|
"port":telegram_api_server[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
telegram_api_server = f"http://{telegram_api_server['ip']}:{telegram_api_server['port']}"
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"level": {
|
||||||
|
"owner": 3,
|
||||||
|
"admin": 2,
|
||||||
|
"helper": 1,
|
||||||
|
"member": 0
|
||||||
|
},
|
||||||
|
"group_permissions": {
|
||||||
|
"can_send_messages": true,
|
||||||
|
"can_send_media_messages": true,
|
||||||
|
"can_send_other_messages": true,
|
||||||
|
"can_send_polls": false,
|
||||||
|
"can_invite_users": false,
|
||||||
|
"can_change_info": false,
|
||||||
|
"can_add_web_page_previews": false,
|
||||||
|
"can_pin_messages": false
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"owner": {
|
||||||
|
"ban": true,
|
||||||
|
"kick": true,
|
||||||
|
"mute": true,
|
||||||
|
"umute": true,
|
||||||
|
"warn": true,
|
||||||
|
"pin": true,
|
||||||
|
"srole": true,
|
||||||
|
"media": true,
|
||||||
|
"stickers": true,
|
||||||
|
"ro": true,
|
||||||
|
"reload": true
|
||||||
|
},
|
||||||
|
"admin": {
|
||||||
|
"ban": true,
|
||||||
|
"kick": true,
|
||||||
|
"mute": true,
|
||||||
|
"umute": true,
|
||||||
|
"warn": true,
|
||||||
|
"pin": true,
|
||||||
|
"srole": true,
|
||||||
|
"media": true,
|
||||||
|
"stickers": true,
|
||||||
|
"ro": true,
|
||||||
|
"reload": true
|
||||||
|
},
|
||||||
|
"helper": {
|
||||||
|
"ban": false,
|
||||||
|
"kick": true,
|
||||||
|
"mute": false,
|
||||||
|
"umute": false,
|
||||||
|
"warn": true,
|
||||||
|
"pin": false,
|
||||||
|
"srole": false,
|
||||||
|
"media": true,
|
||||||
|
"stickers": true,
|
||||||
|
"ro": false,
|
||||||
|
"reload": true
|
||||||
|
},
|
||||||
|
"member": {
|
||||||
|
"ban": false,
|
||||||
|
"kick": false,
|
||||||
|
"mute": false,
|
||||||
|
"umute": false,
|
||||||
|
"warn": false,
|
||||||
|
"pin": false,
|
||||||
|
"srole": false,
|
||||||
|
"media": false,
|
||||||
|
"stickers": false,
|
||||||
|
"ro": false,
|
||||||
|
"reload": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
from .database import Database
|
|
@ -0,0 +1,109 @@
|
||||||
|
from .models import Member,Restriction
|
||||||
|
from peewee import Field
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
def check_data_exists(self, fieldname:Field, value) -> bool | None:
|
||||||
|
"""Check if data exists in db"""
|
||||||
|
query = Member.select().where(fieldname == value)
|
||||||
|
|
||||||
|
if (query is None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return query.exists()
|
||||||
|
|
||||||
|
def register_user(self, user_id, first_name, user_name=None, role:str='member') -> bool:
|
||||||
|
"""If the user doesn't exist, returns true. Registers a user in the db."""
|
||||||
|
|
||||||
|
if self.check_data_exists(Member.user_id,user_id):
|
||||||
|
return False
|
||||||
|
|
||||||
|
Member.create(
|
||||||
|
user_id = user_id,
|
||||||
|
first_name = first_name,
|
||||||
|
user_name = user_name,
|
||||||
|
|
||||||
|
role = role,
|
||||||
|
|
||||||
|
reports = 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def search_single_member(self,fieldname:Field,value) -> Member | None:
|
||||||
|
"""If the user is found, returns dataclass. Returns user info."""
|
||||||
|
exists = self.check_data_exists(fieldname,value)
|
||||||
|
|
||||||
|
if not (exists):
|
||||||
|
return None
|
||||||
|
|
||||||
|
user = Member.get(fieldname == value)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
def create_restriction(self, from_user_id, to_user_id, operation, reason):
|
||||||
|
from_admin = self.search_single_member(Member.user_id,to_user_id)
|
||||||
|
to_user = self.search_single_member(Member.user_id,from_user_id)
|
||||||
|
|
||||||
|
if not (from_admin) or not (to_user):
|
||||||
|
return None
|
||||||
|
|
||||||
|
Restriction.create(
|
||||||
|
operation = operation,
|
||||||
|
|
||||||
|
from_admin = from_admin,
|
||||||
|
to_user = to_user,
|
||||||
|
|
||||||
|
reason = reason,
|
||||||
|
)
|
||||||
|
|
||||||
|
def search_user_restriction(self, user_id) -> list[Restriction] | None:
|
||||||
|
user = Member.get(Member.user_id == user_id)
|
||||||
|
|
||||||
|
query = Restriction.select().join(Member,on=Restriction.to_user)
|
||||||
|
|
||||||
|
if (query is None):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return query.where(Restriction.to_user == user)
|
||||||
|
|
||||||
|
def delete_user(self,user_id) -> bool:
|
||||||
|
"""If the user exists, returns true. Deletes the user from the db."""
|
||||||
|
|
||||||
|
exists = self.check_data_exists(Member.user_id,user_id)
|
||||||
|
|
||||||
|
if not (exists):
|
||||||
|
return False
|
||||||
|
|
||||||
|
Member.delete().where(Member.user_id == user_id)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def update_member_data(self, user_id, fieldnames:list[Field], newvalues:list) -> bool:
|
||||||
|
"""Update member data."""
|
||||||
|
exists = self.check_data_exists(Member.user_id,user_id)
|
||||||
|
|
||||||
|
if (not exists):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for i in range(len(newvalues)):
|
||||||
|
query = Member.update({fieldnames[i]:newvalues[i]}).where(Member.user_id == user_id)
|
||||||
|
if (query is None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def change_reports(self,user_id,delete=False) -> int | None:
|
||||||
|
"""If the user exists, returns number reports. Gives the user a warning or retrieves it."""
|
||||||
|
exists = self.check_data_exists(Member.user_id,user_id)
|
||||||
|
|
||||||
|
if not (exists):
|
||||||
|
return False
|
||||||
|
|
||||||
|
count = Member.get(Member.user_id == user_id).reports
|
||||||
|
|
||||||
|
if delete:count += 1
|
||||||
|
else:count -= 1
|
||||||
|
|
||||||
|
query = Member.update(reports = count).where(Member.user_id == user_id).execute()
|
||||||
|
|
||||||
|
return count
|
|
@ -0,0 +1,39 @@
|
||||||
|
from peewee import Model, BigIntegerField, CharField, DateField, DateTimeField, ForeignKeyField
|
||||||
|
|
||||||
|
import config
|
||||||
|
from playhouse.db_url import connect
|
||||||
|
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
db = connect(config.db_url)
|
||||||
|
|
||||||
|
class Member(Model):
|
||||||
|
user_id = BigIntegerField()
|
||||||
|
first_name = CharField()
|
||||||
|
user_name = CharField(null=True)
|
||||||
|
role = CharField()
|
||||||
|
|
||||||
|
join_date = DateField(default=date.today())
|
||||||
|
|
||||||
|
reports = BigIntegerField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "members"
|
||||||
|
database = db
|
||||||
|
|
||||||
|
class Restriction(Model):
|
||||||
|
restriction_id = BigIntegerField()
|
||||||
|
operation = CharField()
|
||||||
|
|
||||||
|
from_admin = ForeignKeyField(Member,lazy_load=False)
|
||||||
|
to_user = ForeignKeyField(Member,lazy_load=False)
|
||||||
|
|
||||||
|
reason = CharField(null=True)
|
||||||
|
date = DateTimeField(default=datetime.now)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "restrictions"
|
||||||
|
database = db
|
||||||
|
|
||||||
|
def build() -> None:
|
||||||
|
db.create_tables([Member,Restriction])
|
|
@ -0,0 +1 @@
|
||||||
|
from .filters import IsAdminFilter,ReplayMessageFilter,UserHasRights
|
|
@ -0,0 +1,77 @@
|
||||||
|
from aiogram import types
|
||||||
|
from aiogram.dispatcher.filters import BoundFilter
|
||||||
|
|
||||||
|
# from config import roles
|
||||||
|
from database.database import Member
|
||||||
|
|
||||||
|
class IsAdminFilter(BoundFilter):
|
||||||
|
"""Check admin permission on hadler"""
|
||||||
|
key = 'is_admin'
|
||||||
|
|
||||||
|
def __init__(self, is_admin):
|
||||||
|
self.is_admin = is_admin
|
||||||
|
|
||||||
|
async def check(self, message: types.Message):
|
||||||
|
member = await message.bot.get_chat_member(message.chat.id, message.from_user.id)
|
||||||
|
result = member.is_chat_admin()
|
||||||
|
if not result:
|
||||||
|
await message.reply("🔒This command can only be used by an admin!")
|
||||||
|
return result
|
||||||
|
|
||||||
|
class UserHasRights(BoundFilter):
|
||||||
|
"""Check command in user rights"""
|
||||||
|
|
||||||
|
key = 'hasRights'
|
||||||
|
|
||||||
|
def __init__(self,hasRights):
|
||||||
|
self.hasRights = hasRights
|
||||||
|
|
||||||
|
async def check(self,message:types.Message):
|
||||||
|
import config
|
||||||
|
from load import database
|
||||||
|
|
||||||
|
roles = config.roles["roles"]
|
||||||
|
|
||||||
|
command = message.text.split()[0].lstrip("!")
|
||||||
|
|
||||||
|
user = database.search_single_member(Member.user_id,message.from_user.id)
|
||||||
|
|
||||||
|
# If data not exists,return False
|
||||||
|
if (user is None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If role not exist,return False.
|
||||||
|
if not (user.role in roles.keys()):
|
||||||
|
return False
|
||||||
|
|
||||||
|
can_run_it = roles[user.role][command]
|
||||||
|
|
||||||
|
replied = message.reply_to_message
|
||||||
|
|
||||||
|
if (replied):
|
||||||
|
if (replied.from_user.id == message.from_user.id):
|
||||||
|
await message.answer("❌ You can't ")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (str(replied.from_user.id) == config.token.split(":")[0]):
|
||||||
|
await message.answer("You can't restrict bot.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not (can_run_it):
|
||||||
|
await message.answer("You can't use this command.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return roles[user.role][command]
|
||||||
|
|
||||||
|
class ReplayMessageFilter(BoundFilter):
|
||||||
|
"""Check if message replied"""
|
||||||
|
key = 'replied'
|
||||||
|
|
||||||
|
def __init__(self, replied):
|
||||||
|
self.replied = replied
|
||||||
|
|
||||||
|
async def check(self, message: types.Message):
|
||||||
|
if message.reply_to_message is None:
|
||||||
|
await message.reply("Is command must be reply")
|
||||||
|
return False
|
||||||
|
return True
|
|
@ -0,0 +1,5 @@
|
||||||
|
from . import groups
|
||||||
|
from . import private
|
||||||
|
from . import channels
|
||||||
|
from . import event
|
||||||
|
from . import errors
|
|
@ -0,0 +1 @@
|
||||||
|
from . import channels_handler
|
|
@ -0,0 +1,6 @@
|
||||||
|
from load import dp,types
|
||||||
|
|
||||||
|
# TODO: channel post forward in chat
|
||||||
|
@dp.channel_post_handler()
|
||||||
|
async def channel_handler(message:types.Message):
|
||||||
|
print(message.text)
|
|
@ -0,0 +1 @@
|
||||||
|
from . import errors_handler
|
|
@ -0,0 +1,23 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from load import dp,bot
|
||||||
|
import config
|
||||||
|
|
||||||
|
from aiogram.utils.exceptions import Unauthorized
|
||||||
|
|
||||||
|
|
||||||
|
@dp.errors_handler()
|
||||||
|
async def errors_handler(update, exception):
|
||||||
|
if (isinstance(exception,Unauthorized)):
|
||||||
|
logging.info(f"Unathorized:{config.token}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
await update.message.answer("Error happaned!\nBot terminated!")
|
||||||
|
|
||||||
|
await bot.send_message(
|
||||||
|
config.telegram_log_chat_id,
|
||||||
|
f"**Bot terminated**!\nException:{exception}",
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info(f"Bot terminated!Exception:{exception}")
|
|
@ -0,0 +1,29 @@
|
||||||
|
from load import dp, bot, types
|
||||||
|
|
||||||
|
# TODO: fix it
|
||||||
|
# import utils
|
||||||
|
# import config
|
||||||
|
# vt = utils.VirusTotalAPI(config.vt_api,True)
|
||||||
|
# @dp.message_handler(content_types=["document"],chat_type=[types.ChatType.SUPERGROUP])
|
||||||
|
# async def file_handler(message:types.Message):
|
||||||
|
# file = await bot.get_file(message.document.file_id)
|
||||||
|
#
|
||||||
|
# await bot.send_message(
|
||||||
|
# message.chat.id,
|
||||||
|
# await vt.scan_file(file.file_path),
|
||||||
|
# parse_mode="Markdown"
|
||||||
|
# )
|
||||||
|
|
||||||
|
@dp.message_handler()
|
||||||
|
async def filter_link_shorts(message:types.Message):
|
||||||
|
link_shorters = open("txt/link_shorters.txt","r").read().split()
|
||||||
|
|
||||||
|
for y in link_shorters:
|
||||||
|
for user_message in message.text.lower().split():
|
||||||
|
if (y in user_message):await message.delete()
|
||||||
|
|
||||||
|
# Joke
|
||||||
|
@dp.message_handler(content_types=types.ContentType.VOICE)
|
||||||
|
async def voice_message(message:types.Message):
|
||||||
|
photo = types.InputFile(path_or_bytesio="media/photo.jpg")
|
||||||
|
await message.answer_photo(photo)
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import admin
|
||||||
|
from . import user
|
|
@ -0,0 +1,423 @@
|
||||||
|
from load import bot, dp, types
|
||||||
|
from aiogram.types.chat_permissions import ChatPermissions
|
||||||
|
|
||||||
|
import config
|
||||||
|
import utils
|
||||||
|
|
||||||
|
from load import database
|
||||||
|
from database.models import Member
|
||||||
|
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
# TODO:Automatic malware checking with VirusTotal(add skipping queue virustotal report)
|
||||||
|
# vt = utils.VirusTotalAPI(config.vt_api,True)
|
||||||
|
|
||||||
|
def getArgument(arguments:list,index:int=0) -> str | None:
|
||||||
|
""" Get element from a list.If element not exist return None """
|
||||||
|
if not (arguments):
|
||||||
|
return None
|
||||||
|
if (len(arguments) >= index):
|
||||||
|
return arguments[index]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CommandArguments:
|
||||||
|
user:Member | None
|
||||||
|
arguments:list
|
||||||
|
|
||||||
|
async def getCommandArgs(message:types.Message) -> CommandArguments:
|
||||||
|
""" Describe user data and arguments from message """
|
||||||
|
|
||||||
|
#Example:
|
||||||
|
#1.!command @username ... (not reply)
|
||||||
|
#2.!command (not_reply)
|
||||||
|
#3.!command ... (not reply)
|
||||||
|
|
||||||
|
arguments_list = message.text.split()[1:]
|
||||||
|
|
||||||
|
is_reply = message.reply_to_message
|
||||||
|
|
||||||
|
member = None
|
||||||
|
arguments = []
|
||||||
|
|
||||||
|
if (is_reply):
|
||||||
|
member = database.search_single_member(Member.user_id,message.reply_to_message)
|
||||||
|
arguments = arguments_list
|
||||||
|
else:
|
||||||
|
first_word = getArgument(arguments_list)
|
||||||
|
if (first_word):
|
||||||
|
if (first_word.isdigit()):
|
||||||
|
member = database.search_single_member(Member.user_id,first_word)
|
||||||
|
|
||||||
|
if (first_word[0] == "@") :
|
||||||
|
member = database.search_single_member(Member.user_name,first_word)
|
||||||
|
|
||||||
|
arguments = arguments_list[1:]
|
||||||
|
else:
|
||||||
|
arguments = arguments_list
|
||||||
|
|
||||||
|
if (member is None) and (first_word):
|
||||||
|
await message.answer(f"❌ User {first_word} not exist.")
|
||||||
|
|
||||||
|
return CommandArguments(member,arguments)
|
||||||
|
|
||||||
|
def checkArg(message:str) -> bool | None:
|
||||||
|
""" Check if first argument in ["enable","on","true"] then return true """
|
||||||
|
if (not message):
|
||||||
|
return None
|
||||||
|
|
||||||
|
argument = message.split()[1]
|
||||||
|
|
||||||
|
on = ['enable','on','true']
|
||||||
|
off = ['disable','off','false']
|
||||||
|
|
||||||
|
return (argument in on) or (not argument in off)
|
||||||
|
|
||||||
|
def delete_substring_from_string(string:str,substring:str) -> str:
|
||||||
|
string_list = string.split(substring)
|
||||||
|
return "".join(string_list).lstrip()
|
||||||
|
|
||||||
|
# Filters:
|
||||||
|
# is_admin=True - Check admin permission, if user is admin, continue
|
||||||
|
# replied=True - If message is answer, continue
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["ban"],commands_prefix="!",hasRights=True)
|
||||||
|
async def ban_user(message: types.Message):
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
reason = getArgument(command.arguments)
|
||||||
|
|
||||||
|
user = command.user
|
||||||
|
admin = message.from_user
|
||||||
|
|
||||||
|
# If can't descibe user data
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!ban @username reason=None"
|
||||||
|
"Reply to a message or use with a username.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ban user and save (bool)
|
||||||
|
status = await bot.kick_chat_member(chat_id=message.chat.id, user_id=user.user_id, until_date=None)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.user_id}) has been banned.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
# Delete user from database
|
||||||
|
database.delete_user(user.user_id)
|
||||||
|
|
||||||
|
# Open restrict
|
||||||
|
database.create_restriction(user.user_id, admin.id, "ban", reason)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["unban"],commands_prefix="!",hasRights=True)
|
||||||
|
async def unban_user(message: types.Message):
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
user = command.user
|
||||||
|
|
||||||
|
# If can't descibe user data
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!unban @username reason=None\n"
|
||||||
|
"Reply to a message or use with username/id.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Unban user and set status (bool)
|
||||||
|
status = await bot.unban_chat_member(chat_id=message.chat.id, user_id=user.user_id)
|
||||||
|
|
||||||
|
# add user to database
|
||||||
|
database.register_user(user.user_id, user.first_name)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.user_id}) has been unbaned.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["kick"],commands_prefix="!",hasRights=True)
|
||||||
|
async def kick_user(message:types.Message):
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
arguments = command.arguments
|
||||||
|
|
||||||
|
user = command.user
|
||||||
|
admin = message.from_user
|
||||||
|
|
||||||
|
reason = getArgument(arguments)
|
||||||
|
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!kick @username reason=None\n"
|
||||||
|
"Reply to a message or use with a username/id.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
status1 = await bot.kick_chat_member(chat_id=message.chat.id, user_id=user.user_id, until_date=None)
|
||||||
|
status2 = await bot.unban_chat_member(chat_id=message.chat.id, user_id=user.user_id)
|
||||||
|
|
||||||
|
if (status1 and status2):
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.user_id}) has been kicked.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
database.create_restriction(user.user_id,admin.id,"kick",reason)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["mute"],commands_prefix="!",hasRights=True)
|
||||||
|
async def mute_user(message:types.Message):
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
arguments = command.arguments
|
||||||
|
|
||||||
|
user = command.user
|
||||||
|
admin = message.from_user
|
||||||
|
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!mute @username time\n"
|
||||||
|
"Reply to a message or use with a username/id.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
duration = re.findall(r"(\d+d|\d+h|\d+m|\d+s)",''.join(arguments))
|
||||||
|
duration = " ".join(duration)
|
||||||
|
reason = delete_substring_from_string(" ".join(arguments),duration)
|
||||||
|
duration_timedelta = utils.parse_timedelta(duration)
|
||||||
|
|
||||||
|
if not duration:
|
||||||
|
await message.answer(f"Error: \"{duration}\" — неверный формат времени. Examles: 3ч, 5м, 4h30s.")
|
||||||
|
return
|
||||||
|
|
||||||
|
permissions = ChatPermissions(can_send_messages=False)
|
||||||
|
|
||||||
|
status = await bot.restrict_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user.user_id,
|
||||||
|
until_date=duration_timedelta,
|
||||||
|
permissions=permissions
|
||||||
|
)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"User **{user.first_name}** has been muted.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
database.create_restriction(user.user_id,admin.id,"mute",reason)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["umute"],commands_prefix="!",hasRights=True)
|
||||||
|
async def umute_user(message: types.Message):
|
||||||
|
# Get information
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
user = command.user
|
||||||
|
|
||||||
|
# If can't
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!unmute @username reason=None\n"
|
||||||
|
"Reply to a message or use with a username/id.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get chat permissions
|
||||||
|
group_permissions = config.roles["group_permissions"]
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
permissions = ChatPermissions(
|
||||||
|
can_send_messages= group_permissions["can_send_messages"],
|
||||||
|
can_send_media_messages= group_permissions["can_send_media_messages"],
|
||||||
|
can_send_polls= group_permissions["can_send_polls"],
|
||||||
|
can_send_other_messages= group_permissions["can_send_other_messages"],
|
||||||
|
can_add_web_page_previews= group_permissions["can_add_web_page_previews"],
|
||||||
|
can_change_info= group_permissions["can_change_info"],
|
||||||
|
can_invite_users= group_permissions["can_invite_users"],
|
||||||
|
can_pin_messages= group_permissions["can_pin_messages"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Restrict user and save
|
||||||
|
status = await bot.restrict_chat_member(
|
||||||
|
chat_id=message.chat.id,
|
||||||
|
user_id=user.user_id,
|
||||||
|
permissions=permissions
|
||||||
|
)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.user_id}) has been unmuted.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["pin"],commands_prefix="!",hasRights=True)
|
||||||
|
async def pin_message(message:types.Message):
|
||||||
|
await bot.pin_chat_message(message.chat.id, message.reply_to_message.message_id)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["ro"],commands_prefix="!",hasRights=True)
|
||||||
|
async def readonly_mode(message:types.Message):
|
||||||
|
check = checkArg(message.text)
|
||||||
|
|
||||||
|
if (check is None):
|
||||||
|
await message.answer("!ro on/off alias:disable,enable,start,stop.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get chat permissions
|
||||||
|
group_permissions = config.roles["group_permissions"]
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
if (check):
|
||||||
|
chat_permissions = ChatPermissions(
|
||||||
|
can_send_messages=not check
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
chat_permissions = ChatPermissions(
|
||||||
|
can_send_messages=group_permissions['can_send_messages'],
|
||||||
|
can_send_media_messages=group_permissions["can_send_media_messages"],
|
||||||
|
can_send_other_messages=group_permissions['can_send_other_messages'],
|
||||||
|
can_send_polls=group_permissions['can_send_polls'],
|
||||||
|
can_invite_users=group_permissions['can_invite_users'],
|
||||||
|
can_change_info=group_permissions['can_change_info'],
|
||||||
|
can_add_web_page_previews=group_permissions['can_add_web_page_previews'],
|
||||||
|
can_pin_messages=group_permissions['can_pin_messages']
|
||||||
|
)
|
||||||
|
|
||||||
|
status = await bot.set_chat_permissions(chat_id=message.chat.id, permissions=chat_permissions)
|
||||||
|
|
||||||
|
if (status):
|
||||||
|
await message.answer(f"readonly - {check}")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["media"],commands_prefix="!",hasRights=True)
|
||||||
|
async def media_content(message: types.Message):
|
||||||
|
check = checkArg(message.text)
|
||||||
|
|
||||||
|
if (check is None):
|
||||||
|
await message.answer("!media on/off alias:disable,enable,start,stop.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get chat permissions
|
||||||
|
group_permissions = config.roles["group_permissions"]
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
chat_permissions = ChatPermissions(
|
||||||
|
can_send_messages=group_permissions['can_send_messages'],
|
||||||
|
can_send_media_messages=check,
|
||||||
|
can_send_other_messages=group_permissions['can_send_other_messages'],
|
||||||
|
can_send_polls=group_permissions['can_send_polls'],
|
||||||
|
can_invite_users=group_permissions['can_invite_users'],
|
||||||
|
can_change_info=group_permissions['can_change_info'],
|
||||||
|
can_add_web_page_previews=group_permissions['can_add_web_page_previews'],
|
||||||
|
can_pin_messages=group_permissions['can_pin_messages']
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set chat pemissions and save results
|
||||||
|
status = await bot.set_chat_permissions(chat_id=message.chat.id, permissions=chat_permissions)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"media - {check}.")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["stickers"],commands_prefix="!",hasRights=True)
|
||||||
|
async def send_stickes(message: types.Message):
|
||||||
|
# Get arguments
|
||||||
|
check = checkArg(message.text)
|
||||||
|
|
||||||
|
if (check is None):
|
||||||
|
await message.answer("!stickers on/off alias:disable,enable,start,stop")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get chat permissions
|
||||||
|
group_permissions = config.roles["group_permissions"]
|
||||||
|
|
||||||
|
# Set permissions.
|
||||||
|
chat_permissions = ChatPermissions(
|
||||||
|
can_send_messages=group_permissions['can_send_messages'],
|
||||||
|
can_send_media_messages=group_permissions['can_send_media_messages'],
|
||||||
|
can_send_other_messages=check,
|
||||||
|
can_send_polls=group_permissions['can_send_polls'],
|
||||||
|
can_invite_users=group_permissions['can_invite_users'],
|
||||||
|
can_change_info=group_permissions['can_change_info'],
|
||||||
|
can_add_web_page_previews=group_permissions['can_add_web_page_previews'],
|
||||||
|
can_pin_messages=group_permissions['can_pin_messages']
|
||||||
|
)
|
||||||
|
|
||||||
|
# Start and save to satus (bool)
|
||||||
|
status = await bot.set_chat_permissions(chat_id=message.chat.id, permissions=chat_permissions)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"stickes - {check}.")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["warn"],commands_prefix="!",hasRights=True)
|
||||||
|
async def warn_user(message: types.Message):
|
||||||
|
# Get information
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
reason = getArgument(command.arguments)
|
||||||
|
|
||||||
|
user = command.user
|
||||||
|
admin = message.from_user
|
||||||
|
|
||||||
|
if (user is None):
|
||||||
|
await message.answer((
|
||||||
|
"Usage:!warn @username reason=None\n"
|
||||||
|
"Reply to a message or use with username/id.")
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Add warning
|
||||||
|
database.change_reports(user.user_id, delete=True)
|
||||||
|
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.user_id}) has gotten a warning.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
database.create_restriction(user.user_id, admin.id, "warn", reason)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["reload"],commands_prefix="!")
|
||||||
|
async def reload(message:types.Message):
|
||||||
|
await utils.check_user_data()
|
||||||
|
|
||||||
|
group = await bot.get_chat(message.chat.id)
|
||||||
|
group_permissions = dict(group["permissions"])
|
||||||
|
|
||||||
|
with open("config/roles.json","r") as jsonfile:
|
||||||
|
data = json.load(jsonfile)
|
||||||
|
|
||||||
|
if group_permissions.keys() != data["group_permissions"].keys():
|
||||||
|
await message.answer("Add some permissions to roles.json")
|
||||||
|
return
|
||||||
|
|
||||||
|
for permission in group_permissions.keys():
|
||||||
|
data["group_permissions"][permission] = group_permissions[permission]
|
||||||
|
|
||||||
|
with open("config/roles.json", "w") as jsonfile:
|
||||||
|
json.dump(data, jsonfile,indent=4)
|
||||||
|
|
||||||
|
await message.answer(f"✅ The synchronization was successful.")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["srole"],commands_prefix="!",hasRights=True)
|
||||||
|
async def set_role(message:types.Message):
|
||||||
|
command = await getCommandArgs(message)
|
||||||
|
new_role = getArgument(command.arguments)
|
||||||
|
|
||||||
|
roles = config.roles
|
||||||
|
|
||||||
|
user = command.user
|
||||||
|
admin = database.search_single_member(Member.user_id,message.from_user)
|
||||||
|
|
||||||
|
if (admin is None):
|
||||||
|
return
|
||||||
|
|
||||||
|
if (user is None) or (new_role is None):
|
||||||
|
await message.answer("""
|
||||||
|
!srole @username/id role(owner,admin,helper,member)
|
||||||
|
Reply to a message or use with username.""")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not (new_role in roles["level"].keys()):
|
||||||
|
await message.answer(f"Role {new_role} not exists.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if (admin.user_id == user.user_id):
|
||||||
|
await message.answer("❌ You can't set role yourself.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if (roles['level'][new_role] > roles['level'][admin.role]):
|
||||||
|
await message.answer("Your rank is not high enough to change roles.")
|
||||||
|
return
|
||||||
|
|
||||||
|
database.update_member_data(user.user_id,[Member.role],[new_role])
|
||||||
|
|
||||||
|
await message.answer(f"{new_role.capitalize()} role set for [{user.first_name}](tg://user?id={user.user_id}).",
|
||||||
|
parse_mode="Markdown")
|
|
@ -0,0 +1,104 @@
|
||||||
|
from load import bot, dp, types
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
|
from load import database
|
||||||
|
from database.models import Member
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(content_types=["new_chat_members"])
|
||||||
|
async def welcome_message(message:types.Message):
|
||||||
|
# User
|
||||||
|
user = message.from_user
|
||||||
|
|
||||||
|
exists = database.check_data_exists(Member.user_id,user.id)
|
||||||
|
|
||||||
|
if (exists):
|
||||||
|
await message.answer("Спасибо что вы с нами.")
|
||||||
|
|
||||||
|
if not (exists):
|
||||||
|
database.register_user(user.id,user.first_name,user.username)
|
||||||
|
# TODO: translate it
|
||||||
|
await message.answer((
|
||||||
|
f"Привет,{user.first_name}\n"
|
||||||
|
"Просим ознакомится с [правилами](https://telegra.ph/Pravila-CHata-Open-Source-05-29)\n"
|
||||||
|
"Советы на 'хороший тон':\n"
|
||||||
|
"\t\t1.Формулируй свою мысль в 1-2 предложения\n"
|
||||||
|
"\t\t1.Не задавай [мета](nometa.xyz) вопросы\n"),
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
|
||||||
|
await message.delete()
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["leave"],chat_type=[types.ChatType.SUPERGROUP])
|
||||||
|
async def leave_group(message:types.Message):
|
||||||
|
user = message.from_user
|
||||||
|
args = message.text.split()
|
||||||
|
|
||||||
|
# TODO: translate it too
|
||||||
|
if (len(args) < 1) or not ( ' '.join(args[1:]) == "I UNDERSTAND" ):
|
||||||
|
await message.answer("Для того чтобы покинуть чат вам нужно ввести /leave I UNDERSTANT!")
|
||||||
|
return
|
||||||
|
|
||||||
|
database.delete_user(user.id)
|
||||||
|
|
||||||
|
# Ban user and save (bool)
|
||||||
|
status = await bot.kick_chat_member(chat_id=message.chat.id,user_id=user.id,until_date=None)
|
||||||
|
|
||||||
|
if status:
|
||||||
|
await message.answer(f"User [{user.first_name}](tg://user?id={user.id}) has laved chat forever.",
|
||||||
|
parse_mode="Markdown")
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["start","help"],chat_type=[types.ChatType.SUPERGROUP])
|
||||||
|
async def start_command_group(message:types.Message):
|
||||||
|
await message.answer((
|
||||||
|
f"Hi,**{message.from_user.first_name}**!\n"
|
||||||
|
"My commands:\n"
|
||||||
|
" /help , /start - read the message.\n"
|
||||||
|
" /me , /bio - member information (if member group)."),
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["bio","me"],chat_type=[types.ChatType.SUPERGROUP])
|
||||||
|
async def get_information(message: types.Message):
|
||||||
|
user = database.search_single_member(Member.user_id,message.from_user.id)
|
||||||
|
|
||||||
|
role_level = config.roles["level"]
|
||||||
|
|
||||||
|
if (user is None):
|
||||||
|
await message.answer("❌Sorry,you not member group.")
|
||||||
|
return
|
||||||
|
|
||||||
|
await message.answer((
|
||||||
|
f"User:[{user.first_name}](tg://user?id={user.user_id})\n"
|
||||||
|
f"level:{role_level[user.role]}\n"),
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["report"],replied=True,chat_type=[types.ChatType.SUPERGROUP])
|
||||||
|
async def report(message: types.Message):
|
||||||
|
args = message.text.split()
|
||||||
|
|
||||||
|
if (len(args) != 2):
|
||||||
|
await message.reply("Please,enter reason.")
|
||||||
|
return
|
||||||
|
|
||||||
|
reported_user = message.reply_to_message.from_user
|
||||||
|
reporter_user = message.from_user
|
||||||
|
reason = args[1]
|
||||||
|
|
||||||
|
# TODO: translate it
|
||||||
|
msg = ("Жалоба на: [{}](tg://user?id={})\nПожаловался:[{}](tg://user?id={})\nПричина: {}\n{}"
|
||||||
|
.format(reported_user['first_name'],
|
||||||
|
reported_user['id'],
|
||||||
|
reporter_user.first_name,
|
||||||
|
reporter_user.id,
|
||||||
|
reason,
|
||||||
|
message.reply_to_message.link("Link message", as_html=False)
|
||||||
|
))
|
||||||
|
|
||||||
|
await bot.send_message(config.telegram_log_chat_id, msg, parse_mode="Markdown")
|
||||||
|
|
||||||
|
@dp.message_handler(content_types=["left_chat_member"])
|
||||||
|
async def event_left_chat(message:types.Message):
|
||||||
|
await message.delete()
|
|
@ -0,0 +1 @@
|
||||||
|
from . import user
|
|
@ -0,0 +1,107 @@
|
||||||
|
from load import dp,types,database,bot
|
||||||
|
from database.models import Member
|
||||||
|
|
||||||
|
from aiogram.types import KeyboardButton,ReplyKeyboardMarkup
|
||||||
|
from aiogram.types.reply_keyboard import ReplyKeyboardRemove
|
||||||
|
|
||||||
|
import config
|
||||||
|
from keyboards.default import menu
|
||||||
|
|
||||||
|
from aiogram.types import CallbackQuery
|
||||||
|
from aiogram.dispatcher.filters import Text
|
||||||
|
|
||||||
|
from aiogram.dispatcher.storage import FSMContext
|
||||||
|
from states.report_message import States
|
||||||
|
|
||||||
|
from keyboards.inline.report_button import report_button
|
||||||
|
from keyboards.inline.callback_data import report_callback
|
||||||
|
|
||||||
|
@dp.message_handler(commands=["start","help"],chat_type=[types.ChatType.PRIVATE])
|
||||||
|
async def start_command_private(message:types.Message):
|
||||||
|
await message.answer((
|
||||||
|
"Hello,**{message.from_user.first_name}**!\n"
|
||||||
|
"\t\tMy commands:\n"
|
||||||
|
"\t\t/help , /start - read this message.")
|
||||||
|
,parse_mode="Markdown",reply_markup=menu
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keyboard
|
||||||
|
@dp.message_handler(Text(equals=["About Us"]))
|
||||||
|
async def about_us(message:types.Message):
|
||||||
|
await message.answer((
|
||||||
|
"Moderator bot - an open source project for managing a Telegram group.\n\n"
|
||||||
|
"Possibilities:\n"
|
||||||
|
"1. Role system\n"
|
||||||
|
"2. Simple commands such as !ban, !mute\n"
|
||||||
|
"3. Convenient sticker/photo disabling with !stickers, !media\n"
|
||||||
|
"4. Users can report admins.\n"
|
||||||
|
"5. Admins can give warnings to users.\n"
|
||||||
|
"\nRelease version:2.5.2\n"
|
||||||
|
"[Github](https://github.com/hok7z/moderator-bot)"),
|
||||||
|
parse_mode="Markdown"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(Text(equals=["Check restrictions"]),state=None)
|
||||||
|
async def check_for_restrict(message:types.Message):
|
||||||
|
user = message.from_user
|
||||||
|
restrictions = database.search_user_restriction(user_id=user.id)
|
||||||
|
|
||||||
|
if (restrictions is None):
|
||||||
|
await message.answer("✅No restrictions.")
|
||||||
|
return
|
||||||
|
|
||||||
|
for restriction in restrictions:
|
||||||
|
callback = report_callback.new(user_id=message.from_user.id)
|
||||||
|
markup = report_button("✉️ Report restriction",callback)
|
||||||
|
|
||||||
|
await message.answer(f"Restriction\n{restriction.operation}\nReason:{restriction.reason}\nDate:{restriction.date}",reply_markup=markup)
|
||||||
|
|
||||||
|
await States.state1.set()
|
||||||
|
|
||||||
|
@dp.callback_query_handler(text_contains="report_restriction",state=States.state1)
|
||||||
|
async def report_restriction(call:CallbackQuery,state:FSMContext):
|
||||||
|
await call.answer(cache_time=60)
|
||||||
|
|
||||||
|
# callback_data = call.data
|
||||||
|
# restriction_id = callback_data.split(":")[1]
|
||||||
|
|
||||||
|
markup = ReplyKeyboardMarkup(resize_keyboard=True)
|
||||||
|
cancel = KeyboardButton("❌ Cancel")
|
||||||
|
markup.add(cancel)
|
||||||
|
|
||||||
|
await state.update_data(restriction_id=restriction_id)
|
||||||
|
|
||||||
|
await call.message.answer("Please,enter your report.",reply_markup=markup)
|
||||||
|
|
||||||
|
@dp.message_handler(state=States.state2)
|
||||||
|
async def get_message_report(message: types.Message,state:FSMContext):
|
||||||
|
answer = message.text
|
||||||
|
|
||||||
|
if not ("Cancel" in answer):
|
||||||
|
|
||||||
|
restriction = database.search_user_restriction(message.from_user.id)
|
||||||
|
|
||||||
|
if (restriction is None):
|
||||||
|
return
|
||||||
|
|
||||||
|
#from_admin = restriction.from_admin
|
||||||
|
#to_user = restriction.to_user
|
||||||
|
|
||||||
|
reason = restriction.reason
|
||||||
|
if (not reason):
|
||||||
|
reason = "No reason"
|
||||||
|
|
||||||
|
await bot.send_message(config.telegram_log_chat_id,(
|
||||||
|
f"Report on restriction #{restriction_id}\n"
|
||||||
|
f"From admin:[{from_admin.first_name}](tg://user?id={from_admin.id})\n"
|
||||||
|
f"To user:[{from_admin.first_name}](tg://user?id={to_user.id})\n"
|
||||||
|
f"Reason:{reason}\n"
|
||||||
|
f"Message:{answer}"
|
||||||
|
),parse_mode="Markdown")
|
||||||
|
|
||||||
|
await message.answer("Report restriction sended",reply_markup=ReplyKeyboardRemove())
|
||||||
|
else:
|
||||||
|
await message.answer("Operation cancaled",reply_markup=ReplyKeyboardRemove())
|
||||||
|
|
||||||
|
await state.finish()
|
|
@ -0,0 +1,2 @@
|
||||||
|
from . import default
|
||||||
|
from . import inline
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .menu import menu
|
||||||
|
from .menu import cancel
|
|
@ -0,0 +1,19 @@
|
||||||
|
from aiogram.types import ReplyKeyboardMarkup,KeyboardButton
|
||||||
|
|
||||||
|
menu = ReplyKeyboardMarkup(
|
||||||
|
resize_keyboard=True,
|
||||||
|
keyboard=[
|
||||||
|
[
|
||||||
|
KeyboardButton("Check restrictions"),
|
||||||
|
KeyboardButton("About Us"),
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|
||||||
|
cancel = ReplyKeyboardMarkup(
|
||||||
|
resize_keyboard=True,
|
||||||
|
keyboard=[
|
||||||
|
[
|
||||||
|
KeyboardButton("❌Cancel")
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
|
@ -0,0 +1 @@
|
||||||
|
from . import report_button
|
|
@ -0,0 +1,4 @@
|
||||||
|
from aiogram.utils.callback_data import CallbackData
|
||||||
|
|
||||||
|
|
||||||
|
report_callback = CallbackData("report_restriction","user_id")
|
|
@ -0,0 +1,8 @@
|
||||||
|
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
|
|
||||||
|
|
||||||
|
def report_button(text,callback_data):
|
||||||
|
markup = InlineKeyboardMarkup()
|
||||||
|
button = InlineKeyboardButton(text,callback_data=callback_data)
|
||||||
|
markup.insert(button)
|
||||||
|
return markup
|
|
@ -0,0 +1,33 @@
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
from aiogram import types
|
||||||
|
from aiogram.bot.api import TelegramAPIServer
|
||||||
|
from aiogram.contrib.fsm_storage.memory import MemoryStorage
|
||||||
|
|
||||||
|
import config
|
||||||
|
import utils
|
||||||
|
import filters
|
||||||
|
|
||||||
|
from database.database import Database
|
||||||
|
|
||||||
|
|
||||||
|
database = Database()
|
||||||
|
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
storage = MemoryStorage()
|
||||||
|
|
||||||
|
tgc = utils.TelegramClientScrapper(config.api_id, config.api_hash, token=config.token, loop = loop)
|
||||||
|
|
||||||
|
bot = Bot(
|
||||||
|
token=config.token,
|
||||||
|
server=TelegramAPIServer.from_base(config.telegram_api_server)
|
||||||
|
)
|
||||||
|
|
||||||
|
dp = Dispatcher(bot, storage = storage)
|
||||||
|
|
||||||
|
dp.filters_factory.bind(filters.IsAdminFilter)
|
||||||
|
dp.filters_factory.bind(filters.ReplayMessageFilter)
|
||||||
|
dp.filters_factory.bind(filters.UserHasRights)
|
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -0,0 +1,707 @@
|
||||||
|
[[package]]
|
||||||
|
name = "aiogram"
|
||||||
|
version = "2.21"
|
||||||
|
description = "Is a pretty simple and fully asynchronous framework for Telegram Bot API"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
aiohttp = ">=3.8.0,<3.9.0"
|
||||||
|
Babel = ">=2.9.1,<2.10.0"
|
||||||
|
certifi = ">=2021.10.8"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
fast = ["uvloop (>=0.16.0,<0.17.0)", "ujson (>=1.35)"]
|
||||||
|
proxy = ["aiohttp-socks (>=0.5.3,<0.6.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiohttp"
|
||||||
|
version = "3.8.1"
|
||||||
|
description = "Async http client/server framework (asyncio)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
aiosignal = ">=1.1.2"
|
||||||
|
async-timeout = ">=4.0.0a3,<5.0"
|
||||||
|
attrs = ">=17.3.0"
|
||||||
|
charset-normalizer = ">=2.0,<3.0"
|
||||||
|
frozenlist = ">=1.1.1"
|
||||||
|
multidict = ">=4.5,<7.0"
|
||||||
|
yarl = ">=1.0,<2.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
speedups = ["aiodns", "brotli", "cchardet"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aioschedule"
|
||||||
|
version = "0.5.2"
|
||||||
|
description = "Job scheduling for humans."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiosignal"
|
||||||
|
version = "1.2.0"
|
||||||
|
description = "aiosignal: a list of registered asynchronous callbacks"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
frozenlist = ">=1.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-timeout"
|
||||||
|
version = "4.0.2"
|
||||||
|
description = "Timeout context manager for asyncio programs"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "attrs"
|
||||||
|
version = "22.1.0"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
|
||||||
|
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||||
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "babel"
|
||||||
|
version = "2.9.1"
|
||||||
|
description = "Internationalization utilities"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pytz = ">=2015.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2022.6.15"
|
||||||
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "2.1.0"
|
||||||
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
unicode_backport = ["unicodedata2"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "commonmark"
|
||||||
|
version = "0.9.1"
|
||||||
|
description = "Python parser for the CommonMark Markdown spec"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "environs"
|
||||||
|
version = "9.5.0"
|
||||||
|
description = "simplified environment variable parsing"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
marshmallow = ">=3.0.0"
|
||||||
|
python-dotenv = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "tox"]
|
||||||
|
django = ["dj-database-url", "dj-email-url", "django-cache-url"]
|
||||||
|
lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"]
|
||||||
|
tests = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "frozenlist"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "A list-like structure which implements collections.abc.MutableSequence"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.3"
|
||||||
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "marshmallow"
|
||||||
|
version = "3.17.0"
|
||||||
|
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
packaging = ">=17.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["pytest", "pytz", "simplejson", "mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)", "tox"]
|
||||||
|
docs = ["sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.8)"]
|
||||||
|
lint = ["mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)"]
|
||||||
|
tests = ["pytest", "pytz", "simplejson"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multidict"
|
||||||
|
version = "6.0.2"
|
||||||
|
description = "multidict implementation"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "21.3"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "peewee"
|
||||||
|
version = "3.15.1"
|
||||||
|
description = "a little orm"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psycopg2"
|
||||||
|
version = "2.9.3"
|
||||||
|
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyaes"
|
||||||
|
version = "1.6.1"
|
||||||
|
description = "Pure-Python Implementation of the AES block-cipher and common modes of operation"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyasn1"
|
||||||
|
version = "0.4.8"
|
||||||
|
description = "ASN.1 types and codecs"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pygments"
|
||||||
|
version = "2.12.0"
|
||||||
|
description = "Pygments is a syntax highlighting package written in Python."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyparsing"
|
||||||
|
version = "3.0.9"
|
||||||
|
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.8"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
diagrams = ["railroad-diagrams", "jinja2"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "python-dotenv"
|
||||||
|
version = "0.20.0"
|
||||||
|
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
cli = ["click (>=5.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytz"
|
||||||
|
version = "2022.1"
|
||||||
|
description = "World timezone definitions, modern and historical"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.28.1"
|
||||||
|
description = "Python HTTP for Humans."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7, <4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = ">=2017.4.17"
|
||||||
|
charset-normalizer = ">=2,<3"
|
||||||
|
idna = ">=2.5,<4"
|
||||||
|
urllib3 = ">=1.21.1,<1.27"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
|
use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rich"
|
||||||
|
version = "12.5.1"
|
||||||
|
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.3,<4.0.0"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
commonmark = ">=0.9.0,<0.10.0"
|
||||||
|
pygments = ">=2.6.0,<3.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rsa"
|
||||||
|
version = "4.9"
|
||||||
|
description = "Pure-Python RSA implementation"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6,<4"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyasn1 = ">=0.1.3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "telethon"
|
||||||
|
version = "1.24.0"
|
||||||
|
description = "Full-featured Telegram client library for Python 3"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyaes = "*"
|
||||||
|
rsa = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
cryptg = ["cryptg"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "1.26.11"
|
||||||
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
|
||||||
|
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yarl"
|
||||||
|
version = "1.8.1"
|
||||||
|
description = "Yet another URL library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
idna = ">=2.0"
|
||||||
|
multidict = ">=4.0"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "1.1"
|
||||||
|
python-versions = "^3.10"
|
||||||
|
content-hash = "cf2aa8bebb164e8dbd85f9e22232813ccaf44fdcd786cb900b459b0feeb738d6"
|
||||||
|
|
||||||
|
[metadata.files]
|
||||||
|
aiogram = [
|
||||||
|
{file = "aiogram-2.21-py3-none-any.whl", hash = "sha256:33ee61db550f6fc455e2d74d8911af31108e3c398eda03c2f91b0a7cb32a97d9"},
|
||||||
|
{file = "aiogram-2.21.tar.gz", hash = "sha256:390ac56a629cd0d151d544e3b87d539ee49f734ccc7a1a7e375c33f436e556e0"},
|
||||||
|
]
|
||||||
|
aiohttp = [
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7dadf3c307b31e0e61689cbf9e06be7a867c563d5a63ce9dca578f956609abf8"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a79004bb58748f31ae1cbe9fa891054baaa46fb106c2dc7af9f8e3304dc30316"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12de6add4038df8f72fac606dff775791a60f113a725c960f2bab01d8b8e6b15"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f0d5f33feb5f69ddd57a4a4bd3d56c719a141080b445cbf18f238973c5c9923"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eaba923151d9deea315be1f3e2b31cc39a6d1d2f682f942905951f4e40200922"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:099ebd2c37ac74cce10a3527d2b49af80243e2a4fa39e7bce41617fbc35fa3c1"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2e5d962cf7e1d426aa0e528a7e198658cdc8aa4fe87f781d039ad75dcd52c516"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fa0ffcace9b3aa34d205d8130f7873fcfefcb6a4dd3dd705b0dab69af6712642"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61bfc23df345d8c9716d03717c2ed5e27374e0fe6f659ea64edcd27b4b044cf7"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:31560d268ff62143e92423ef183680b9829b1b482c011713ae941997921eebc8"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:01d7bdb774a9acc838e6b8f1d114f45303841b89b95984cbb7d80ea41172a9e3"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97ef77eb6b044134c0b3a96e16abcb05ecce892965a2124c566af0fd60f717e2"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-win32.whl", hash = "sha256:c2aef4703f1f2ddc6df17519885dbfa3514929149d3ff900b73f45998f2532fa"},
|
||||||
|
{file = "aiohttp-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:713ac174a629d39b7c6a3aa757b337599798da4c1157114a314e4e391cd28e32"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:473d93d4450880fe278696549f2e7aed8cd23708c3c1997981464475f32137db"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b5eeae8e019e7aad8af8bb314fb908dd2e028b3cdaad87ec05095394cce632"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af642b43ce56c24d063325dd2cf20ee012d2b9ba4c3c008755a301aaea720ad"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3630c3ef435c0a7c549ba170a0633a56e92629aeed0e707fec832dee313fb7a"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4a4a4e30bf1edcad13fb0804300557aedd07a92cabc74382fdd0ba6ca2661091"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f8b01295e26c68b3a1b90efb7a89029110d3a4139270b24fda961893216c440"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a25fa703a527158aaf10dafd956f7d42ac6d30ec80e9a70846253dd13e2f067b"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5bfde62d1d2641a1f5173b8c8c2d96ceb4854f54a44c23102e2ccc7e02f003ec"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:51467000f3647d519272392f484126aa716f747859794ac9924a7aafa86cd411"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:03a6d5349c9ee8f79ab3ff3694d6ce1cfc3ced1c9d36200cb8f08ba06bd3b782"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:102e487eeb82afac440581e5d7f8f44560b36cf0bdd11abc51a46c1cd88914d4"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-win32.whl", hash = "sha256:4aed991a28ea3ce320dc8ce655875e1e00a11bdd29fe9444dd4f88c30d558602"},
|
||||||
|
{file = "aiohttp-3.8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b0e20cddbd676ab8a64c774fefa0ad787cc506afd844de95da56060348021e96"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:37951ad2f4a6df6506750a23f7cbabad24c73c65f23f72e95897bb2cecbae676"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c23b1ad869653bc818e972b7a3a79852d0e494e9ab7e1a701a3decc49c20d51"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15b09b06dae900777833fe7fc4b4aa426556ce95847a3e8d7548e2d19e34edb8"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:477c3ea0ba410b2b56b7efb072c36fa91b1e6fc331761798fa3f28bb224830dd"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2f2f69dca064926e79997f45b2f34e202b320fd3782f17a91941f7eb85502ee2"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ef9612483cb35171d51d9173647eed5d0069eaa2ee812793a75373447d487aa4"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6d69f36d445c45cda7b3b26afef2fc34ef5ac0cdc75584a87ef307ee3c8c6d00"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:55c3d1072704d27401c92339144d199d9de7b52627f724a949fc7d5fc56d8b93"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b9d00268fcb9f66fbcc7cd9fe423741d90c75ee029a1d15c09b22d23253c0a44"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:07b05cd3305e8a73112103c834e91cd27ce5b4bd07850c4b4dbd1877d3f45be7"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c34dc4958b232ef6188c4318cb7b2c2d80521c9a56c52449f8f93ab7bc2a8a1c"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-win32.whl", hash = "sha256:d2f9b69293c33aaa53d923032fe227feac867f81682f002ce33ffae978f0a9a9"},
|
||||||
|
{file = "aiohttp-3.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6ae828d3a003f03ae31915c31fa684b9890ea44c9c989056fea96e3d12a9fa17"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0c7ebbbde809ff4e970824b2b6cb7e4222be6b95a296e46c03cf050878fc1785"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b7ef7cbd4fec9a1e811a5de813311ed4f7ac7d93e0fda233c9b3e1428f7dd7b"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c3d6a4d0619e09dcd61021debf7059955c2004fa29f48788a3dfaf9c9901a7cd"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:718626a174e7e467f0558954f94af117b7d4695d48eb980146016afa4b580b2e"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:589c72667a5febd36f1315aa6e5f56dd4aa4862df295cb51c769d16142ddd7cd"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ed076098b171573161eb146afcb9129b5ff63308960aeca4b676d9d3c35e700"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:086f92daf51a032d062ec5f58af5ca6a44d082c35299c96376a41cbb33034675"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:11691cf4dc5b94236ccc609b70fec991234e7ef8d4c02dd0c9668d1e486f5abf"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:31d1e1c0dbf19ebccbfd62eff461518dcb1e307b195e93bba60c965a4dcf1ba0"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11a67c0d562e07067c4e86bffc1553f2cf5b664d6111c894671b2b8712f3aba5"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:bb01ba6b0d3f6c68b89fce7305080145d4877ad3acaed424bae4d4ee75faa950"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:44db35a9e15d6fe5c40d74952e803b1d96e964f683b5a78c3cc64eb177878155"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:844a9b460871ee0a0b0b68a64890dae9c415e513db0f4a7e3cab41a0f2fedf33"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-win32.whl", hash = "sha256:7d08744e9bae2ca9c382581f7dce1273fe3c9bae94ff572c3626e8da5b193c6a"},
|
||||||
|
{file = "aiohttp-3.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:04d48b8ce6ab3cf2097b1855e1505181bdd05586ca275f2505514a6e274e8e75"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5315a2eb0239185af1bddb1abf472d877fede3cc8d143c6cddad37678293237"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a996d01ca39b8dfe77440f3cd600825d05841088fd6bc0144cc6c2ec14cc5f74"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:13487abd2f761d4be7c8ff9080de2671e53fff69711d46de703c310c4c9317ca"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea302f34477fda3f85560a06d9ebdc7fa41e82420e892fc50b577e35fc6a50b2"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2f635ce61a89c5732537a7896b6319a8fcfa23ba09bec36e1b1ac0ab31270d2"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e999f2d0e12eea01caeecb17b653f3713d758f6dcc770417cf29ef08d3931421"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0770e2806a30e744b4e21c9d73b7bee18a1cfa3c47991ee2e5a65b887c49d5cf"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d15367ce87c8e9e09b0f989bfd72dc641bcd04ba091c68cd305312d00962addd"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c7cefb4b0640703eb1069835c02486669312bf2f12b48a748e0a7756d0de33d"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:71927042ed6365a09a98a6377501af5c9f0a4d38083652bcd2281a06a5976724"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:28d490af82bc6b7ce53ff31337a18a10498303fe66f701ab65ef27e143c3b0ef"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:b6613280ccedf24354406caf785db748bebbddcf31408b20c0b48cb86af76866"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81e3d8c34c623ca4e36c46524a3530e99c0bc95ed068fd6e9b55cb721d408fb2"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-win32.whl", hash = "sha256:7187a76598bdb895af0adbd2fb7474d7f6025d170bc0a1130242da817ce9e7d1"},
|
||||||
|
{file = "aiohttp-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:1c182cb873bc91b411e184dab7a2b664d4fea2743df0e4d57402f7f3fa644bac"},
|
||||||
|
{file = "aiohttp-3.8.1.tar.gz", hash = "sha256:fc5471e1a54de15ef71c1bc6ebe80d4dc681ea600e68bfd1cbce40427f0b7578"},
|
||||||
|
]
|
||||||
|
aioschedule = [
|
||||||
|
{file = "aioschedule-0.5.2.tar.gz", hash = "sha256:1fe8621d287f58cbba3d73695fbbd890355294ac0c01981a1fd1e4f0510fc744"},
|
||||||
|
]
|
||||||
|
aiosignal = [
|
||||||
|
{file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"},
|
||||||
|
{file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"},
|
||||||
|
]
|
||||||
|
async-timeout = [
|
||||||
|
{file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
|
||||||
|
{file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
|
||||||
|
]
|
||||||
|
attrs = [
|
||||||
|
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
|
||||||
|
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
|
||||||
|
]
|
||||||
|
babel = [
|
||||||
|
{file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"},
|
||||||
|
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
|
||||||
|
]
|
||||||
|
certifi = []
|
||||||
|
charset-normalizer = []
|
||||||
|
commonmark = [
|
||||||
|
{file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
|
||||||
|
{file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
|
||||||
|
]
|
||||||
|
environs = [
|
||||||
|
{file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"},
|
||||||
|
{file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"},
|
||||||
|
]
|
||||||
|
frozenlist = [
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f271c93f001748fc26ddea409241312a75e13466b06c94798d1a341cf0e6989"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c6ef8014b842f01f5d2b55315f1af5cbfde284eb184075c189fd657c2fd8204"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:219a9676e2eae91cb5cc695a78b4cb43d8123e4160441d2b6ce8d2c70c60e2f3"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d64cdd973aede3dd71a9364742c542587db214e63b7529fbb487ed67cddd9"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2af6f7a4e93f5d08ee3f9152bce41a6015b5cf87546cb63872cc19b45476e98a"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a718b427ff781c4f4e975525edb092ee2cdef6a9e7bc49e15063b088961806f8"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c56c299602c70bc1bb5d1e75f7d8c007ca40c9d7aebaf6e4ba52925d88ef826d"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717470bfafbb9d9be624da7780c4296aa7935294bd43a075139c3d55659038ca"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:31b44f1feb3630146cffe56344704b730c33e042ffc78d21f2125a6a91168131"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c3b31180b82c519b8926e629bf9f19952c743e089c41380ddca5db556817b221"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d82bed73544e91fb081ab93e3725e45dd8515c675c0e9926b4e1f420a93a6ab9"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49459f193324fbd6413e8e03bd65789e5198a9fa3095e03f3620dee2f2dabff2"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:94e680aeedc7fd3b892b6fa8395b7b7cc4b344046c065ed4e7a1e390084e8cb5"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-win32.whl", hash = "sha256:fabb953ab913dadc1ff9dcc3a7a7d3dc6a92efab3a0373989b8063347f8705be"},
|
||||||
|
{file = "frozenlist-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:eee0c5ecb58296580fc495ac99b003f64f82a74f9576a244d04978a7e97166db"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bc75692fb3770cf2b5856a6c2c9de967ca744863c5e89595df64e252e4b3944"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086ca1ac0a40e722d6833d4ce74f5bf1aba2c77cbfdc0cd83722ffea6da52a04"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b51eb355e7f813bcda00276b0114c4172872dc5fb30e3fea059b9367c18fbcb"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74140933d45271c1a1283f708c35187f94e1256079b3c43f0c2267f9db5845ff"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4c5120ddf7d4dd1eaf079af3af7102b56d919fa13ad55600a4e0ebe532779b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97d9e00f3ac7c18e685320601f91468ec06c58acc185d18bb8e511f196c8d4b2"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6e19add867cebfb249b4e7beac382d33215d6d54476bb6be46b01f8cafb4878b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a027f8f723d07c3f21963caa7d585dcc9b089335565dabe9c814b5f70c52705a"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:61d7857950a3139bce035ad0b0945f839532987dfb4c06cfe160254f4d19df03"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:53b2b45052e7149ee8b96067793db8ecc1ae1111f2f96fe1f88ea5ad5fd92d10"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bbb1a71b1784e68870800b1bc9f3313918edc63dbb8f29fbd2e767ce5821696c"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ab6fa8c7871877810e1b4e9392c187a60611fbf0226a9e0b11b7b92f5ac72792"},
|
||||||
|
{file = "frozenlist-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f89139662cc4e65a4813f4babb9ca9544e42bddb823d2ec434e18dad582543bc"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4c0c99e31491a1d92cde8648f2e7ccad0e9abb181f6ac3ddb9fc48b63301808e"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61e8cb51fba9f1f33887e22488bad1e28dd8325b72425f04517a4d285a04c519"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc2f3e368ee5242a2cbe28323a866656006382872c40869b49b265add546703f"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58fb94a01414cddcdc6839807db77ae8057d02ddafc94a42faee6004e46c9ba8"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:022178b277cb9277d7d3b3f2762d294f15e85cd2534047e68a118c2bb0058f3e"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:572ce381e9fe027ad5e055f143763637dcbac2542cfe27f1d688846baeef5170"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19127f8dcbc157ccb14c30e6f00392f372ddb64a6ffa7106b26ff2196477ee9f"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42719a8bd3792744c9b523674b752091a7962d0d2d117f0b417a3eba97d1164b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2743bb63095ef306041c8f8ea22bd6e4d91adabf41887b1ad7886c4c1eb43d5f"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fa47319a10e0a076709644a0efbcaab9e91902c8bd8ef74c6adb19d320f69b83"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:52137f0aea43e1993264a5180c467a08a3e372ca9d378244c2d86133f948b26b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:f5abc8b4d0c5b556ed8cd41490b606fe99293175a82b98e652c3f2711b452988"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:1e1cf7bc8cbbe6ce3881863671bac258b7d6bfc3706c600008925fb799a256e2"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-win32.whl", hash = "sha256:0dde791b9b97f189874d654c55c24bf7b6782343e14909c84beebd28b7217845"},
|
||||||
|
{file = "frozenlist-1.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:9494122bf39da6422b0972c4579e248867b6b1b50c9b05df7e04a3f30b9a413d"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31bf9539284f39ff9398deabf5561c2b0da5bb475590b4e13dd8b268d7a3c5c1"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0c8c803f2f8db7217898d11657cb6042b9b0553a997c4a0601f48a691480fab"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da5ba7b59d954f1f214d352308d1d86994d713b13edd4b24a556bcc43d2ddbc3"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e6b2b456f21fc93ce1aff2b9728049f1464428ee2c9752a4b4f61e98c4db96"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:526d5f20e954d103b1d47232e3839f3453c02077b74203e43407b962ab131e7b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b499c6abe62a7a8d023e2c4b2834fce78a6115856ae95522f2f974139814538c"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab386503f53bbbc64d1ad4b6865bf001414930841a870fc97f1546d4d133f141"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f63c308f82a7954bf8263a6e6de0adc67c48a8b484fab18ff87f349af356efd"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:12607804084d2244a7bd4685c9d0dca5df17a6a926d4f1967aa7978b1028f89f"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:da1cdfa96425cbe51f8afa43e392366ed0b36ce398f08b60de6b97e3ed4affef"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f810e764617b0748b49a731ffaa525d9bb36ff38332411704c2400125af859a6"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:35c3d79b81908579beb1fb4e7fcd802b7b4921f1b66055af2578ff7734711cfa"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c92deb5d9acce226a501b77307b3b60b264ca21862bd7d3e0c1f3594022f01bc"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-win32.whl", hash = "sha256:5e77a8bd41e54b05e4fb2708dc6ce28ee70325f8c6f50f3df86a44ecb1d7a19b"},
|
||||||
|
{file = "frozenlist-1.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:625d8472c67f2d96f9a4302a947f92a7adbc1e20bedb6aff8dbc8ff039ca6189"},
|
||||||
|
{file = "frozenlist-1.3.1.tar.gz", hash = "sha256:3a735e4211a04ccfa3f4833547acdf5d2f863bfeb01cfd3edaffbc251f15cec8"},
|
||||||
|
]
|
||||||
|
idna = [
|
||||||
|
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||||
|
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||||
|
]
|
||||||
|
marshmallow = []
|
||||||
|
multidict = [
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"},
|
||||||
|
{file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"},
|
||||||
|
{file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"},
|
||||||
|
{file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"},
|
||||||
|
{file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"},
|
||||||
|
{file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"},
|
||||||
|
]
|
||||||
|
packaging = [
|
||||||
|
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||||
|
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||||
|
]
|
||||||
|
peewee = []
|
||||||
|
psycopg2 = [
|
||||||
|
{file = "psycopg2-2.9.3-cp310-cp310-win32.whl", hash = "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362"},
|
||||||
|
{file = "psycopg2-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca"},
|
||||||
|
{file = "psycopg2-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56"},
|
||||||
|
{file = "psycopg2-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305"},
|
||||||
|
{file = "psycopg2-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2"},
|
||||||
|
{file = "psycopg2-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461"},
|
||||||
|
{file = "psycopg2-2.9.3-cp38-cp38-win32.whl", hash = "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7"},
|
||||||
|
{file = "psycopg2-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf"},
|
||||||
|
{file = "psycopg2-2.9.3-cp39-cp39-win32.whl", hash = "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126"},
|
||||||
|
{file = "psycopg2-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c"},
|
||||||
|
{file = "psycopg2-2.9.3.tar.gz", hash = "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981"},
|
||||||
|
]
|
||||||
|
pyaes = [
|
||||||
|
{file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"},
|
||||||
|
]
|
||||||
|
pyasn1 = [
|
||||||
|
{file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
|
||||||
|
{file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"},
|
||||||
|
{file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"},
|
||||||
|
{file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"},
|
||||||
|
{file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"},
|
||||||
|
{file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"},
|
||||||
|
{file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"},
|
||||||
|
]
|
||||||
|
pygments = [
|
||||||
|
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
|
||||||
|
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
|
||||||
|
]
|
||||||
|
pyparsing = [
|
||||||
|
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||||
|
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||||
|
]
|
||||||
|
python-dotenv = [
|
||||||
|
{file = "python-dotenv-0.20.0.tar.gz", hash = "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f"},
|
||||||
|
{file = "python_dotenv-0.20.0-py3-none-any.whl", hash = "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"},
|
||||||
|
]
|
||||||
|
pytz = [
|
||||||
|
{file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
|
||||||
|
{file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
|
||||||
|
]
|
||||||
|
requests = [
|
||||||
|
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
|
||||||
|
{file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
|
||||||
|
]
|
||||||
|
rich = []
|
||||||
|
rsa = []
|
||||||
|
telethon = [
|
||||||
|
{file = "Telethon-1.24.0-py3-none-any.whl", hash = "sha256:04fdc5fa4ed3e886e6ecf4bad79205ab8880c6aefbd42c29c89c689a502aa816"},
|
||||||
|
{file = "Telethon-1.24.0.tar.gz", hash = "sha256:818cb61281ed3f75ba4da9b68cb69486bed9474d2db4e0aa16e482053117452c"},
|
||||||
|
]
|
||||||
|
urllib3 = []
|
||||||
|
yarl = [
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"},
|
||||||
|
{file = "yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"},
|
||||||
|
{file = "yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"},
|
||||||
|
{file = "yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"},
|
||||||
|
{file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"},
|
||||||
|
{file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"},
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "moderator_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Telegram bot for moderation of Telegram groups."
|
||||||
|
authors = ["hok7z <hok7zv@tutanota.com>"]
|
||||||
|
license = "GPL3"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
aiogram = "^2.20"
|
||||||
|
peewee = "^3.14.10"
|
||||||
|
rich = "^12.4.4"
|
||||||
|
environs = "^9.5.0"
|
||||||
|
requests = "^2.27.1"
|
||||||
|
Telethon = "^1.24.0"
|
||||||
|
psycopg2 = "^2.9.3"
|
||||||
|
aioschedule = "^0.5.2"
|
||||||
|
|
||||||
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
|
@ -0,0 +1,6 @@
|
||||||
|
from aiogram.dispatcher.filters.state import StatesGroup,State
|
||||||
|
|
||||||
|
|
||||||
|
class States(StatesGroup):
|
||||||
|
state1 = State()
|
||||||
|
state2 = State()
|
|
@ -0,0 +1,231 @@
|
||||||
|
bit.ly
|
||||||
|
goo.gl
|
||||||
|
tinyurl.com
|
||||||
|
is.gd
|
||||||
|
cli.gs
|
||||||
|
pic.gd
|
||||||
|
DwarfURL.com
|
||||||
|
ow.ly
|
||||||
|
yfrog.com
|
||||||
|
migre.me
|
||||||
|
ff.im
|
||||||
|
tiny.cc
|
||||||
|
url4.eu
|
||||||
|
tr.im
|
||||||
|
twit.ac
|
||||||
|
su.pr
|
||||||
|
twurl.nl
|
||||||
|
snipurl.com
|
||||||
|
BudURL.com
|
||||||
|
short.to
|
||||||
|
ping.fm
|
||||||
|
Digg.com
|
||||||
|
post.ly
|
||||||
|
Just.as
|
||||||
|
.tk
|
||||||
|
bkite.com
|
||||||
|
snipr.com
|
||||||
|
flic.kr
|
||||||
|
loopt.us
|
||||||
|
doiop.com
|
||||||
|
twitthis.com
|
||||||
|
htxt.it
|
||||||
|
AltURL.com
|
||||||
|
RedirX.com
|
||||||
|
DigBig.com
|
||||||
|
short.ie
|
||||||
|
u.mavrev.com
|
||||||
|
kl.am
|
||||||
|
wp.me
|
||||||
|
u.nu
|
||||||
|
rubyurl.com
|
||||||
|
om.ly
|
||||||
|
linkbee.com
|
||||||
|
Yep.it
|
||||||
|
posted.at
|
||||||
|
xrl.us
|
||||||
|
metamark.net
|
||||||
|
sn.im
|
||||||
|
hurl.ws
|
||||||
|
eepurl.com
|
||||||
|
idek.net
|
||||||
|
urlpire.com
|
||||||
|
chilp.it
|
||||||
|
moourl.com
|
||||||
|
snurl.com
|
||||||
|
xr.com
|
||||||
|
lin.cr
|
||||||
|
EasyURI.com
|
||||||
|
zz.gd
|
||||||
|
ur1.ca
|
||||||
|
URL.ie
|
||||||
|
adjix.com
|
||||||
|
twurl.cc
|
||||||
|
s7y.us shrinkify
|
||||||
|
EasyURL.net
|
||||||
|
atu.ca
|
||||||
|
sp2.ro
|
||||||
|
Profile.to
|
||||||
|
ub0.cc
|
||||||
|
minurl.fr
|
||||||
|
cort.as
|
||||||
|
fire.to
|
||||||
|
2tu.us
|
||||||
|
twiturl.de
|
||||||
|
to.ly
|
||||||
|
BurnURL.com
|
||||||
|
nn.nf
|
||||||
|
clck.ru
|
||||||
|
notlong.com
|
||||||
|
thrdl.es
|
||||||
|
spedr.com
|
||||||
|
vl.am
|
||||||
|
miniurl.com
|
||||||
|
virl.com
|
||||||
|
PiURL.com
|
||||||
|
1url.com
|
||||||
|
gri.ms
|
||||||
|
tr.my
|
||||||
|
Sharein.com
|
||||||
|
urlzen.com
|
||||||
|
fon.gs
|
||||||
|
Shrinkify.com
|
||||||
|
ri.ms
|
||||||
|
b23.ru
|
||||||
|
Fly2.ws
|
||||||
|
xrl.in
|
||||||
|
Fhurl.com
|
||||||
|
wipi.es
|
||||||
|
korta.nu
|
||||||
|
shortna.me
|
||||||
|
fa.b
|
||||||
|
WapURL.co.uk
|
||||||
|
urlcut.com
|
||||||
|
6url.com
|
||||||
|
abbrr.com
|
||||||
|
SimURL.com
|
||||||
|
klck.me
|
||||||
|
x.se
|
||||||
|
2big.at
|
||||||
|
url.co.uk
|
||||||
|
ewerl.com
|
||||||
|
inreply.to
|
||||||
|
TightURL.com
|
||||||
|
a.gg
|
||||||
|
tinytw.it
|
||||||
|
zi.pe
|
||||||
|
riz.gd
|
||||||
|
hex.io
|
||||||
|
fwd4.me
|
||||||
|
bacn.me
|
||||||
|
shrt.st
|
||||||
|
ln-s.ru
|
||||||
|
tiny.pl
|
||||||
|
o-x.fr
|
||||||
|
StartURL.com
|
||||||
|
jijr.com
|
||||||
|
shorl.com
|
||||||
|
icanhaz.com
|
||||||
|
updating.me
|
||||||
|
kissa.be
|
||||||
|
hellotxt.com
|
||||||
|
pnt.me
|
||||||
|
nsfw.in
|
||||||
|
xurl.jp
|
||||||
|
yweb.com
|
||||||
|
urlkiss.com
|
||||||
|
QLNK.net
|
||||||
|
w3t.org
|
||||||
|
lt.tl
|
||||||
|
twirl.at
|
||||||
|
zipmyurl.com
|
||||||
|
urlot.com
|
||||||
|
a.nf
|
||||||
|
hurl.me
|
||||||
|
URLHawk.com
|
||||||
|
Tnij.org
|
||||||
|
4url.cc
|
||||||
|
firsturl.de
|
||||||
|
Hurl.it
|
||||||
|
sturly.com
|
||||||
|
shrinkster.com
|
||||||
|
ln-s.net
|
||||||
|
go2cut.com
|
||||||
|
liip.to
|
||||||
|
shw.me
|
||||||
|
XeeURL.com
|
||||||
|
liltext.com
|
||||||
|
lnk.gd
|
||||||
|
xzb.cc
|
||||||
|
linkbun.ch
|
||||||
|
href.in
|
||||||
|
urlbrief.com
|
||||||
|
2ya.com
|
||||||
|
safe.mn
|
||||||
|
shrunkin.com
|
||||||
|
bloat.me
|
||||||
|
krunchd.com
|
||||||
|
minilien.com
|
||||||
|
ShortLinks.co.uk
|
||||||
|
qicute.com
|
||||||
|
rb6.me
|
||||||
|
urlx.ie
|
||||||
|
pd.am
|
||||||
|
go2.me
|
||||||
|
tinyarro.ws
|
||||||
|
tinyvid.io
|
||||||
|
lurl.no
|
||||||
|
ru.ly
|
||||||
|
lru.jp
|
||||||
|
rickroll.it
|
||||||
|
togoto.us
|
||||||
|
ClickMeter.com
|
||||||
|
hugeurl.com
|
||||||
|
tinyuri.ca
|
||||||
|
shrten.com
|
||||||
|
shorturl.com
|
||||||
|
Quip-Art.com
|
||||||
|
urlao.com
|
||||||
|
a2a.me
|
||||||
|
tcrn.ch
|
||||||
|
goshrink.com
|
||||||
|
DecentURL.com
|
||||||
|
decenturl.com
|
||||||
|
zi.ma
|
||||||
|
1link.in
|
||||||
|
sharetabs.com
|
||||||
|
shoturl.us
|
||||||
|
fff.to
|
||||||
|
hover.com
|
||||||
|
lnk.in
|
||||||
|
jmp2.net
|
||||||
|
dy.fi
|
||||||
|
urlcover.com
|
||||||
|
2pl.us
|
||||||
|
tweetburner.com
|
||||||
|
u6e.de
|
||||||
|
xaddr.com
|
||||||
|
gl.am
|
||||||
|
dfl8.me
|
||||||
|
go.9nl.com
|
||||||
|
gurl.es
|
||||||
|
C-O.IN
|
||||||
|
TraceURL.com
|
||||||
|
liurl.cn
|
||||||
|
MyURL.in
|
||||||
|
urlenco.de
|
||||||
|
ne1.net
|
||||||
|
buk.me
|
||||||
|
rsmonkey.com
|
||||||
|
cuturl.com
|
||||||
|
turo.us
|
||||||
|
sqrl.it
|
||||||
|
iterasi.net
|
||||||
|
tiny123.com
|
||||||
|
EsyURL.com
|
||||||
|
urlx.org
|
||||||
|
IsCool.net
|
||||||
|
twitterpan.com
|
||||||
|
GoWat.ch
|
||||||
|
poprl.com
|
||||||
|
njx.me
|
|
@ -0,0 +1,9 @@
|
||||||
|
from .notify_start import notify_started_bot
|
||||||
|
from .default_commands import set_default_commands
|
||||||
|
|
||||||
|
from .update_user_data import check_user_data
|
||||||
|
|
||||||
|
from .telegram_client import TelegramClientScrapper
|
||||||
|
from .parse_timedelta import parse_timedelta
|
||||||
|
|
||||||
|
from .virustotal import VirusTotalAPI
|
|
@ -0,0 +1,6 @@
|
||||||
|
async def set_default_commands(dp):
|
||||||
|
from load import types
|
||||||
|
await dp.bot.set_my_commands([
|
||||||
|
types.BotCommand("start","Start bot"),
|
||||||
|
types.BotCommand("help","Help")
|
||||||
|
])
|
|
@ -0,0 +1,4 @@
|
||||||
|
import config
|
||||||
|
|
||||||
|
async def notify_started_bot(bot):
|
||||||
|
await bot.send_message(config.telegram_log_chat_id,"Bot started!")
|
|
@ -0,0 +1,12 @@
|
||||||
|
import re
|
||||||
|
import datetime as dt
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
def parse_timedelta(specification: str) -> Union[None, dt.timedelta]:
|
||||||
|
specification = specification.strip().replace(' ', '')
|
||||||
|
match = re.fullmatch(r'(?:(\d+)(?:d|д))?(?:(\d+)(?:h|ч))?(?:(\d+)(?:m|м))?(?:(\d+)(?:s|с))?', specification)
|
||||||
|
if match:
|
||||||
|
units = [(0 if i is None else int(i)) for i in match.groups()]
|
||||||
|
return dt.timedelta(days=units[0], hours=units[1], minutes=units[2], seconds=units[3])
|
||||||
|
else:
|
||||||
|
return None
|
|
@ -0,0 +1,61 @@
|
||||||
|
from telethon import TelegramClient
|
||||||
|
from telethon.errors import SessionPasswordNeededError
|
||||||
|
from telethon.tl.functions.channels import GetParticipantsRequest
|
||||||
|
from telethon.tl.types import ChannelParticipantsSearch
|
||||||
|
from telethon.tl.types import PeerChannel
|
||||||
|
|
||||||
|
|
||||||
|
class TelegramClientScrapper:
|
||||||
|
def __init__(self, api_id, api_hash, phone=None, token=None, loop=None):
|
||||||
|
self.api_id = api_id
|
||||||
|
self.api_hash = api_hash
|
||||||
|
self.phone = phone
|
||||||
|
self.loop = loop
|
||||||
|
self.token = token
|
||||||
|
|
||||||
|
async def _connect(self):
|
||||||
|
self.client = TelegramClient("session", self.api_id, self.api_hash, loop=self.loop)
|
||||||
|
await self.client.start(bot_token=self.token)
|
||||||
|
if not await self.client.is_user_authorized():
|
||||||
|
await self.client.send_code_request(self.phone)
|
||||||
|
try:
|
||||||
|
await self.client.sign_in(self.phone, input("Enter you just recieved:"))
|
||||||
|
except SessionPasswordNeededError:
|
||||||
|
await self.client.sign_in(password=input("Enter password:"))
|
||||||
|
|
||||||
|
async def get_group_users(self, group_id):
|
||||||
|
|
||||||
|
chat_entity = PeerChannel(int(group_id))
|
||||||
|
|
||||||
|
offset = 0
|
||||||
|
limit = 100
|
||||||
|
list_participants = []
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
participants = await self.client(GetParticipantsRequest(
|
||||||
|
chat_entity, ChannelParticipantsSearch(''), offset, limit,
|
||||||
|
hash=0
|
||||||
|
))
|
||||||
|
|
||||||
|
if (not participants.users):
|
||||||
|
break
|
||||||
|
|
||||||
|
list_participants.extend(participants.users)
|
||||||
|
offset += len(participants.users)
|
||||||
|
|
||||||
|
participants_details = []
|
||||||
|
for participant in list_participants:
|
||||||
|
is_bot = participant.bot
|
||||||
|
user_name = participant.username
|
||||||
|
if (user_name):
|
||||||
|
user_name = f"@{user_name}"
|
||||||
|
|
||||||
|
if (not is_bot):
|
||||||
|
participants_details.append({
|
||||||
|
"id": participant.id,
|
||||||
|
"first_name": participant.first_name,
|
||||||
|
"user_name":user_name
|
||||||
|
})
|
||||||
|
|
||||||
|
return participants_details
|
|
@ -0,0 +1,37 @@
|
||||||
|
from database.models import Member
|
||||||
|
from config import group_id
|
||||||
|
|
||||||
|
async def __is_group_owner(user_id):
|
||||||
|
from load import bot
|
||||||
|
member = await bot.get_chat_member(group_id,user_id)
|
||||||
|
return member.is_chat_owner()
|
||||||
|
|
||||||
|
async def check_user_data():
|
||||||
|
"""Check user data in database and update it"""
|
||||||
|
from load import tgc,database
|
||||||
|
users = await tgc.get_group_users(group_id)
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
user_exists = database.check_data_exists(Member.user_id,user["id"])
|
||||||
|
|
||||||
|
role = "member"
|
||||||
|
if (await __is_group_owner(user["id"])):role = "owner"
|
||||||
|
|
||||||
|
if (not user_exists):
|
||||||
|
user_name = user["user_name"]
|
||||||
|
|
||||||
|
if (user_name):
|
||||||
|
user_name = f"@{user_name}"
|
||||||
|
|
||||||
|
database.register_user(
|
||||||
|
user["id"],
|
||||||
|
user["first_name"],
|
||||||
|
user["user_name"],
|
||||||
|
role,
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
database.update_member_data(user["id"],
|
||||||
|
[Member.first_name,Member.user_name],
|
||||||
|
[user["first_name",user["user_name"]]]
|
||||||
|
)
|
|
@ -0,0 +1,77 @@
|
||||||
|
import io
|
||||||
|
from typing import Union,Any
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
# TODO: skip queue virustotal
|
||||||
|
class VirusTotalAPI:
|
||||||
|
def __init__(self,apikey:str,local_telegram_api:bool):
|
||||||
|
self.apikey = apikey
|
||||||
|
self.local_telegram_api = local_telegram_api
|
||||||
|
|
||||||
|
async def __download_file(self,filepath:str,
|
||||||
|
*args,**kw) -> Union[io.BytesIO,Any]:
|
||||||
|
|
||||||
|
if ( self.local_telegram_api ):
|
||||||
|
with open(filepath,'rb') as bf:
|
||||||
|
return io.BytesIO(bf.read())
|
||||||
|
else:
|
||||||
|
from load import bot
|
||||||
|
return await bot.download_file(filepath,
|
||||||
|
*args,**kw)
|
||||||
|
|
||||||
|
async def __file_scan(self,filepath) -> None:
|
||||||
|
file = await self.__download_file(filepath)
|
||||||
|
|
||||||
|
url = "https://www.virustotal.com/vtapi/v2/file/scan"
|
||||||
|
params = {"apikey":self.apikey,"file":file}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
response = await session.post(url,data=params)
|
||||||
|
response = await response.json()
|
||||||
|
|
||||||
|
return response["sha1"]
|
||||||
|
|
||||||
|
async def __file_report(self,resource) -> dict:
|
||||||
|
url = "https://www.virustotal.com/vtapi/v2/file/report"
|
||||||
|
params = {"apikey":self.apikey,"resource":resource}
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
response = await session.get(url,params=params)
|
||||||
|
response = await response.json()
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def format_output(self,file_report:dict) -> str:
|
||||||
|
"""Format file_report
|
||||||
|
File Analys
|
||||||
|
Status:Infected/Clear
|
||||||
|
Positives:positives/total percent%
|
||||||
|
File Report
|
||||||
|
"""
|
||||||
|
|
||||||
|
total = file_report["total"]
|
||||||
|
positives = file_report["positives"]
|
||||||
|
permalink = file_report["permalink"]
|
||||||
|
percent = round(positives/total*100)
|
||||||
|
|
||||||
|
if (percent >= 40):
|
||||||
|
status = "Infected ☣️"
|
||||||
|
else:
|
||||||
|
status = "Clear ✅"
|
||||||
|
|
||||||
|
output = (
|
||||||
|
(
|
||||||
|
"File Analys\n"
|
||||||
|
f"Detected:{positives}/{total} %{percent}\n"
|
||||||
|
f"Status:{status}\n"
|
||||||
|
f"[File Report]({permalink})\n"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
async def scan_file(self,filepath:str) -> str:
|
||||||
|
resource = await self.__file_scan(filepath)
|
||||||
|
file_report = await self.__file_report(resource)
|
||||||
|
|
||||||
|
return file_report
|
Reference in New Issue