Commit de937a91 authored by IS1_4M's avatar IS1_4M
Browse files

Added new UI

parent 720530a5
......@@ -17,6 +17,30 @@ async def do_update(guild):
await AdminChanSuite.refresh_active_vars(guild)
return 1
async def assert_auth(guild):
auth_channel_name = await AdminChanSuite.get_auth_channel_name(guild)
auth_role_name = await AdminChanSuite.get_auth_channel_name(guild) # Needs a seperate server var variable.
auth_channel = None
auth_role = None
for channel in guild.text_channels:
if channel.name == auth_channel_name:
auth_channel = channel
if auth_channel == None:
auth_channel = await guild.create_text_channel(auth_channel_name)
await (await auth_channel.send(await AdminChanSuite.get_auth_chan_message(guild))).pin()
await (await auth_channel.fetch_message(channel.last_message_id)).delete()
for role in guild.roles:
if role.name == auth_role_name:
auth_role = role
if auth_role == None:
auth_role = await guild.create_role(name=auth_role_name)
await auth_channel.set_permissions(guild.default_role, read_messages = False)
await auth_channel.set_permissions(auth_role, read_messages=True, send_messages=True)
return (auth_channel, auth_role)
class AdminChannel(AbstractChannel):
Convenor_cli_permissions = {'read_messages':True,
'send_message':True,
......@@ -115,6 +139,10 @@ class AdminChanSuite(AbstractChanSuite):
if message.content.startswith(var_name):
return message
return -23
async def get_auth_enabled(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'auth_channel_enabled=')) == "True"
async def get_auth_chan_message(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'auth_channel_welcome_text='))
async def get_sender_name(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'sender_name='))
async def get_authrolename0(guild):
......@@ -252,9 +280,34 @@ class AdminChanSuite(AbstractChanSuite):
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('!toggle_auth'):
var_message = await AdminChanSuite.get_var_message(message.guild, 'auth_channel_enabled=')
val_bool = await AdminChanSuite.get_auth_enabled(message.guild)
if not val_bool:
await assert_auth(message.guild)
auth_name = await AdminChanSuite.get_auth_channel_name(message.guild)
new_text = await AdminChanSuite.get_auth_chan_message(message.guild)
for channel in message.channel.guild.text_channels:
if channel.name == auth_name:
for msg in await channel.pins(): # The only pinned message that can exist in auth is the one the bot sent lol
await msg.edit(content = new_text)
break
return await AdminChanSuite.set_var(var_message, str(not val_bool))
elif lower_text.startswith('!setwelcomemessageas '):
new_text = message.content[len('!setwelcomemessageas '):]
var_message = await AdminChanSuite.get_var_message(message.guild, 'auth_channel_welcome_text=')
if var_message == -23:
return -23
await AdminChanSuite.set_var(var_message, new_text)
auth_name = await AdminChanSuite.get_auth_channel_name(message.guild)
for channel in message.channel.guild.text_channels:
if channel.name == auth_name:
for msg in await channel.pins(): # The only pinned message that can exist in auth is the one the bot sent lol
await msg.edit(content = new_text)
break
return 1
elif lower_text.startswith('!update'):
return await do_update(message.guild)
print(message.content)
return 0
'''
......
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 8 00:25:28 2020
@author: josep
"""
import discord
from AdminChannel import AdminChanSuite
from EmailSuite import EmailSuite
from random import random
from datetime import datetime
from handles import get_member_by_discord_name
'''
auth_commands
'''
users = []
AUTHENTICATED=20000;
async def make_new_member(member):
new_member = User(member.guild, member)
await new_member._init(authChannel=await AdminChanSuite.get_auth_channel_name(member.guild))
users.append(new_member)
return new_member
async def process_auth(channel, author):
auth_user = None
for user in users:
if user._member.id == author.id:
auth_user = user
break
if auth_user == None:
print("Failed to find user: " + author.name + ". Making new one")
#print(repr(message.channel.guild))
auth_user = await make_new_member(get_member_by_discord_name(channel.guild, author.name + "#" + author.discriminator))
if await AdminChanSuite.get_auth_enabled(channel.guild) == False:
await auth_user.authenticate(auth_user._authcode)
return AUTHENTICATED
return auth_user
async def send_auth_code_to_user(channel, auth_user, emailaddress, email_confirm):
if emailaddress != email_confirm:
return -1000
if '@' in emailaddress:
emailaddress = emailaddress[:emailaddress.index('@')]
print('send email to ' + emailaddress)
auth_user = await process_auth(channel, auth_user)
if auth_user != AUTHENTICATED:
await auth_user.send_auth_email_to_addr(emailaddress)
await channel.send('Send auth code to: ' + emailaddress + await AdminChanSuite.get_email_verification_destination_domain(channel.guild), delete_after = 3)
async def authenticate(channel, auth_user, auth_code):
auth_user = await process_auth(channel, auth_user)
if auth_user != AUTHENTICATED:
if await auth_user.authenticate(auth_code.upper()) == AUTHENTICATED:
users.remove(auth_user)
await channel.send('Authentication succeeded... Moved you to the full discord. Look at all channels for information!', delete_after = 5)
else:
await channel.send('Authentication failed... ' + auth_code + ' is not the correct auth code', delete_after = 3)
'''
General User commands
'''
async def ghelp(channel):
commands = ['!clublist\n\t\t - Lists all clubs in ' + channel.guild.name, '!describeclub Clubname\n\t\t - Gives a Clubname\'s self-provided description', '!joinclub Clubname\n\t\t - Joins the club Clubname', '!leaveclub\n\t\t - Leaves a server\'s club',
'!makeclub Clubname\n\t\t - Makes the club Clubname','!admin\n\t\t - Opens a channel with you and admins', '!report person reason\n\t\t - Sends a report on a person to an admin or club convener.',
'!addtextchannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Adds a new public text channel in a category',
'!removetextchannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Removes the public text channel YOU MADE from the category. Doesn\'t work for other people\'s channels',
'!addvoicechannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Adds a new public voice channel in a category',
'!removevoicechannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Removes the public voice channel YOU MADE from the category. Doesn\'t work for other people\'s channels',]
send_text = 'Commands in ' + channel.guild.name + ' are:\n\t'
for command in commands:
send_text += command + '\n\t'
await channel.send(send_text)
return 1
class User:
def __init__(self, guild, member):
#send a message to the user asking for their pre-@earlham.edu email part
# send an auth code
# if they get the code right, delete them from this class and add them to the ECMember class
# If after 24 hours they are not an ECMember, kick them out of the server.
self._guild = guild
self._member = member
# Get the auth role from the guild.
#Record the time
#self._time = None
#their authcode:
self._authcode = 'AUTH' + str(random())
self._email_prefix = "None00"
# and their email prefix.
self._email_prefix = None
async def _init(self, authRole = 'auth', authChannel = 'please authenticate'):
'''
Assert there is an Auth Role in the server. If there is no auth role, immediately kick the user out of the server/
Assert there is an Auth Channel in the server. If there is no such auth channel, immediately kick the user out of the server/
'''
# TODO
authRole = await AdminChanSuite.get_auth_channel_name(self._guild)
authChannel = await AdminChanSuite.get_auth_channel_name(self._guild)
self._authRole = None
self._authChannel = None
for role in self._guild.roles:
if role.name == authRole:
self._authRole = role
break
for channel in self._guild.text_channels:
if channel.name == authChannel:
self._authChannel = channel
break
if self._authRole == None:
self._authRole = await self._guild.create_role(name=authRole, colour=discord.Colour.from_rgb(255,255,255))
#raise AssertionError("THERE IS NO AUTH ROLE IN THE SERVER... KICKED NEW USER")
if self._authChannel == None:
self._authChannel = await self._guild.create_text_channel(authChannel)
await self._authChannel.set_permissions(self._guild.default_role, read_messages = False)
await self._authChannel.set_permissions(self._authRole, read_messages=True, send_messages=True)
await (await self._authChannel.send(await AdminChanSuite.get_auth_chan_message(self._guild))).pin()
await (await channel.fetch_message(channel.last_message_id)).delete()
#raise AssertionError("THERE IS NO AUTH CHANNEL IN THE SERVER... KICKED NEW USER")
'''Give the new user authentication priviledges'''
await self._member.add_roles(self._authRole)
'''AND AUTHENTICATE'''
# Record authentication start time
self._now = datetime.now()
# Send message asking for their pre-earlham@earlham.edu email part (Do i want to do this?)
async def send_auth_email_to_addr(self, email_prefix):
self._email_prefix = email_prefix
message = """
Hello """ + self._member.name + """,
Copy \"!auth """+ self._authcode + """\" into the auth discord channel to join the """ + self._guild.name + ' discord server!'
sender_name = await AdminChanSuite.get_sender_name(self._guild)
domain_dest = await AdminChanSuite.get_email_verification_destination_domain(self._guild)
EmailSuite.send_email_to_addr(email_prefix + domain_dest,"Time to join " + self._guild.name + "...", message, sender_name=sender_name)
def getResponse(self):
# Get all messages. If not number of digits in the authcode, it's an address.
# Send email out.
# otherwise, it's an authcode. attempt authorization.
pass
async def authenticate(self, authcode):
# Get their user information. Make an ECMember object and return it with their creds
'''AUTHENTICATE. FIGURE OUT WHETHER STUDENT OR FACULTY LATER'''
'''NOT FINISHED. MUST FIX TO BE MORE GENERAL, BUT FOR FUTURE RENDITIONS'''
if authcode == self._authcode:
#make an ecmember,
print('successfully authenticated')
new_member, role_name = (ECStudent(self._member), await AdminChanSuite.get_authrolename0(self._guild)) if User.valid_student_email(self._email_prefix) else (ECFaculty(self._member), await AdminChanSuite.get_authrolename1(self._guild)) # FIX TO BE MORE GENERAL LATER
await self._member.remove_roles(self._authRole)
await new_member._init(role_name=role_name)
return AUTHENTICATED
# post message of failed authentication
# wait three seconds and then delete message of failed authentication
return False #ECMember()
async def attempt_kick(self):
# kick them out if the time is >= 24 hours after self._now.
# Deletes them from the server.
# returns true if kicked. False otherwise.
timedelta = datetime.now() - self._now
if timedelta.days >= 1:
await self._member.kick()
def is_int(string):
try:
return int(string)
except:
return False
def valid_student_email(earlham_email_handle):
return True
year = User.is_int(earlham_email_handle[-2:])
return (year and 17 <= year <= 20)
class ECMember:
def __init__(self):
# give them access to information channel and meet & greet channels.
# Give them access to read messages in digital advertisement text channel.
# Give them ability to dm users, see user roles
pass
class ECStudent(ECMember):
def __init__(self, member):
# Give them ability to join and start clubs.
ECMember.__init__(self)
self._member = member
async def _init(self, role_name='ECSTUDENT', role_color='Magenta'):
'''
Assert there is an ECSTUDENT ROLE. if there isn't, make one.
and add general member permissions to said role.
'''
student_role_name = role_name
student_role_color= role_color
guild = self._member.guild
student_role = None
for role in guild.roles:
if role.name == student_role_name:
student_role = role
break
if student_role == None:
# make the role and add general permissions
student_role = await guild.create_role(name=student_role_name, colour=discord.Colour.magenta()) # FIX TO ACTUALLY SUPPORT COLORS LATER
#await student_role.set_permissions( blah blah)
await self._member.add_roles(student_role)
# Give the member the ECSTUDENT role
# Give the ECStudent Role
# permissions for botty commands will line up based on the user's object type
# Play games
class ECFaculty(ECMember):
def __init__(self, member):
# Give them the ability to join and advise clubs.
ECMember.__init__(self)
self._member = member
async def _init(self, role_name='ECFACULTY', role_color='teal'):
'''
Assert there is an ECFACULTY ROLE. if there isn't, make one.
and add general member permissions to said role.
'''
faculty_role_name = role_name
faculty_role_color = role_color
guild = self._member.guild
faculty_role = None
for role in guild.roles:
if role.name == faculty_role_name:
faculty_role = role
break
if faculty_role == None:
# make the role and add general permissions
faculty_role = await guild.create_role(name=faculty_role_name, colour=discord.Colour.teal()) # FIX TO ACTUALLY SUPPORT COLORS LATER
#await faculty_role.set_permissions( blah blah)
await self._member.add_roles(faculty_role)
clubs = []
users = []
\ No newline at end of file
......@@ -5,8 +5,7 @@ Created on Sat Sep 5 14:09:29 2020
@author: josep
"""
from handles import User, \
bot_token, MIN_BETWEEN_TASK_EXECUTIONS
from handles import bot_token, MIN_BETWEEN_TASK_EXECUTIONS, get_member_by_discord_name
import discord
from discord.ext import commands, tasks
from datetime import datetime, timedelta
......@@ -18,13 +17,15 @@ from restrictedchannel import RestrictChanSuite
from AbstractChannel import AbstractChanSuite
from AdminChannel import AdminChanSuite, AdminChannel
from SOCChannel import SOCChannelSuite
from UI import UI, AuthControlPanel, GeneralControlPanel
from Auth import User, ghelp, authenticate, send_auth_code_to_user, make_new_member, process_auth
from rssfeedtest import get_today_at_earlham
from Response_Handling import handle_response_codes
def get_member_by_discord_name(guild, discord_name):
print(repr(guild))
print(guild.members)
for member in guild.members:
if member.name + "#" + member.discriminator == discord_name:
return member
......@@ -37,8 +38,8 @@ def is_auth(channel, auth_channel_name):
# return channel
#return False
clubs = []
users = []
#client = discord.Client()
intents = discord.Intents.default()
......@@ -47,12 +48,8 @@ intents.members = True
client = commands.Bot('!', intents=intents)
async def make_new_member(member):
new_member = User(member.guild, member)
await new_member._init(authChannel=await AdminChanSuite.get_auth_channel_name(member.guild))
users.append(new_member)
return new_member
@tasks.loop(minutes=MIN_BETWEEN_TASK_EXECUTIONS)
async def do_scheduled_tasks():
......@@ -99,6 +96,7 @@ async def update_today_at_schools():
await channel.send(annoucement)
except:
return
@update_today_at_schools.before_loop
async def before_update_today_at_schools():
print('started update before loop')
......@@ -123,7 +121,13 @@ async def on_guild_join(guild):
@client.event
async def on_member_join(member):
await make_new_member(member)
new_member = await make_new_member(member)
if await AdminChanSuite.get_auth_enabled(member.guild) == False:
await new_member.authenticate(new_member._authcode)
@client.event
async def on_raw_reaction_add(payload):
return await handle_response_codes(*(await UI.on_raw_reaction_add(client, payload)))
@client.event
async def on_message(message):
......@@ -139,6 +143,7 @@ async def on_message(message):
'''
try:
maybe_auth = is_auth(message.channel, await AdminChanSuite.get_auth_channel_name(message.guild))#''' This will break the program later. message.channel can be a DM channel. find a way to make it so that that wont break the channel'''
print("hello!!!!'")
print('got auth channel: ' + str(maybe_auth))
except:
maybe_auth = False
......@@ -146,36 +151,26 @@ async def on_message(message):
if maybe_auth:
# all messages in auth channel should delete after 3 sec, no matter what.
await message.delete(delay=3)
try:
await message.delete(delay=8)
except:
pass
# Get the user to do auth stuff with
auth_user = None
for user in users:
if user._member.id == message.author.id:
auth_user = user
break
if auth_user == None:
print("Failed to find user: " + message.author.name + ". Making new one")
print(repr(message.channel.guild))
auth_user = await make_new_member(get_member_by_discord_name(message.channel.guild, message.author.name + "#" + message.author.discriminator))
'''
AUTH COMMANDS GO HERE
'''
print('made it to auth commands')
#killer = create_task(kill_after_n(3, message)) # messages in this channel expire after 3 seconds
if content.startswith('!auth'): # this allows users to put in their codes
if await auth_user.authenticate(content[len('!auth '):].upper(), await AdminChanSuite.get_authrolename0(message.guild), await AdminChanSuite.get_authrolename1(message.guild)) == True:
users.remove(auth_user)
await message.channel.send('Authenticatoin succeeded... Moved you to the full discord. Look at all channels for information!', delete_after = 5)
else:
await message.channel.send('Authentication failed... ' + content[len('!auth '):] + ' is not the correct auth code', delete_after = 3)
else: #anything else is ![prefix] which files an email attempt
if '@' in content:
content = content[:content.index('@')]
print('sent email to ' + content[len('!'):])
await auth_user.send_auth_email_to_addr(content[len('!'):])
await message.channel.send('Send auth code to: ' + content[len('!'):] + '@earlham.edu', delete_after = 3)
#run(killer)
auth_user = await process_auth(message.channel, message.author)
if auth_user != 20000:
print('made it to auth commands')
#killer = create_task(kill_after_n(3, message)) # messages in this channel expire after 3 seconds
if content.startswith('!auth'): # this allows users to put in their codes
await authenticate(message.channel, message.author, content[len('!auth '):].upper())
elif content.startswith('!commandpanel'):
await AuthControlPanel._init_(message.channel)
else: #anything else is ![prefix] which files an email attempt
await send_auth_code_to_user(message.channel, message.author, content[len('!'):])
#run(killer)
return 1
'''
......@@ -210,7 +205,9 @@ async def on_message(message):
# student = ECStudent(get_member_by_discord_name(message.channel.guild, content[len('!MAKESTUDENT '):]))
# await student._init(role_name=student_role_name)
# return
if content.startswith('!examples'):
if content.startswith('!commandpanel'):
await GeneralControlPanel._init_(message.channel)
elif content.startswith('!examples'):
commands = ['!clublist\n\t\t - lists all clubs in ' + message.channel.guild.name,
'!joinclub ECHackers\n\t\t - Joins the ECHackers Club',
'!leaveclub ECHackers\n\t\t - Leaves the ECHackers Club',
......@@ -227,17 +224,7 @@ async def on_message(message):
await message.channel.send(send_text)
return 1
elif content.startswith('!help') or content.startswith('!ocommands') or content.startswith('!ccommands') or content.startswith('!rcommands'):
commands = ['!clublist\n\t\t - Lists all clubs in ' + message.channel.guild.name, '!describeclub Clubname\n\t\t - Gives a Clubname\'s self-provided description', '!joinclub Clubname\n\t\t - Joins the club Clubname', '!leaveclub\n\t\t - Leaves a server\'s club',
'!makeclub Clubname\n\t\t - Makes the club Clubname','!admin\n\t\t - Opens a channel with you and admins', '!report person reason\n\t\t - Sends a report on a person to an admin or club convener.',
'!addtextchannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Adds a new public text channel in a category',
'!removetextchannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Removes the public text channel YOU MADE from the category. Doesn\'t work for other people\'s channels',
'!addvoicechannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Adds a new public voice channel in a category',
'!removevoicechannel The-name-of-the-public-category The-new-channel\'s-name\n\t\t - Removes the public voice channel YOU MADE from the category. Doesn\'t work for other people\'s channels',]
send_text = '[WIP] Commands in ' + message.channel.guild.name + ' are:\n\t'
for command in commands:
send_text += command + '\n\t'
await message.channel.send(send_text)
return 1
await ghelp(message.channel)
elif content.startswith('!admin'):
await message.channel.send('not yet implemented...')
......@@ -286,6 +273,7 @@ async def on_message(message):
print('could not find auth channel')
if maybe_auth:
await message.delete(delay=3)
auth_user = await process_auth(message.channel, message.author)
# Check if a message comes in from a CLI channel.
# if in a CLI channel,
# is it an admin channel?
......
......@@ -9,13 +9,8 @@ import discord
from AbstractChannel import AbstractChanSuite, AbstractChannel
from AdminChannel import AdminChanSuite
from datetime import datetime, timedelta
from handles import MIN_BETWEEN_TASK_EXECUTIONS, PROCESSING_TIME_PADDING
from handles import MIN_BETWEEN_TASK_EXECUTIONS, PROCESSING_TIME_PADDING, get_member_by_discord_name
from EmailSuite import EmailSuite
def get_member_by_discord_name(guild, discord_name):
for member in guild.members:
if member.name + "#" + member.discriminator == discord_name:
return member
return False
class Club(AbstractChannel): # Creates a club category channel with CLUB MEMBER role read and write permissions for club members and CLI access for club convenors
Convenor_cli_permissions = {'read_messages':True,
......@@ -146,6 +141,101 @@ class ClubSuite(AbstractChanSuite):
async def add_private_voice_chan(club, channelName):
await AbstractChanSuite.add_private_voice_chan(club, channelName, Club.convener_role_name, Club.Convenor_cli_permissions)
async def ui_add_member(club, member_name):
member = get_member_by_discord_name(club.guild, member_name)
await ClubSuite.add_member(club, member); return True
async def ui_kick_member(club, member_name):
member = get_member_by_discord_name(club.guild, member_name)
await ClubSuite.kick_member(club, member); return True
async def ui_convenerhelp(cli):
await cli.send(ClubSuite.get_help_message(cli)); return True
async def ui_describe(cli, description):
for pin in await cli.pins():
if pin.content.startswith("DESCRIPTION SET TO:"):
await pin.unpin()
await (await cli.send('DESCRIPTION SET TO: ' + description)).pin()
return True
async def ui_pin(channel, TextChannel, content):
channel = await ClubSuite.get_text_channel(channel.guild.get_channel(channel.category_id), TextChannel)
await (await channel.send(content)).pin()
return 1
async def ui_unpin(channel, TextChannel, content):
channel = await ClubSuite.get_text_channel(channel.guild, TextChannel)
for pin in await channel.pins():
if pin.content == content:
await pin.unpin()
return True
return -217
async def ui_schedule_message(cli, date, time, content, channel):
await (await cli.send('MESSAGE SCHEDULED for ' + date + " @ " + time + ' "' + content + '" to ' + channel)).pin()
return 1
async def ui_unschedule(cli, content):
for pin in await cli.pins():
if pin.content == content:
await pin.delete()
return 1
return -11
async def ui_weekly_reminder(cli,weekday, time, content, channels):
await (await cli.send('Now meeting weekly on '+ weekday + 's at ' + time + ' . Posting ' + content + ' in ' + str(channels))).pin()
return 1
async def ui_cancel_weekly_reminder(cli, content):
for message in cli.pins():
if message.content == content:
message.delete()
return 1
return -12
async def ui_setup_email(cli, channel, discord_name, dest_email, confirm_dest_email):
if dest_email != confirm_dest_email:
return -1
await (await cli.send('EMAIL LINK ESTABLISHED IN ' + channel + ' . ' +discord_name + ':' + dest_email)).pin()
return 1