Commit 9a7f8be5 authored by IS1_4M's avatar IS1_4M
Browse files

ADded admin functionality and email updates

parent 94a6ac5c
......@@ -97,6 +97,7 @@ class AbstractChanSuite:
if chan.name == channel_name: # Then there this is become a duplicate. Do not finish instantiation.
return -4
return 1
'''
chanType is either c, o, or R at this time.
'''
......
......@@ -6,18 +6,27 @@ Created on Thu Oct 8 10:08:06 2020
"""
import discord
from handles import general_user_role_names, server_vars, key
from AbstractChannel import AbstractChannel, AbstractChanSuite
from handles import general_user_role_names
from PublicChannel import PublicChan, PubChanSuite
from restrictedchannel import RestrictChan
from cryptography.fernet import Fernet
async def do_update(guild):
await AdminChanSuite.refresh_active_vars(guild)
return 1
class AdminChannel(AbstractChannel):
Convenor_cli_permissions = {'read_messages':True,
'send_message':True,
'view_channel':True,
'connect':True,
'speak':True}
Member_permissions = {'read_messages':True,
'send_messages':True,
'connect':True,
'speak':True}
default_guild_role_perms = {'read_messages':False,
'view_channel':False,
......@@ -29,6 +38,7 @@ class AdminChannel(AbstractChannel):
channel_type = 'A'
convener_role_name = 'Admin'
member_role_name = 'none'
member_color = discord.Colour.red()
category_name = "Server"
convenor_color = discord.Colour.red()
......@@ -53,14 +63,79 @@ class AdminChannel(AbstractChannel):
async def _init(self):
return await AbstractChannel._init(self, suite=AdminChanSuite) # Add a var channel too and populate it with necessary fields for server functioning.
response = await AbstractChannel._init(self, [], suite=AdminChanSuite) # Add a var channel too and populate it with necessary fields for server functioning.
if response != 1:
return response
# get the admin category and add a var to it
cat = AdminChanSuite.get_admincat(self._guild)
var_chan = await AbstractChanSuite.add_text_channel(cat, 'var')
var_chan = await AbstractChanSuite.get_text_channel(cat, 'var')
var_chan.topic = 'DO NOT EDIT MANUALLY! This is the section that stores information relevant for your server! Use !adminvarsetup to begin to get this set up!'
for var, initialized_to in server_vars.items():
await var_chan.send(var + initialized_to)
for role in self._chan_roles:
await var_chan.set_permissions(role, send_messages=False)
class AdminChanSuite(AbstractChanSuite):
async def refresh_active_vars(guild):
cat = AdminChanSuite.get_admincat(guild)
if not AdminChanSuite.get_admincat(guild):
achan = AdminChannel()
await achan._init()
cat = AdminChanSuite.get_admincat(guild)
if not await AbstractChanSuite.get_text_channel(cat, 'var'):
var_chan = await AbstractChanSuite.add_text_channel(cat, 'var')
var_chan = await AbstractChanSuite.get_text_channel(cat, 'var')
for role in guild.roles:
await var_chan.set_permissions(role, send_messages=False)
await AdminChanSuite._delete_depreciated_vars(guild)
await AdminChanSuite._add_vars(guild)
async def _delete_depreciated_vars(guild):
server_var_keys = set(server_vars.keys())
cat = AdminChanSuite.get_admincat(guild)
var = await AbstractChanSuite.get_text_channel(cat, 'var')
async for message in var.history(limit=200):
server_var_parts = message.content.split('=')
if server_var_parts[0] + "=" not in server_var_keys:
await message.delete()
# inefficient
async def _add_vars(guild):
cat = AdminChanSuite.get_admincat(guild)
var = await AbstractChanSuite.get_text_channel(cat, 'var')
for server_var, default_value in server_vars.items():
if await AdminChanSuite.get_var_message(guild, server_var) == -23:
await var.send(server_var + default_value)
async def get_var_message(guild, var_name):
cat = AdminChanSuite.get_admincat(guild)
var = await AbstractChanSuite.get_text_channel(cat, 'var')
async for message in var.history(limit=200):
if message.content.startswith(var_name):
return message
return -23
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):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'auth_role_name0='))
async def get_authrolename1(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'auth_role_name1='))
async def get_auth_channel_name(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'auth_channel_name='))
async def get_email_verification_destination_domain(guild):
return AdminChanSuite.get_var_val_from_message(await AdminChanSuite.get_var_message(guild, 'email_verification_destination_domain='))
async def get_general_user_role_names(guild):
return [await AdminChanSuite.get_authrolename0(guild), await AdminChanSuite.get_authrolename1(guild)]
def _assert_non_duplicate(guild, channel_name):
if AbstractChanSuite._assert_non_duplicate(guild, AdminChannel.channel_type, channel_name) == -4:
return -22
return 1
def get_all_adminchans(guild):
return AbstractChanSuite.get_all_chans(guild, AdminChannel.channel_type)
# Gets the Admin Category. returns false if it doesn't exist.
def get_admincat(guild):
print(list(AdminChanSuite.get_all_adminchans(guild)))
return AbstractChanSuite.get_chan(AdminChanSuite.get_all_adminchans(guild),'A-Server')
# gets the admin cli out of the admin category.
......@@ -83,6 +158,27 @@ class AdminChanSuite(AbstractChanSuite):
return ['Unimplemented']
def get_help_message(channel):
return 'Unimplemented'
async def set_var(message, new_value):
# Encrypt the unencrypted string and post it in the message's associated content.
split_at = message.content.index('=')
var = message.content[:split_at + 1]
await message.edit(content=var + new_value)
return 1
def get_var_val_from_message(message):
split_at = message.content.index('=')
var = message.content[split_at + 1:]
return var
def encrypt(unencrypted_string):
unencrypted_string = unencrypted_string.encode()
f = Fernet(key)
encrypted_string = f.encrypt(unencrypted_string).decode()
return encrypted_string
def decrypt(encrypted_string):
f = Fernet(key)
encrypted_string=encrypted_string.encode()
return f.decrypt(encrypted_string).decode()
async def process_cli_commands(message):
# for case sensitive commands
raw_text = message.content
......@@ -94,7 +190,7 @@ class AdminChanSuite(AbstractChanSuite):
# Admin category andcli for executing commands down the line.
admin_category = AdminChanSuite.get_admincat(message.guild)
admin_cli = AdminChanSuite.get_cli(admin_category)
print(admin_category, admin_cli)
if not admin_category or not admin_cli:
return False
......@@ -112,8 +208,55 @@ class AdminChanSuite(AbstractChanSuite):
resName = lower_text_parts[1]
new_restrictChan = RestrictChan(message.guild, message.author, resName)
return await new_restrictChan._init()
elif lower_text.startswith('!setsendernameas '):
if len(raw_text_parts) != 2:
return -24
var_message = await AdminChanSuite.get_var_message(message.guild, 'sender_name=')
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('#!setemailpassas '):
if len(raw_text_parts) != 2:
return -24
encrypted_pass = AdminChanSuite.encrypt(raw_text_parts[1])
var_message = await AdminChanSuite.get_var_message(message.guild, 'associated_email_password_encrypted=')
if var_message == -23:
return -23
if await AdminChanSuite.set_var(var_message, encrypted_pass) == 1:
return 8
elif lower_text.startswith('!setauthrole0as'):
if len(raw_text_parts) != 2:
return -24
var_message = await AdminChanSuite.get_var_message(message.guild, 'auth_role_name0=')
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('!setauthrole1as'):
if len(raw_text_parts) != 2:
return -24
var_message = await AdminChanSuite.get_var_message(message.guild, 'auth_role_name1=')
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('!setauthchannameas'):
if len(raw_text_parts) != 2:
return -24
var_message = await AdminChanSuite.get_var_message(message.guild, 'auth_channel_name=')
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('!setdestdomainas'):
if len(raw_text_parts) != 2:
return -24
var_message = await AdminChanSuite.get_var_message(message.guild, 'email_verification_destination_domain=')
if var_message == -23:
return -23
return await AdminChanSuite.set_var(var_message, raw_text_parts[1])
elif lower_text.startswith('!update'):
return await do_update(message.guild)
print(message.content)
return 0
'''
Case sensitive commands go second
'''
......
......@@ -5,13 +5,10 @@ Created on Sat Sep 5 14:09:29 2020
@author: josep
"""
from handles import User, ECMember, ECStudent, ECFaculty, student_role_name, faculty_role_name, \
general_user_role_names, account_password, bot_token, \
send_account_email, domain_dest, auth_channel,\
MIN_BETWEEN_TASK_EXECUTIONS
from handles import User, \
bot_token, MIN_BETWEEN_TASK_EXECUTIONS
import discord
from discord.ext import commands, tasks
import smtplib, ssl
from datetime import datetime, timedelta
from asyncio import sleep
......@@ -19,13 +16,15 @@ from PublicChannel import PubChanSuite
from ClubChannel import ClubSuite
from restrictedchannel import RestrictChanSuite
from AbstractChannel import AbstractChanSuite
from AdminChannel import AdminChanSuite
from AdminChannel import AdminChanSuite, AdminChannel
from SOCChannel import SOCChannelSuite
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
......@@ -42,11 +41,15 @@ clubs = []
users = []
#client = discord.Client()
client = commands.Bot('!')
intents = discord.Intents.default()
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=auth_channel)
await new_member._init(authChannel=await AdminChanSuite.get_auth_channel_name(member.guild))
users.append(new_member)
return new_member
......@@ -64,9 +67,6 @@ async def do_scheduled_tasks():
await SOCChannelSuite.process_tasks(clis)
except Exception as e:
print(e)
@do_scheduled_tasks.before_loop
async def wait_until_multiple_of_15_min():
......@@ -113,6 +113,14 @@ async def before_update_today_at_schools():
print('finished before loop setup. Sleeping...')
await sleep((future-now).seconds)
@client.event
async def on_guild_join(guild):
if not AdminChanSuite.get_admincat(guild):
admin = AdminChannel(guild, guild.owner)
await admin._init()
@client.event
async def on_member_join(member):
await make_new_member(member)
......@@ -130,11 +138,12 @@ async def on_message(message):
Check if channel is server's auth channel. If so, allow auth commands.
'''
try:
maybe_auth = is_auth(message.channel, auth_channel)#''' 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'''
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('got auth channel: ' + str(maybe_auth))
except:
maybe_auth = False
print('could not find auth channel')
return
print('got auth channel: ' + str(maybe_auth))
if maybe_auth:
# all messages in auth channel should delete after 3 sec, no matter what.
await message.delete(delay=3)
......@@ -146,6 +155,7 @@ async def on_message(message):
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))
'''
......@@ -154,7 +164,7 @@ async def on_message(message):
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(), student_role_name, faculty_role_name) == True:
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:
......@@ -163,7 +173,7 @@ async def on_message(message):
if '@' in content:
content = content[:content.index('@')]
print('sent email to ' + content[len('!'):])
auth_user.send_auth_email_to_addr(content[len('!'):], domain_dest,send_account_email, account_password)
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)
return 1
......@@ -176,6 +186,7 @@ async def on_message(message):
#response = AdminChanSuite.process_commands(message) # is a response number from ADminChanSUite.process_commands(message)
#if response != 0:
#
print("attempting adminchansuiteprocess")
response = await AdminChanSuite.process_commands(message)
if response:
return await handle_response_codes(message, response)
......@@ -270,7 +281,7 @@ async def on_message(message):
if message.content.startswith('<@!'):
await ClubSuite.process_at_messages(message)
try:
maybe_auth = is_auth(message.channel, auth_channel)#''' 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'''
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'''
except:
print('could not find auth channel')
if maybe_auth:
......
......@@ -7,6 +7,7 @@ Created on Sat Sep 5 14:08:39 2020
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 EmailSuite import EmailSuite
......@@ -317,14 +318,13 @@ class ClubSuite(AbstractChanSuite):
elif content.startswith("!setupemail"): #!setupemail discordname#id:email channel_to_be_active_in
colon_containing = 0
for colon_containing in range(len(message_parts)):
if ':' in message_parts[colon_containing]:
if ':' in message_parts_[colon_containing]:
break
discord_name, dest_email = message_parts_[colon_containing].split(':')
if colon_containing != 1:
discord_name = ' '.join(message_parts_[1:colon_containing] + [discord_name])
# Confirm that the discord user in the server at the moment.
print(discord_name)
user = get_member_by_discord_name(message.guild, discord_name)
if not user:
return -21
......@@ -442,9 +442,9 @@ class ClubSuite(AbstractChanSuite):
discord_user = get_member_by_discord_name(message.guild, discord_name)
# If we mentioned the user in question, email them!
if int(discord_user.id) == int(uid) and message.channel == target_chan:
email, passw = EmailSuite.get_send_email_credentials(message.guild)
sender_name = await AdminChanSuite.get_sender_name(message.guild)
await cli.send('Sent email alert to: '+ dest_email_addr + '.', delete_after=3)
EmailSuite.send_email_to_addr(dest_email_addr, email, passw, 'You have been mentioned in ' + message.channel.name + '!', 'Here is the message ' + message.author.name + ' mentioend you in! :\n\t' + discord_name + ' ' + ' '.join(message_parts[1:]))
EmailSuite.send_email_to_addr(dest_email_addr, 'You have been mentioned in ' + message.channel.name + '!', 'Here is the message ' + message.author.name + ' mentioned you in! :\n\t' + discord_name + ' ' + ' '.join(message_parts[1:]), sender_name=sender_name)
return
else:
return 0
......
......@@ -6,7 +6,8 @@ Created on Wed Oct 14 16:04:29 2020
"""
import smtplib, ssl
from handles import send_account_email, account_password
#from AdminChannel import AdminChanSuite
from handles import send_account_email, aws_pass, aws_username
'''
Just a class of email functionalities the bot uses.
'''
......@@ -15,18 +16,21 @@ Just a class of email functionalities the bot uses.
class EmailSuite:
def get_send_email_credentials(guild):
# Seperate function right now so that we can change how we get credentials later on
return (send_account_email, account_password)
#return (AdminChanSuite.get_send_email_addr(guild), AdminChanSuite.get_send_email_pass(guild))
return (aws_username,aws_pass)
def send_email_to_addr(to_email, login_email, login_password,
message_subject, message_text, send_by_email=None):
def send_email_to_addr(to_email, message_subject, message_text,
login_username=aws_username, login_pass = aws_pass,
from_email = send_account_email,
sender_name="Community Discord Server"):
port = 465
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
server.login(login_email, login_password)
with smtplib.SMTP_SSL("email-smtp.us-east-1.amazonaws.com", port, context=context) as server:
server.login(login_username, login_pass)
# TODO: Send email here
sender_email = send_by_email if send_by_email else login_email#"@gmail.com"
sender_email = from_email#"@gmail.com"
receiver_email = to_email
message = 'From:'+ sender_email + '\r\nTo: '+receiver_email + """\r\nSubject: """ + message_subject + """\r\n\r\n""" + message_text
server.sendmail(sender_email, receiver_email, message)
server.close()
\ No newline at end of file
message = 'From: ' + sender_name + ' <'+ sender_email + '>\r\nTo: '+receiver_email + """\r\nSubject: """ + message_subject + """\r\n\r\n""" + message_text
server.sendmail(from_email, receiver_email, message)
server.close()
\ No newline at end of file
......@@ -4,6 +4,7 @@ Created on Thu Oct 8 19:00:45 2020
@author: josep
"""
RESPONSE_CODES = {1: "SUCCEEDED",
2: "SUCCESSFULLY AUTHENTICATED",
3: "SUCCESSFULLY SENT EMAIL TO SUCH AND SUCH",
......@@ -11,6 +12,7 @@ RESPONSE_CODES = {1: "SUCCEEDED",
5: "REQUEST BEING PROCESSED AS WE SPEAK",
6: "WE WILL WORK ON THAT BOT FOR YOU",
7: "SUCCESSFULLY ADDED A VOICE CHANNEL",
8: "SUCCESSFULLY SET ENCRYPTED INFORMATION",
0:'NOT HANDLED HERE EXCEPTION',
-1: "NO USER USERNAME",
-2: "NO SUCH TEXTCHANNEL",
......@@ -32,6 +34,9 @@ RESPONSE_CODES = {1: "SUCCEEDED",
-18: "INVALID TIME FORMAT ERROR",
-19: "EMAILSETUP NEEDS 3 PARTS ERROR",
-21: "USER NOT FOUND ERROR",
-22: 'ADMIN CHAN ALREADY EXISTS',
-23: 'NOT IN VAR ERROR',
-24: "Too many args error",
-25: "YOU DONT HAVE PERMISSION TO ACCESS",
}
......@@ -51,6 +56,9 @@ async def handle_response_codes(message, code):
await message.channel.send('We will get back to you soon with questions and information about your bot!', delete_after = 3)
elif code == 7:
pass
elif code == 8:
await message.channel.send('Successfully saved encrypted information. Deleting your unencrypted message...')
await message.delete()
elif code == 0:
await message.channel.send("No command called: " + message.content.split(' ')[0] + ". Try again?", delete_after = 3)
elif code == -1:
......@@ -91,6 +99,10 @@ async def handle_response_codes(message, code):
await message.channel.send('Hey! !emailsetup takes 2 parameters! as !emailsetup discordname#id:destination_email channel_to_be_active_in !' , delete_after = 3)
elif code == -21:
await message.channel.send("Hey! We couldn't find that user in the discord server at all! Check your spelling and make sure you got their #4numid at the end of their name!", delete_after = 3)
elif code == -23:
await message.channel.send('Hey! That variable isn\'t in var! Try again!', delete_after = 3)
elif code == -24:
await message.channel.send("Hey! That is too many arguments for this command!", delete_after = 3)
elif code == -25:
await message.channel.send("You don't have permission to execute: " + message_parts[0], delete_after = 3)
elif type(code) == tuple:
......
......@@ -10,26 +10,40 @@ from datetime import datetime
from random import random
import json
DEV_MODE = False
DEV_MODE = True
with open('../../../ECHackersBotCreds/credentials' + ('_test_bot.json' if DEV_MODE else '.json')) as file:
credentials = json.load(file)
key = open("../../../ECHackersBotCreds/secret.key", "rb").read()
server_vars = {'sender_name=':'Discord++',
'auth_role_name0=':'',
'auth_role_name1=':'',
'auth_channel_name=':'',
'email_verification_destination_domain=':''}
auth_channel = 'auth'
domain_dest = '@earlham.edu'
send_account_email='earlhamhackerscontrol@gmail.com'
account_password = credentials['email_password']
bot_token = credentials['bot_token']
aws_username = credentials['aws_username']
aws_pass = credentials['aws_pass']
student_role_name = 'ECStudent'
faculty_role_name = 'ECFaculty'
general_user_role_names = [student_role_name, faculty_role_name]
MIN_BETWEEN_TASK_EXECUTIONS = 15
PROCESSING_TIME_PADDING = 30
clubs = []
users = []
from AdminChannel import AdminChanSuite
from EmailSuite import EmailSuite
class User:
def __init__(self, guild, member):
......@@ -92,23 +106,15 @@ You should see an email from earlhamhackerscontrol@gmail.com in your zimbra emai
self._now = datetime.now()
# Send message asking for their pre-earlham@earlham.edu email part (Do i want to do this?)
def send_auth_email_to_addr(self, email_prefix, domain_dest,send_account_email, account_password):
async def send_auth_email_to_addr(self, email_prefix):
self._email_prefix = email_prefix
port = 465
password = account_password
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
server.login("earlhamhackerscontrol@gmail.com", password)
# TODO: Send email here
sender_email = send_account_email#"@gmail.com"
receiver_email = email_prefix + domain_dest
message = 'From:'+ sender_email + '\r\nTo: '+receiver_email + """\r\nSubject: Time to join the ECDigitalCommunity...\r\n\r\n
message = """
Hello """ + self._member.name + """,
Copy \"!auth """+ self._authcode + """\" into the auth discord channel to join the ECDigitalCommunity."""
server.sendmail(sender_email, receiver_email, message)
server.close()
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 the ECDigitalCommunity...", 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.
......@@ -121,7 +127,7 @@ You should see an email from earlhamhackerscontrol@gmail.com in your zimbra emai
if authcode == self._authcode:
#make an ecmember,
print('successfully authenticated')
new_member, role_name = (ECStudent(self._member), student_role_name) if User.valid_student_email(self._email_prefix) else (ECFaculty(self._member),faculty_role_name) # FIX TO BE MORE GENERAL LATER
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 True
......@@ -178,7 +184,6 @@ class ECStudent(ECMember):
#await student_role.set_permissions( blah blah)
await self._member.add_roles(student_role)
# Give the member the ECSTUDENT role
# Give the ECStudent Role
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment