Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
cbdiscord
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Geovanny E. Vera Pazmino
cbdiscord
Commits
bcdaeacd
Commit
bcdaeacd
authored
Apr 17, 2020
by
Geovanny
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added helper for commands
parent
5a711f4b
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
430 additions
and
40 deletions
+430
-40
bot.py
discord/bot.py
+15
-1
manager.py
discord/unit/manager.py
+8
-39
manager.py
discord/user/manager.py
+9
-0
help.py
discord/util/help.py
+212
-0
pager.py
discord/util/pager.py
+186
-0
No files found.
discord/bot.py
View file @
bcdaeacd
...
...
@@ -7,15 +7,29 @@ from discord.ext import commands
from
unit.manager
import
UnitManager
from
user.manager
import
UserManager
from
util.command_error_handler
import
CommandErrorHandler
from
util.help
import
EditedMinimalHelpCommand
,
PaginatedHelpCommand
from
util.api_requests
import
Api
from
settings
import
DISCORD_TOKEN
class
ConqBot
(
commands
.
Bot
):
def
__init__
(
self
,
command_prefix
=
'>'
):
super
()
.
__init__
(
command_prefix
)
super
()
.
__init__
(
command_prefix
=
command_prefix
,
help_command
=
EditedMinimalHelpCommand
())
self
.
id_to_session
=
{}
self
.
static_help_command
=
self
.
help_command
command_impl
=
self
.
help_command
.
_command_impl
self
.
help_command
=
PaginatedHelpCommand
()
self
.
static_help_command
.
_command_impl
=
command_impl
# self.remove_command('help')
# self.add_command(commands.Command(self._help, name='help'))
async
def
_help
(
self
,
ctx
,
*
,
command
=
None
):
await
ctx
.
send_help
(
command
)
async
def
getUserSession
(
self
,
user
:
discord
.
User
):
if
user
.
id
in
self
.
id_to_session
:
return
self
.
id_to_session
[
user
.
id
]
...
...
discord/unit/manager.py
View file @
bcdaeacd
...
...
@@ -21,44 +21,11 @@ class UnitManager(commands.Cog):
else
:
return
await
ctx
.
send
(
'Unexpected error. Please try again'
)
#@commands.HelpCommand()
async
def
send_cog_help
(
self
,
cog
):
print
(
'Hello'
)
self
.
add_command_formatting
(
command
)
for
name
,
param
in
command
.
clean_params
.
items
():
if
isinstance
(
param
.
annotation
,
ArgumentConverter
):
arguments
=
param
.
annotation
.
arguments
if
not
arguments
:
continue
self
.
paginator
.
add_line
(
"Arguments:"
)
max_size
=
max
(
len
(
name
)
for
name
in
arguments
)
for
name
,
argument
in
arguments
.
items
():
entry
=
"{0}{1:<{width}} {2}"
.
format
(
self
.
indent
*
" "
,
name
,
argument
.
doc
,
width
=
max_size
)
self
.
paginator
.
add_line
(
self
.
shorten_text
(
entry
))
self
.
paginator
.
close_page
()
await
self
.
send_pages
()
async
def
send_bot_help
(
self
,
command
):
print
(
'There'
)
self
.
add_command_formatting
(
command
)
for
name
,
param
in
command
.
clean_params
.
items
():
if
isinstance
(
param
.
annotation
,
ArgumentConverter
):
arguments
=
param
.
annotation
.
arguments
if
not
arguments
:
continue
self
.
paginator
.
add_line
(
"Arguments:"
)
max_size
=
max
(
len
(
name
)
for
name
in
arguments
)
for
name
,
argument
in
arguments
.
items
():
entry
=
"{0}{1:<{width}} {2}"
.
format
(
self
.
indent
*
" "
,
name
,
argument
.
doc
,
width
=
max_size
)
self
.
paginator
.
add_line
(
self
.
shorten_text
(
entry
))
self
.
paginator
.
close_page
()
await
self
.
send_pages
()
@
commands
.
command
()
async
def
modifyUnit
(
self
,
ctx
,
unit
:
str
,
*
,
params
:
modify_param_converter
=
modify_param_converter
.
defaults
()):
"""Modify units by name or id. Specify parameters to be modified"""
"""Modify units by name or id. Specify parameters to be modified.
Example: modifyUnit 13 name=
\"
New Name
\"
type=
\"
New Type
\"
Help for more info"""
if
not
params
:
return
await
ctx
.
send
(
'Some parameters have to be provided'
)
...
...
@@ -91,7 +58,9 @@ class UnitManager(commands.Cog):
@
commands
.
command
()
async
def
insertUnit
(
self
,
ctx
,
name
:
str
,
*
,
params
:
insert_param_converter
=
insert_param_converter
.
defaults
()):
"""Insert unit by name. Additional parameters can be added"""
"""Insert unit by name. Additional parameters can be added
Example: insertUnit "New Name" type=
\"
New Type
\"
Help for more info"""
unit_data
=
params
;
unit_data
[
'name'
]
=
name
;
...
...
@@ -103,7 +72,7 @@ class UnitManager(commands.Cog):
return
await
self
.
handleApiError
(
ctx
,
error
)
@
commands
.
command
()
async
def
unit
i
nfo
(
self
,
ctx
,
*
,
unit
:
str
):
async
def
unit
I
nfo
(
self
,
ctx
,
*
,
unit
:
str
):
"""Get info from unit"""
data
=
None
...
...
@@ -144,7 +113,7 @@ class UnitManager(commands.Cog):
@
commands
.
command
()
async
def
all
u
nits
(
self
,
ctx
):
async
def
all
U
nits
(
self
,
ctx
):
"""Gets all units"""
data
=
await
Api
.
get
(
'/unit/all'
)
...
...
discord/user/manager.py
View file @
bcdaeacd
...
...
@@ -21,6 +21,7 @@ class UserManager(commands.Cog):
@
commands
.
command
()
async
def
registerUser
(
self
,
ctx
):
"""Register user. Only done once per user. Can't access user related content otherwise"""
req_body
=
{
'discordId'
:
ctx
.
message
.
author
.
id
}
try
:
await
Api
.
post
(
'/user/discord-register'
,
req_body
)
...
...
@@ -30,6 +31,7 @@ class UserManager(commands.Cog):
@
commands
.
command
()
async
def
removeAssign
(
self
,
ctx
,
term
:
str
):
"""Unassign unit from yourself"""
data
=
None
try
:
session
=
await
self
.
bot
.
getUserSession
(
ctx
.
message
.
author
)
...
...
@@ -55,6 +57,9 @@ class UserManager(commands.Cog):
@
commands
.
command
()
async
def
modUnit
(
self
,
ctx
,
term
:
str
,
*
,
params
:
param_converter
=
param_converter
.
defaults
()):
"""Modify unit assigned.
Example: modUnit
\"
Yelmo
\"
unit_level=20
Help for more info"""
data
=
None
try
:
session
=
await
self
.
bot
.
getUserSession
(
ctx
.
message
.
author
)
...
...
@@ -81,6 +86,9 @@ class UserManager(commands.Cog):
@
commands
.
command
()
async
def
assignUnit
(
self
,
ctx
,
term
:
str
,
*
,
params
:
param_converter
=
param_converter
.
defaults
()):
"""Assign unit to yourself.
Example: assignUnit
\"
Yelmo
\"
unit_level=1
Help for more info"""
data
=
None
try
:
data
=
await
Api
.
get
(
'/unit/{0}'
.
format
(
term
))
...
...
@@ -108,6 +116,7 @@ class UserManager(commands.Cog):
@
commands
.
command
()
async
def
myUnits
(
self
,
ctx
):
"""Get units assigned to user"""
try
:
session
=
await
self
.
bot
.
getUserSession
(
ctx
.
message
.
author
)
data
=
await
Api
.
getSession
(
'/user/units'
,
session
)
...
...
discord/util/help.py
0 → 100644
View file @
bcdaeacd
import
discord
from
discord.ext
import
commands
from
util.pager
import
Pager
import
discord_argparse
as
da
class
HelpPager
(
Pager
):
commands_per_page
=
8
indent
=
3
def
add_page
(
self
,
cog_name
,
cog_desc
,
cmds
):
'''Will split into several pages to accomodate the per_page limit.'''
# will obviously not run if no commands are in the page
for
cmds_slice
in
[
cmds
[
i
:
i
+
self
.
commands_per_page
]
for
i
in
range
(
0
,
len
(
cmds
),
self
.
commands_per_page
)]:
self
.
entries
.
append
((
cog_name
,
cog_desc
,
cmds_slice
))
async
def
craft_page
(
self
,
e
,
page
,
entries
):
cog_name
,
cog_desc
,
commands
=
entries
[
0
]
name
=
f
'{cog_name} Commands'
self
.
embed
.
set_author
(
name
=
name
,
icon_url
=
self
.
bot
.
user
.
avatar_url
)
self
.
embed
.
description
=
cog_desc
for
name
,
value
in
commands
:
self
.
embed
.
add_field
(
name
=
name
,
value
=
value
,
inline
=
False
)
async
def
craft_page_detail
(
self
,
cog_name
,
cog_desc
,
command
):
name
=
f
'{cog_name} Commands'
embed
=
discord
.
Embed
()
embed
.
set_author
(
name
=
name
,
icon_url
=
self
.
bot
.
user
.
avatar_url
)
embed
.
description
=
cog_desc
embed
.
add_field
(
name
=
command
.
name
,
value
=
command
.
help
,
inline
=
False
)
for
name
,
param
in
command
.
clean_params
.
items
():
if
isinstance
(
param
.
annotation
,
da
.
ArgumentConverter
):
arguments
=
param
.
annotation
.
arguments
if
not
arguments
:
continue
max_size
=
max
(
len
(
name
)
for
name
in
arguments
)
params_text
=
''
for
name
,
argument
in
arguments
.
items
():
entry
=
"{0}{1:<{width}} |
\t
{2}"
.
format
(
self
.
indent
*
" "
,
name
,
argument
.
doc
,
width
=
max_size
)
params_text
+=
"{0}
\n
"
.
format
(
entry
)
embed
.
add_field
(
name
=
"Arguments"
,
value
=
params_text
)
return
embed
async
def
help_embed
(
self
,
e
):
e
.
set_author
(
name
=
'How do I use the bot?'
,
icon_url
=
self
.
bot
.
user
.
avatar_url
)
e
.
description
=
(
'Invoke a command by sending the prefix followed by a command name.
\n\n
'
'For example, the command signature `track <query>` can be invoked by doing `track yellow`
\n\n
'
'The different argument brackets mean:'
)
e
.
add_field
(
name
=
'<argument>'
,
value
=
'the argument is required.'
,
inline
=
False
)
e
.
add_field
(
name
=
'[argument]'
,
value
=
'the argument is optional.
\n\u200b
'
,
inline
=
False
)
class
PaginatedHelpCommand
(
commands
.
HelpCommand
):
'''Cog that implements the help command and help pager.'''
async
def
add_command
(
self
,
cmds
,
command
,
force
=
False
):
if
command
.
hidden
:
return
if
force
is
False
:
try
:
if
not
await
command
.
can_run
(
self
.
context
):
return
except
commands
.
CheckFailure
:
return
help_message
=
command
.
brief
or
command
.
help
if
help_message
is
None
:
help_message
=
'No description available.'
else
:
help_message
=
help_message
.
split
(
'
\n
'
)[
0
]
cmds
.
append
((
self
.
context
.
prefix
+
get_signature
(
command
),
help_message
))
async
def
prepare_help_command
(
self
,
ctx
,
command
=
None
):
self
.
context
=
ctx
self
.
pager
=
HelpPager
(
ctx
,
list
(),
per_page
=
1
)
async
def
add_cog
(
self
,
cog
):
cog_name
=
cog
.
__class__
.
__name__
cog_desc
=
cog
.
__doc__
cmds
=
[]
added
=
[]
for
command
in
cog
.
walk_commands
():
if
command
in
added
:
continue
await
self
.
add_command
(
cmds
,
command
)
added
.
append
(
command
)
self
.
pager
.
add_page
(
cog_name
,
cog_desc
,
cmds
)
async
def
send_bot_help
(
self
,
mapping
):
for
cog
in
mapping
:
if
cog
is
not
None
:
await
self
.
add_cog
(
cog
)
await
self
.
pager
.
go
()
async
def
send_cog_help
(
self
,
cog
):
await
self
.
add_cog
(
cog
)
await
self
.
pager
.
go
()
async
def
send_group_help
(
self
,
group
):
if
group
.
cog_name
.
lower
()
==
group
.
name
.
lower
():
await
self
.
send_cog_help
(
group
.
cog
)
return
added
=
[]
cmds
=
[]
for
command
in
group
.
walk_commands
():
if
command
in
added
:
continue
await
self
.
add_command
(
cmds
,
command
)
added
.
append
(
command
)
self
.
pager
.
add_page
(
group
.
cog_name
,
group
.
cog
.
__doc__
,
cmds
)
await
self
.
pager
.
go
()
async
def
send_command_help
(
self
,
command
):
cog_name
=
command
.
cog_name
if
cog_name
is
not
None
and
cog_name
.
lower
()
==
command
.
name
:
await
self
.
send_cog_help
(
command
.
cog
)
return
cog_desc
=
command
.
cog
.
__doc__
embed
=
await
self
.
pager
.
craft_page_detail
(
cog_name
,
cog_desc
,
command
)
return
await
self
.
context
.
send
(
embed
=
embed
)
async
def
command_not_found
(
self
,
string
):
return
commands
.
CommandNotFound
(
string
)
async
def
send_error_message
(
self
,
error
):
if
not
isinstance
(
error
,
commands
.
CommandNotFound
):
return
cmd
=
str
(
error
)
for
cog
in
self
.
context
.
bot
.
cogs
:
if
cmd
==
cog
.
lower
():
await
self
.
send_cog_help
(
self
.
context
.
bot
.
get_cog
(
cog
))
return
await
self
.
context
.
send
(
'Command
\'
{}
\'
not found.'
.
format
(
cmd
))
class
EditedMinimalHelpCommand
(
commands
.
MinimalHelpCommand
):
def
get_ending_note
(
self
):
return
(
'The interactive help menu did not get sent because the bot is missing '
'the following permissions: '
+
', '
.
join
(
self
.
missing_perms
)
)
async
def
send_error_message
(
self
,
error
):
return
# rip is just the signature command ripped from the lib, but with alias support removed.
def
get_signature
(
command
):
"""Returns a POSIX-like signature useful for help command output."""
result
=
[]
parent
=
command
.
full_parent_name
name
=
command
.
name
if
not
parent
else
parent
+
' '
+
command
.
name
result
.
append
(
name
)
if
command
.
usage
:
result
.
append
(
command
.
usage
)
return
' '
.
join
(
result
)
params
=
command
.
clean_params
if
not
params
:
return
' '
.
join
(
result
)
for
name
,
param
in
params
.
items
():
if
param
.
default
is
not
param
.
empty
:
# We don't want None or '' to trigger the [name=value] case and instead it should
# do [name] since [name=None] or [name=] are not exactly useful for the user.
should_print
=
param
.
default
if
isinstance
(
param
.
default
,
str
)
else
param
.
default
is
not
None
if
should_print
:
result
.
append
(
'[
%
s=
%
s]'
%
(
name
,
param
.
default
))
else
:
result
.
append
(
'[
%
s]'
%
name
)
elif
param
.
kind
==
param
.
VAR_POSITIONAL
:
result
.
append
(
'[
%
s...]'
%
name
)
else
:
result
.
append
(
'<
%
s>'
%
name
)
return
' '
.
join
(
result
)
\ No newline at end of file
discord/util/pager.py
0 → 100644
View file @
bcdaeacd
import
discord
import
asyncio
from
math
import
ceil
STATIC_PERMS
=
(
'add_reactions'
,
'manage_messages'
,
'embed_links'
)
FIRST_EMOJI
=
'
\
N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}'
NEXT_EMOJI
=
'
\
N{BLACK RIGHT-POINTING DOUBLE TRIANGLE}'
PREV_EMOJI
=
'
\
N{BLACK LEFT-POINTING DOUBLE TRIANGLE}'
LAST_EMOJI
=
'
\
N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}'
STOP_EMOJI
=
'
\N{BLACK SQUARE FOR STOP}
'
HELP_EMOJI
=
'
\N{WHITE QUESTION MARK ORNAMENT}
'
class
Pager
:
def
__init__
(
self
,
ctx
,
entries
=
None
,
page
=
1
,
per_page
=
12
,
owner
=
None
,
timeout
=
120.0
,
separator
=
' '
):
self
.
ctx
=
ctx
self
.
bot
=
ctx
.
bot
self
.
author
=
owner
or
ctx
.
author
self
.
guild
=
ctx
.
guild
self
.
channel
=
ctx
.
channel
self
.
entries
=
entries
or
[]
self
.
embed
=
discord
.
Embed
()
self
.
page
=
page
self
.
timeout
=
timeout
self
.
separator
=
separator
self
.
per_page
=
per_page
self
.
on_help
=
False
self
.
static
=
False
self
.
missing_perms
=
[]
# overrides to a static view if missing perms!
perms
=
ctx
.
guild
.
me
.
permissions_in
(
ctx
.
channel
)
for
perm
in
STATIC_PERMS
:
if
not
getattr
(
perms
,
perm
):
self
.
missing_perms
.
append
(
perm
.
replace
(
'_'
,
' '
)
.
title
())
self
.
static
=
True
async
def
go
(
self
):
if
not
len
(
self
.
entries
):
return
await
self
.
get_page
(
1
)
msg
=
await
self
.
ctx
.
send
(
embed
=
self
.
embed
)
if
self
.
static
:
return
if
self
.
top_page
!=
1
:
emojis
=
[
FIRST_EMOJI
,
PREV_EMOJI
,
NEXT_EMOJI
,
LAST_EMOJI
,
STOP_EMOJI
,
HELP_EMOJI
]
if
self
.
top_page
==
2
:
emojis
.
remove
(
FIRST_EMOJI
)
emojis
.
remove
(
LAST_EMOJI
)
for
emoji
in
emojis
:
try
:
await
msg
.
add_reaction
(
emoji
)
except
discord
.
HTTPException
:
pass
def
pred
(
reaction
,
user
):
return
reaction
.
message
.
id
==
msg
.
id
and
user
!=
self
.
bot
.
user
while
True
:
try
:
reaction
,
user
=
await
self
.
bot
.
wait_for
(
'reaction_add'
,
check
=
pred
,
timeout
=
self
.
timeout
)
except
asyncio
.
TimeoutError
:
break
else
:
# just remove if it isn't authors reaction
if
user
!=
self
.
author
:
await
msg
.
remove_reaction
(
reaction
.
emoji
,
user
)
continue
# if it is, and it's a stop emoji, just stop
if
reaction
.
emoji
==
STOP_EMOJI
:
await
msg
.
clear_reactions
()
return
# otherwise, delete the reaction before handling case
await
msg
.
remove_reaction
(
reaction
.
emoji
,
user
)
if
reaction
.
emoji
==
NEXT_EMOJI
:
await
self
.
next
()
elif
reaction
.
emoji
==
PREV_EMOJI
:
await
self
.
prev
()
elif
reaction
.
emoji
==
FIRST_EMOJI
:
await
self
.
first
()
elif
reaction
.
emoji
==
LAST_EMOJI
:
await
self
.
last
()
elif
reaction
.
emoji
==
HELP_EMOJI
:
await
self
.
help
()
else
:
continue
await
msg
.
edit
(
embed
=
self
.
embed
)
try
:
await
msg
.
clear_reactions
()
except
discord
.
HTTPException
:
pass
@
property
def
top_page
(
self
):
if
self
.
static
:
return
1
return
ceil
(
len
(
self
.
entries
)
/
self
.
per_page
)
def
clear_embed
(
self
):
e
=
self
.
embed
e
.
title
=
None
e
.
description
=
None
e
.
set_author
(
name
=
''
,
url
=
''
)
e
.
clear_fields
()
if
self
.
static
:
e
.
set_footer
(
text
=
'Non-interactive! I
\'
m missing: '
+
', '
.
join
(
self
.
missing_perms
))
elif
self
.
on_help
:
e
.
set_footer
(
text
=
''
)
elif
self
.
top_page
>
1
:
e
.
set_footer
(
text
=
f
'Page {self.page}/{self.top_page}'
)
else
:
e
.
set_footer
(
text
=
''
)
async
def
get_page
(
self
,
page
):
self
.
clear_embed
()
await
self
.
craft_page
(
self
.
embed
,
page
,
self
.
get_page_entries
(
page
))
async
def
craft_page
(
self
,
e
,
page
,
entries
):
'''Crafts the actual embed.'''
e
.
description
=
self
.
separator
.
join
(
str
(
entry
)
for
entry
in
entries
)
def
get_page_entries
(
self
,
page
):
'''Converts a page number to a range of entries.'''
base
=
(
page
-
1
)
*
self
.
per_page
return
self
.
entries
[
base
:
base
+
self
.
per_page
]
async
def
try_page
(
self
,
page
):
if
self
.
top_page
>=
page
>=
1
:
self
.
page
=
page
await
self
.
get_page
(
page
)
async
def
next
(
self
):
await
self
.
try_page
(
self
.
page
+
1
)
async
def
prev
(
self
):
await
self
.
try_page
(
self
.
page
-
1
)
async
def
first
(
self
):
self
.
page
=
1
await
self
.
get_page
(
self
.
page
)
async
def
last
(
self
):
self
.
page
=
self
.
top_page
await
self
.
get_page
(
self
.
page
)
async
def
help
(
self
):
if
self
.
on_help
:
self
.
on_help
=
False
await
self
.
get_page
(
self
.
page
)
else
:
self
.
on_help
=
True
self
.
clear_embed
()
await
self
.
help_embed
(
self
.
embed
)
async
def
help_embed
(
self
,
e
):
e
.
title
=
'How to navigate this paginator!'
e
.
description
=
'Below is a description of what each emoji does.'
e
.
add_field
(
name
=
PREV_EMOJI
,
value
=
'Moves back to the previous page.'
)
e
.
add_field
(
name
=
NEXT_EMOJI
,
value
=
'Moves to the next page.'
)
if
self
.
top_page
>
2
:
e
.
add_field
(
name
=
FIRST_EMOJI
,
value
=
'Moves to the first page.'
)
e
.
add_field
(
name
=
LAST_EMOJI
,
value
=
'Moves to the last page.'
)
e
.
add_field
(
name
=
STOP_EMOJI
,
value
=
'Quits this pagination session.'
)
e
.
add_field
(
name
=
HELP_EMOJI
,
value
=
'Toggles this help message.'
)
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment