Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
UCC
Discord Bot
Commits
5de793cf
Commit
5de793cf
authored
Feb 03, 2020
by
Timothy du Heaume
Browse files
sync roles and reactions when connecting or reconnecting
parent
1081456f
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/main.rs
View file @
5de793cf
...
...
@@ -188,8 +188,13 @@ impl EventHandler for Handler {
// private channels, and more.
//
// In this case, just print what the current user's username is.
fn
ready
(
&
self
,
_
:
Context
,
ready
:
Ready
)
{
fn
ready
(
&
self
,
ctx
:
Context
,
ready
:
Ready
)
{
info!
(
"{} is connected!"
,
ready
.user.name
);
reaction_roles
::
add_all_role_reactions
(
ctx
);
}
fn
resume
(
&
self
,
ctx
:
Context
,
_
:
serenity
::
model
::
event
::
ResumedEvent
)
{
reaction_roles
::
add_all_role_reactions
(
ctx
);
}
}
...
...
src/reaction_roles.rs
View file @
5de793cf
use
std
::
collections
::{
HashMap
,
HashSet
};
use
std
::
iter
::
FromIterator
;
use
serenity
::{
model
::{
channel
::
Message
,
channel
::
Reaction
},
model
::{
channel
::
Message
,
channel
::
Reaction
,
id
::
UserId
},
client
::
Context
};
use
crate
::
util
::
get_string_from_react
;
use
crate
::
util
::
{
get_string_from_react
,
get_react_from_string
}
;
use
crate
::
config
::
CONFIG
;
pub
fn
add_role_by_reaction
(
ctx
:
Context
,
msg
:
Message
,
added_reaction
:
Reaction
)
{
...
...
@@ -22,3 +24,46 @@ pub fn remove_role_by_reaction(ctx: Context, msg: Message, removed_reaction: Rea
return
ctx
.http
.remove_member_role
(
CONFIG
.server_id
,
*
msg
.author.id
.as_u64
(),
*
role_id
.as_u64
())
.ok
();
});
}
pub
fn
add_all_role_reactions
(
ctx
:
Context
)
{
let
messages_with_role_mappings
=
get_all_role_reaction_message
(
&
ctx
);
let
guild
=
ctx
.http
.get_guild
(
CONFIG
.server_id
)
.unwrap
();
// this method supports paging, but we probably don't need it since the server only has a couple of
// hundred members. the Reaction.users() method can apparently only retrieve 100 users at once, but
// this one seems to work fine when set to 1000 (I tried 10,000 but the api returned a 400)
let
all_members
=
ctx
.http
.get_guild_members
(
CONFIG
.server_id
,
Some
(
1000
),
None
)
.unwrap
();
for
(
message
,
mapping
)
in
messages_with_role_mappings
{
for
(
react
,
role
)
in
mapping
{
// the docs say this method can't retrieve more than 100 user reactions at a time, but it seems
// to work fine when set to 255...
// TODO: proper pagination for the unlikely scenario that there are more than 100 (255?) reactions?
let
reaction_type
=
get_react_from_string
(
react
.clone
(),
guild
.clone
());
let
reactors
=
message
.reaction_users
(
ctx
.http
.clone
(),
reaction_type
,
Some
(
255
),
None
)
.unwrap
();
let
reactor_ids
:
HashSet
<
UserId
>
=
HashSet
::
from_iter
(
reactors
.iter
()
.map
(|
r
|
r
.id
));
// this looks O(n!), but n will probably never be more than three digits, so maybe it's okay?
// one solution might be to batch up all the roles to add/remove for each member and do them
// all at once with .add_roles()
for
mut
member
in
all_members
.clone
()
{
if
reactor_ids
.contains
(
&
member
.user_id
())
{
member
.add_role
(
ctx
.http
.clone
(),
role
)
.unwrap
();
}
else
{
member
.remove_role
(
ctx
.http
.clone
(),
role
)
.unwrap
();
}
}
}
}
}
fn
get_all_role_reaction_message
(
ctx
:
&
Context
)
->
Vec
<
(
Message
,
&
'static
HashMap
<
String
,
serenity
::
model
::
id
::
RoleId
>
)
>
{
let
guild
=
ctx
.http
.get_guild
(
CONFIG
.server_id
)
.unwrap
();
let
channels
=
ctx
.http
.get_channels
(
*
guild
.id
.as_u64
())
.unwrap
();
return
channels
.iter
()
.flat_map
(|
channel
|
{
let
ctxx
=
ctx
.clone
();
// since we don't know which channels the messages are in, we check every combination of message and
// channel and ignore the bad matches using .ok() and .filter_map()
CONFIG
.react_role_messages
.iter
()
.filter_map
(
move
|
rrm
|
ctxx
.http
.get_message
(
*
channel
.id
.as_u64
(),
*
rrm
.message
.as_u64
())
.ok
()
.map
(|
m
|
(
m
,
&
rrm
.mapping
)))
})
.collect
();
}
src/util.rs
View file @
5de793cf
use
serenity
::
model
::
channel
::
ReactionType
;
use
serenity
::
model
::
{
channel
::
ReactionType
,
guild
::
PartialGuild
}
;
pub
fn
get_string_from_react
(
react
:
ReactionType
)
->
String
{
match
react
{
...
...
@@ -8,3 +8,9 @@ pub fn get_string_from_react(react: ReactionType) -> String {
_
=>
format!
(
"Unrecognised reaction type: {:?}"
,
react
),
}
}
pub
fn
get_react_from_string
(
string
:
String
,
guild
:
PartialGuild
)
->
ReactionType
{
guild
.emojis
.values
()
.find
(|
e
|
e
.name
==
string
)
.map_or_else
(
||
ReactionType
::
from
(
string
),
// unicode emoji
|
custom_emoji
|
ReactionType
::
from
(
custom_emoji
.id
))
}
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