role granting
This commit is contained in:
parent
54e890ab2c
commit
d6642549c4
@ -1,7 +1,12 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
from v6d0auth.config import root
|
||||||
|
|
||||||
guild = int(os.getenv('v6guild', 541241763042689025))
|
guild = int(os.getenv('v6guild', 541241763042689025))
|
||||||
emoji = int(os.getenv('v6emoji', 586669134406877270))
|
emoji = int(os.getenv('v6emoji', 586669134406877270))
|
||||||
role = int(os.getenv('v6role', 643896112977018880))
|
role = int(os.getenv('v6role', 643896112977018880))
|
||||||
message = int(os.getenv('v6message', 825385619097518110))
|
message = int(os.getenv('v6message', 825385619097518110))
|
||||||
channel = int(os.getenv('v6channel', 876814972968116224))
|
channel = int(os.getenv('v6channel', 876814972968116224))
|
||||||
|
role_channel = int(os.getenv('v6channel', 964261739980025966))
|
||||||
|
myroot = root / 'v6d3losyash'
|
||||||
|
myroot.mkdir(exist_ok=True)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
from typing import Union, Optional
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
from ptvp35 import KVJson, Db
|
||||||
from v6d1tokens.client import request_token
|
from v6d1tokens.client import request_token
|
||||||
from v6d2ctx.serve import serve
|
from v6d2ctx.serve import serve
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ client = discord.Client(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
ESCAPED = '`_*\'"\\'
|
ESCAPED = '`_*\'"\\'
|
||||||
|
nest_db = Db(config.myroot / 'nest.db', kvrequest_type=KVJson)
|
||||||
|
|
||||||
|
|
||||||
def escape(s: str):
|
def escape(s: str):
|
||||||
@ -32,30 +35,220 @@ def escape(s: str):
|
|||||||
return res.getvalue()
|
return res.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
lock = asyncio.Lock()
|
||||||
|
|
||||||
|
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
print("ready")
|
print("ready")
|
||||||
await client.change_presence(activity=discord.Game(
|
await client.change_presence(activity=discord.Game(
|
||||||
name='феноменально',
|
name='феноменально',
|
||||||
))
|
))
|
||||||
|
async with lock:
|
||||||
|
await state.reload()
|
||||||
|
|
||||||
|
|
||||||
@client.event
|
class SimpleEmoji:
|
||||||
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
|
def __init__(self, ref: Union[str, int]):
|
||||||
emoji: discord.Emoji = payload.emoji
|
self.ref = ref
|
||||||
if emoji.id != config.emoji:
|
|
||||||
return
|
def __hash__(self):
|
||||||
if payload.message_id != config.message:
|
return hash(self.ref)
|
||||||
return
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, SimpleEmoji):
|
||||||
|
return self.ref == other.ref
|
||||||
|
return NotImplemented
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def of(cls, emoji: Union[str, discord.Emoji, discord.PartialEmoji]) -> 'SimpleEmoji':
|
||||||
|
if isinstance(emoji, discord.Emoji):
|
||||||
|
return cls(emoji.id)
|
||||||
|
elif isinstance(emoji, str):
|
||||||
|
return cls(emoji)
|
||||||
|
elif isinstance(emoji, discord.PartialEmoji):
|
||||||
|
if emoji.id is None:
|
||||||
|
return cls(emoji.name)
|
||||||
|
else:
|
||||||
|
return cls(emoji.id)
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
def to(self) -> Union[str, discord.Emoji]:
|
||||||
|
if isinstance(self.ref, str):
|
||||||
|
return self.ref
|
||||||
|
else:
|
||||||
|
return client.get_emoji(self.ref)
|
||||||
|
|
||||||
|
|
||||||
|
class RoleGrant:
|
||||||
|
def __init__(self, role: int, emoji: SimpleEmoji):
|
||||||
|
self.role = role
|
||||||
|
self.emoji = emoji
|
||||||
|
|
||||||
|
def format(self) -> str:
|
||||||
|
guild: discord.Guild = client.get_guild(config.guild)
|
||||||
|
return f'{self.emoji.to()} {guild.get_role(self.role)}'
|
||||||
|
|
||||||
|
|
||||||
|
class MessageDescription:
|
||||||
|
def __init__(self, key: str, description: str, *roles: RoleGrant):
|
||||||
|
self.key = key
|
||||||
|
self._description = description
|
||||||
|
self.roles = roles
|
||||||
|
self.mapping: dict[SimpleEmoji, int] = {grant.emoji: grant.role for grant in roles}
|
||||||
|
|
||||||
|
def description(self):
|
||||||
|
return self._description + '\n' + '\n'.join(map(RoleGrant.format, self.roles))
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelDescription:
|
||||||
|
def __init__(self, *mds: MessageDescription):
|
||||||
|
self.mds = mds
|
||||||
|
self.mapping: dict[str, MessageDescription] = {md.key: md for md in mds}
|
||||||
|
|
||||||
|
|
||||||
|
def role_channel() -> discord.TextChannel:
|
||||||
guild: discord.Guild = client.get_guild(config.guild)
|
guild: discord.Guild = client.get_guild(config.guild)
|
||||||
member: discord.Member = guild.get_member(payload.user_id)
|
channel: discord.TextChannel = guild.get_channel(config.role_channel)
|
||||||
|
return channel
|
||||||
|
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self, cd: ChannelDescription):
|
||||||
|
self.defmap: dict[str, int] = {}
|
||||||
|
self.defrev: dict[int, str] = {}
|
||||||
|
self.cd = cd
|
||||||
|
|
||||||
|
async def _load(self):
|
||||||
|
self.defmap = nest_db.get('state-map', {})
|
||||||
|
self.defrev.clear()
|
||||||
|
for md in self.cd.mds:
|
||||||
|
msg = await self._get(md.key, md.description())
|
||||||
|
for reaction in msg.reactions:
|
||||||
|
emoji = SimpleEmoji.of(reaction.emoji)
|
||||||
|
if emoji not in md.mapping:
|
||||||
|
await reaction.clear()
|
||||||
|
for emoji in md.mapping.keys():
|
||||||
|
await msg.add_reaction(emoji.to())
|
||||||
|
|
||||||
|
async def _get_raw(self, key: str, content: str) -> discord.Message:
|
||||||
|
channel = role_channel()
|
||||||
|
if key in self.defmap:
|
||||||
|
try:
|
||||||
|
msg = await channel.fetch_message(self.defmap[key])
|
||||||
|
if msg.content != content:
|
||||||
|
await msg.edit(content=content)
|
||||||
|
return msg
|
||||||
|
except discord.NotFound:
|
||||||
|
pass
|
||||||
|
return await channel.send(content)
|
||||||
|
|
||||||
|
async def _get(self, key: str, content: str) -> discord.Message:
|
||||||
|
msg = await self._get_raw(key, content)
|
||||||
|
self.defmap[key] = msg.id
|
||||||
|
self.defrev[msg.id] = key
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def _reset_defmap(self):
|
||||||
|
self.defmap = {key: msid for msid, key in self.defrev.items()}
|
||||||
|
|
||||||
|
async def _clear_channel(self):
|
||||||
|
msg: discord.Message
|
||||||
|
async for msg in role_channel().history(limit=100):
|
||||||
|
if msg.author.id == client.user.id and msg.id not in self.defrev:
|
||||||
|
await msg.delete()
|
||||||
|
|
||||||
|
async def _save(self):
|
||||||
|
self._reset_defmap()
|
||||||
|
await self._clear_channel()
|
||||||
|
await nest_db.set('state-map', self.defmap)
|
||||||
|
|
||||||
|
async def reload(self):
|
||||||
|
await self._load()
|
||||||
|
await self._save()
|
||||||
|
|
||||||
|
async def _role_member(
|
||||||
|
self, msid: int, member_id: int, emoji: SimpleEmoji
|
||||||
|
) -> tuple[Optional[discord.Role], Optional[discord.Member]]:
|
||||||
|
key = self.defrev[msid]
|
||||||
|
md = self.cd.mapping[key]
|
||||||
|
role_id = md.mapping.get(emoji)
|
||||||
|
if role_id is None:
|
||||||
|
channel = role_channel()
|
||||||
|
message: discord.Message = await channel.fetch_message(msid)
|
||||||
|
await message.clear_reaction(emoji.to())
|
||||||
|
return None, None
|
||||||
|
guild: discord.Guild = await client.fetch_guild(config.guild)
|
||||||
|
role: discord.Role = guild.get_role(role_id)
|
||||||
|
member: discord.Member = await guild.fetch_member(member_id)
|
||||||
|
return role, member
|
||||||
|
|
||||||
|
async def role_grant(self, msid: int, member_id: int, emoji: SimpleEmoji):
|
||||||
|
role, member = await self._role_member(msid, member_id, emoji)
|
||||||
|
if role is None or member is None:
|
||||||
|
return
|
||||||
|
await member.add_roles(role, reason='emojis go yes')
|
||||||
|
await log(f'emoji {emoji.to()} +role {role} member {member}')
|
||||||
|
|
||||||
|
async def role_revoke(self, msid: int, member_id: int, emoji: SimpleEmoji):
|
||||||
|
role, member = await self._role_member(msid, member_id, emoji)
|
||||||
|
if role is None or member is None:
|
||||||
|
return
|
||||||
|
await member.remove_roles(role, reason='emojis go no')
|
||||||
|
await log(f'emoji {emoji.to()} -role {role} member {member}')
|
||||||
|
|
||||||
|
|
||||||
|
state = State(
|
||||||
|
ChannelDescription(
|
||||||
|
MessageDescription(
|
||||||
|
'games',
|
||||||
|
'Игровые роли',
|
||||||
|
RoleGrant(541263011822698506, SimpleEmoji(541257134407417864)),
|
||||||
|
RoleGrant(542056704842661899, SimpleEmoji('🦆')),
|
||||||
|
RoleGrant(541349294586724365, SimpleEmoji('⛏')),
|
||||||
|
RoleGrant(541263005971644419, SimpleEmoji('🌈')),
|
||||||
|
RoleGrant(934467294371938355, SimpleEmoji('🎩')),
|
||||||
|
RoleGrant(933103254752088104, SimpleEmoji('🐟')),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def log(msg: str):
|
||||||
|
guild: discord.Guild = client.get_guild(config.guild)
|
||||||
|
channel: discord.TextChannel = guild.get_channel(config.channel)
|
||||||
|
await channel.send(msg)
|
||||||
|
|
||||||
|
|
||||||
|
async def grant_citizenship(member_id: int):
|
||||||
|
guild: discord.Guild = client.get_guild(config.guild)
|
||||||
|
member: discord.Member = guild.get_member(member_id)
|
||||||
role = guild.get_role(config.role)
|
role = guild.get_role(config.role)
|
||||||
if role in member.roles:
|
if role in member.roles:
|
||||||
return
|
return
|
||||||
await member.add_roles(role, reason='феноменально')
|
await member.add_roles(role, reason='феноменально')
|
||||||
|
await log(f'{escape(str(member))} {member.id} <:Jesus:586669134406877270>')
|
||||||
|
|
||||||
channel: discord.TextChannel = guild.get_channel(config.channel)
|
|
||||||
await channel.send(f'{escape(str(member))} {member.id} <:Jesus:586669134406877270>')
|
@client.event
|
||||||
|
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
|
||||||
|
if payload.user_id == client.user.id:
|
||||||
|
return
|
||||||
|
emoji: discord.PartialEmoji = payload.emoji
|
||||||
|
if emoji.id == config.emoji and payload.message_id == config.message:
|
||||||
|
await grant_citizenship(payload.user_id)
|
||||||
|
if payload.message_id in state.defrev:
|
||||||
|
await state.role_grant(payload.message_id, payload.user_id, SimpleEmoji.of(emoji))
|
||||||
|
|
||||||
|
|
||||||
|
@client.event
|
||||||
|
async def on_raw_reaction_remove(payload: discord.RawReactionActionEvent):
|
||||||
|
if payload.user_id == client.user.id:
|
||||||
|
return
|
||||||
|
emoji: discord.PartialEmoji = payload.emoji
|
||||||
|
if payload.message_id in state.defrev:
|
||||||
|
await state.role_revoke(payload.message_id, payload.user_id, SimpleEmoji.of(emoji))
|
||||||
|
|
||||||
|
|
||||||
@client.event
|
@client.event
|
||||||
@ -73,12 +266,23 @@ async def on_member_remove(member: discord.Member):
|
|||||||
if guild.id != config.guild:
|
if guild.id != config.guild:
|
||||||
return
|
return
|
||||||
channel: discord.TextChannel = guild.get_channel(config.channel)
|
channel: discord.TextChannel = guild.get_channel(config.channel)
|
||||||
await channel.send(f'{escape(str(member))} {member.id} left (joined {member.joined_at})')
|
message = await channel.send(f'{escape(str(member))} {member.id} left (joined {member.joined_at})')
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
entry: discord.AuditLogEntry
|
||||||
|
async for entry in guild.audit_logs(action=discord.AuditLogAction.kick):
|
||||||
|
if entry.target.id == member.id:
|
||||||
|
await message.reply(f'latest kick: {entry.created_at} {entry.reason}')
|
||||||
|
break
|
||||||
|
async for entry in guild.audit_logs(action=discord.AuditLogAction.ban):
|
||||||
|
if entry.target.id == member.id:
|
||||||
|
await message.reply(f'latest ban: {entry.created_at} {entry.reason}')
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
await client.login(token)
|
async with nest_db:
|
||||||
await client.connect()
|
await client.login(token)
|
||||||
|
await client.connect()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user