Commit 418e593f authored by IS1_4M's avatar IS1_4M
Browse files

overhaul. Fixed things. added message scheduling.

parent 1eec97ab
......@@ -22,6 +22,9 @@ class AbstractChannel:# Abstract For club, restricted, and hangout category chan
#Auto give at least one person convener access to the club.
# Needs functionality to give other ECStudents convener roles.
'''
# ONLY MAKE IF THERE ARE NO DUPLICATES.
'''
self._guild = guild
self._CLIUserRole = CLIUser
self._channelName = channelType + "-" + channelName
......@@ -34,7 +37,13 @@ class AbstractChannel:# Abstract For club, restricted, and hangout category chan
self._member_role_perms = member_role_perms
self._CLIUserRolePerms = CLIUser_role_perms
async def _init(self, standard_member_role_names, suite=None): # standard_member_roles should include variations on validated member roles. Like ECStudent, ECFaculty
# Make sure all standard roles are actually already there before calling this function.
# Make sure all standard roles are actually already there before calling this function.
is_dupe = suite._assert_non_duplicate(self._guild, self._channelName) # This respects the suite that we are making a new channel from. It can't work with AbstractChanSuite._assert_non_duplicate. intended feature.jh
if is_dupe != 1:
return is_dupe # this is a duplicate and we need to reflect that.
'''
CREATE & ASSIGN ROLES. (Expandable to include mods, operators, etc.)
'''
......@@ -74,12 +83,21 @@ class AbstractChannel:# Abstract For club, restricted, and hangout category chan
await self._cli.send(AbstractChanSuite.get_help_message(self._cli))
else:
await self._cli.send(suite.get_help_message(self._cli))
return 1
# Conveners and members of this club can post in this channel. (Use textchannel.set_permissions)
def __repr__(self):
return self._cli_channel_id
class AbstractChanSuite:
weekdays = ['Monday','Tuesday','Wesnesday','Thursday','Friday','Saturday','Sunday']
'''
Checks to make a channel does not already exist.
'''
def _assert_non_duplicate(guild, channel_type, channel_name):
for chan in AbstractChanSuite.get_all_chans(guild, channel_type):
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.
'''
......@@ -112,6 +130,15 @@ class AbstractChanSuite:
return role
return None
def get_all_clis(guild):
clis = []
for category in guild.categories:
for textchannel in category.text_channels:
if '-command-line' in textchannel.name[-1*len('-command-line'):]:
clis.append(textchannel)
break
return clis
def get_cli(category, CLIUserRoleName):
for channel in category.channels:
if category.name.lower() + '-' + CLIUserRoleName.lower() + '-command-line' == channel.name.lower():
......@@ -162,14 +189,14 @@ class AbstractChanSuite:
CLIUserRoleName = chan.name + ' ' + CLIUserRoleName
new_channel = await AbstractChanSuite.add_voice_channel(chan, channelName)
for role in chan.guild:
new_channel.set_permissions(role, read_messages=False, send_messages=False, connect=False, speak=False)
new_channel.set_permissions(role, read_messages=False, send_messages=False, connect=False, speak=False, view_channel=False)
await new_channel.set_permissions(AbstractChanSuite.get_role(chan, CLIUserRoleName), CLIUserPermissions)
async def add_private_text_chan(chan, channelName, CLIUserRoleName, CLIUserPermissions):
CLIUserRoleName = chan.name + ' ' + CLIUserRoleName
new_channel = await AbstractChanSuite.add_text_channel(chan, channelName)
for role in chan.guild:
new_channel.set_permissions(role, read_messages=False, send_messages=False, connect=False, speak=False)
new_channel.set_permissions(role, read_messages=False, send_messages=False, connect=False, speak=False, view_channel=False)
await new_channel.set_permissions(AbstractChanSuite.get_role(chan, CLIUserRoleName), CLIUserPermissions)
'''
......@@ -263,4 +290,6 @@ class AbstractChanSuite:
raise NotImplementedError()
async def process_commands(message):
return await AbstractChanSuite.process_cli_commands(message) or await AbstractChanSuite.process_user_commands(message)
\ No newline at end of file
return await AbstractChanSuite.process_cli_commands(message) or await AbstractChanSuite.process_user_commands(message)
async def process_tasks(clis):
raise NotImplementedError()
\ No newline at end of file
# -*- coding: utf-8 -*-
"""
Created on Thu Oct 8 10:08:06 2020
@author: josep
"""
import discord
from AbstractChannel import AbstractChannel, AbstractChanSuite
from handles import general_user_role_names
from PublicChannel import PublicChan, PubChanSuite
from restrictedchannel import RestrictChan
class AdminChannel(AbstractChannel):
Convenor_cli_permissions = {'read_messages':True,
'send_message':True,
'view_channel':True,
'connect':True,
'speak':True}
default_guild_role_perms = {'read_messages':False,
'view_channel':False,
'send_messages':False,
'connect':False,
'speak': False}
convenor_color = discord.Colour.red()
Member_abstract_permissions = None
channel_type = 'A'
convener_role_name = 'Admin'
member_role_name = 'none'
category_name = "Server"
convenor_color = discord.Colour.red()
def __init__(self, guild, moderator): # Should auto initialize the var section in this constructor.
# Make a cli where commands from club conveners here can shape club below.
# Have list of all voice and text channels owned by the club.
# Can only influence voice/text channels owned by this club object.
# Clubs are the only things that can act on the server. Conveners can act
# on club objects.
#Auto give at least one person convener access to the club.
# Needs functionality to give other ECStudents convener roles.
AbstractChannel.__init__(self, guild, moderator, AdminChannel.category_name,
AdminChannel.channel_type,
AdminChannel.convener_role_name,
AdminChannel.member_role_name,
AdminChannel.convenor_color,
AdminChannel.member_color,
AdminChannel.default_guild_role_perms,
AdminChannel.Member_permissions,
AdminChannel.Convenor_cli_permissions)
async def _init(self):
return await AbstractChannel._init(self, suite=AdminChanSuite)
class AdminChanSuite(AbstractChanSuite):
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.
# false if it doesn't exist.
def get_cli(category):
if category:
return AbstractChanSuite.get_cli(category, AdminChannel.convener_role_name)
def is_cli(guild, channel):
return AbstractChanSuite.is_cli(AdminChanSuite.get_all_adminchans(guild),
channel, AdminChannel.convener_role_name)
async def add_admin(channel, member):
await AbstractChanSuite.add_CLIUser(channel, member, AdminChannel.convener_role_name)
async def remove_as_moderator(chan, member):
await member.remove_roles(AdminChanSuite.get_role(chan, chan.name + ' ' + AdminChannel.convener_role_name))
def get_admin_commands():
return ['Unimplemented']
def get_restrictchan_command_examples():
return ['Unimplemented']
def get_help_message(channel):
return 'Unimplemented'
async def process_cli_commands(message):
# for case sensitive commands
raw_text = message.content
raw_text_parts = raw_text.split(' ')
# for not case sensitive commands
lower_text = raw_text.lower()
lower_text_parts = lower_text.split(' ')
# Admin category andcli for executing commands down the line.
admin_category = AdminChanSuite.get_admincat(message.guild)
admin_cli = AdminChanSuite.get_cli(admin_category)
if not admin_category or not admin_cli:
return False
'''
Case unsensitive commands go first
'''
if lower_text.startswith('!addpubchan'):
pubName = lower_text_parts[1]
# Making a new channel should ALWAYS AUTOMATICALLY check for duplicates.
new_pubchan = PublicChan(message.guild, message.author, pubName)
await new_pubchan._init(general_user_role_names)
return 1 # when you come back, finish the auto check for dupes functions.
elif lower_text.startswith('!addrestrictchan'):
resName = lower_text_parts[1]
new_restrictChan = RestrictChan(message.guild, message.author, resName)
await new_restrictChan._init()
return 1
return 0
'''
Case sensitive commands go second
'''
async def process_user_commands(message):
return False # There are never user commands in this channel because there are no users allowed.
async def process_commands(message):
return await AdminChanSuite.process_cli_commands(message) or await AdminChanSuite.process_user_commands(message)
\ No newline at end of file
......@@ -15,8 +15,12 @@ from asyncio import create_task, sleep, run
from PublicChannel import PubChanSuite, PublicChan
from ClubChannel import ClubSuite, Club
from restrictedchannel import RestrictChan, RestrictChanSuite
from handles import User, ECMember, ECStudent, ECFaculty, Organizer, Convener, Admin, SuperAdmin
from AbstractChannel import AbstractChanSuite
from AdminChannel import AdminChanSuite
from SOCChannel import SOCChannelSuite
from handles import User, ECMember, ECStudent, ECFaculty, Organizer, Convener, Admin, SuperAdmin, student_role_name, faculty_role_name, general_user_role_names
from rssfeedtest import get_today_at_earlham
from Response_Handling import handle_response_codes
import json
def get_member_by_discord_name(guild, discord_name):
......@@ -40,9 +44,6 @@ send_account_email='earlhamhackerscontrol@gmail.com'
with open('../../../ECHackersBotCreds/credentials.json') as file:
credentials = json.load(file)
student_role_name = 'ECStudent'
faculty_role_name = 'ECFaculty'
general_user_role_names = [student_role_name, faculty_role_name]
account_password = credentials['email_password']
clubs = []
users = []
......@@ -55,7 +56,33 @@ async def make_new_member(member):
await new_member._init(authChannel=auth_channel)
users.append(new_member)
return new_member
@tasks.loop(minutes=15)
async def do_scheduled_tasks():
print('started processing tasks')
for guild in client.guilds:
clis = AbstractChanSuite.get_all_clis(guild)
try:
await ClubSuite.process_tasks(clis)
except Exception as e:
print(e)
#await RestrictChanSuite.process_tasks(clis)
#await PubChanSuite.process_tasks(clis)
#await AdminChanSuite.process_tasks(clis)
#await SOCChannelSuite.process_tasks(clis)
@do_scheduled_tasks.before_loop
async def wait_until_multiple_of_15_min():
print('Started before loop of server task scheduling service')
now = datetime.now()
future = datetime(now.year, now.month, now.day, now.hour + (now.minute//15 + 1)==4, ((now.minute//15 + 1) * 15)%60, 0, 0)
print('waiting to start server task scheduling service')
await sleep((future - now).seconds)
#print('sleeping 10 seconds')
#await sleep(10)
# I need a var section big time so i can call for updates
# THIS NEEDS PRIORITY UPDATES
......@@ -67,8 +94,6 @@ async def update_today_at_schools():
print(client.guilds)
for guild in client.guilds:
print('searching guild:', guild.name)
today_at_school = None
today_at_virtual_school = None
virtual_annoucements, local_annoucements = get_today_at_earlham()
for channel in guild.channels:
print(channel.name)
......@@ -89,18 +114,12 @@ async def before_update_today_at_schools():
hour = 8
minute = 5
await client.wait_until_ready()
print('check1')
now = datetime.now()
future = datetime(now.year, now.month, now.day, hour, minute, 0)
#future = datetime.now() + timedelta(seconds=5)
print('check2')
print(now.hour, hour, now.minute, minute, now.hour >= hour, now.minute > minute)
if now.hour >= hour and now.minute > minute:
print('adding a day')
future += timedelta(days=1)
print('added a day')
print((future - now).seconds)
print('sleeping for (s): ', (future-now).seconds)
print('finished before loop setup. Sleeping...')
await sleep((future-now).seconds)
@client.event
......@@ -126,6 +145,8 @@ async def on_message(message):
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)
# Get the user to do auth stuff with
auth_user = None
for user in users:
......@@ -133,7 +154,6 @@ async def on_message(message):
auth_user = user
break
if auth_user == None:
print("Failed to find user: " + message.author.name + ". Making new one")
auth_user = await make_new_member(get_member_by_discord_name(message.channel.guild, message.author.name + "#" + message.author.discriminator))
......@@ -155,103 +175,40 @@ async def on_message(message):
auth_user.send_auth_email_to_addr(content[len('!'):], domain_dest,send_account_email, account_password)
await message.channel.send('Send auth code to: ' + content[len('!'):] + '@earlham.edu', delete_after = 3)
#run(killer)
await message.delete(delay=3)
return
return 1
'''
Check if the channel mentioned is a cli for a pubchan. If so, perform pubchan commands.
Process any ADMIN commands if any-- commands that can be performed via the
ADMIN CHANNEL structure.
'''
try:
is_admin = message.channel.name == 'admin'
#maybe_pubchan = PubChanSuite.is_cli(PubChanSuite.get_all_pubchans(message.channel.guild, message.channel))
except:
is_admin = False
if is_admin:
'''
moderator commands go here
'''
# Add, remove hangout spaces
if content.startswith('!addpubchan'):
clubName = content[len('!addpubchan '):].upper()
clubs = list(PubChanSuite.get_all_pubchans(message.channel.guild))
# make sure we're not making a duplicate club
for i in range(len(clubs)):
clubs[i] = clubs[i].name
if clubName in clubs:
await message.channel.send('Sorry, that pubchan name is already taken. try a different one?', delete_after = 5)
return
# and make the club if not a duplicate
newClub = PublicChan(message.guild, message.author, clubName)
await newClub._init(general_user_role_names)
return
'''
Restricted Channel commands go here
'''
if content.startswith('!addrestrictedchan'):
clubName = content[len('!addrestrictedchan '):].upper()
clubs = list(RestrictChanSuite.get_all_restrictchans(message.channel.guild))
# make sure we're not making a duplicate club
for i in range(len(clubs)):
clubs[i] = clubs[i].name
if clubName in clubs:
await message.channel.send('Sorry, that restrictedchannel name is already taken. try a different one?', delete_after = 5)
return
# and make the club if not a duplicate
newClub = RestrictChan(message.guild, message.author, clubName)
await newClub._init()
return
# try catch around this boy
#response = AdminChanSuite.process_commands(message) # is a response number from ADminChanSUite.process_commands(message)
#if response != 0:
#
response = await AdminChanSuite.process_commands(message)
if response:
return await handle_response_codes(message, response)
'''
Check if the channel mentioned is a cli for a club. if so, perform club commands.
'''
# try catch around this boy
if await ClubSuite.process_commands(message):
await message.channel.send('Succeeded...', delete_after=3)
return
response = await ClubSuite.process_commands(message)
if response:
return await handle_response_codes(message, response)
'''
GENERAL COMMANDS GO HERE
'''
if content.startswith('!makeclub'):
clubName = content[len('!makeclub '):].upper()
clubName = clubName.replace(' ', '-')
print(clubName)
clubs = list(ClubSuite.get_all_clubs(message.channel.guild))
# make sure we're not making a duplicate club
for i in range(len(clubs)):
clubs[i] = clubs[i].name.upper()
if clubName in clubs:
await message.channel.send('Sorry, that clubname is already taken. try a different one?', delete_after = 5)
return
# and make the club if not a duplicate
newClub = Club(message.guild, message.author, clubName)
await newClub._init()
return
elif content.startswith('!joinclub'):
target = ('c-' + content[len('!joinclub '):]).upper().replace(' ','-')
print('registered joinclub for' + target)
target_club = ClubSuite.get_club(ClubSuite.get_all_clubs(message.channel.guild), target)
await ClubSuite.add_member(target_club, message.author)
return
# Find club category
# if there is a role called category [member], add the person to the role]
elif content.startswith('!leaveclub'):
target = ('c-' + content[len('!leaveclub '):]).upper().replace(' ','-')
print('registered leaveclub for' + target)
target_club = ClubSuite.get_club(ClubSuite.get_all_clubs(message.channel.guild), target)
await ClubSuite.kick_member(target_club, message.author)
return
elif content.startswith('!MAKESTUDENT'):
student = ECStudent(get_member_by_discord_name(message.channel.guild, content[len('!MAKESTUDENT '):]))
await student._init(role_name=student_role_name)
return
elif content.startswith('!clublist'):
clubs = ClubSuite.get_all_clubs(message.channel.guild)
send_text = 'The clubs in ' + message.channel.guild.name + ' are: \n\t'
for club in clubs:
send_text += club.name[2:] + '\n\t'
await message.channel.send(send_text)
elif content.startswith('!examples'):
#elif content.startswith('!MAKESTUDENT'):
# 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'):
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',
......@@ -266,7 +223,7 @@ async def on_message(message):
for command in commands:
send_text += command + '\n\t'
await message.channel.send(send_text)
return
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.',
......@@ -278,7 +235,7 @@ async def on_message(message):
for command in commands:
send_text += command + '\n\t'
await message.channel.send(send_text)
return
return 1
elif content.startswith('!admin'):
await message.channel.send('not yet implemented...')
......@@ -304,22 +261,21 @@ async def on_message(message):
- do !help for general other commands, and !examples for how to use them
'''
await message.channel.send('What ways can do you things? You can:' + options)
# Try to process remaining commands as hangoutspace commands:
if await PubChanSuite.process_commands(message):
await message.channel.send('Succeeded... ', delete_after = 3);return
response = await PubChanSuite.process_commands(message)
if response:
return await handle_response_codes(message, response)
# or as restricted suite petitions
if await RestrictChanSuite.process_commands(message):
await message.channel.send('Succeeded... ', delete_after = 3)
return
await message.channel.send('Sorry. We didn\'t process your command. Will you check for typos or ask for help and try again?', delete_after=10)
response = await RestrictChanSuite.process_commands(message)
if response:
return await handle_response_codes(message, response)
# Always handle remaining response codes at the end.
return await handle_response_codes(message, response)
else:
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'''
except:
print('could not find auth channel')
if maybe_auth:
await message.delete(delay=3)
# Check if a message comes in from a CLI channel.
# if in a CLI channel,
# is it an admin channel?
......@@ -336,5 +292,6 @@ async def on_message(message):
# In meet & greet lobbies, link to games, shows,
# and movies after 15 min of people talking.
# We NEED to be able to host remote events. Convocation, Speaker events, and more
do_scheduled_tasks.start()
update_today_at_schools.start()
client.run(credentials['bot_token'])
......@@ -7,6 +7,7 @@ Created on Sat Sep 5 14:08:39 2020
import discord
from AbstractChannel import AbstractChanSuite, AbstractChannel
from datetime import datetime
def get_member_by_discord_name(guild, discord_name):
for member in guild.members:
if member.name + "#" + member.discriminator == discord_name:
......@@ -52,9 +53,14 @@ class Club(AbstractChannel): # Creates a club category channel with CLUB MEMBER
async def _init(self):
await self._guild.create_role(name=self._channelName + " " + Club.member_role_name)
await AbstractChannel._init(self, [self._channelName + " " + Club.member_role_name],
return await AbstractChannel._init(self, [self._channelName + " " + Club.member_role_name],
suite=ClubSuite)
class ClubSuite(AbstractChanSuite):
def _assert_non_duplicate(guild, channel_name):
if AbstractChanSuite._assert_non_duplicate(guild, Club.channel_type, channel_name) == -4:
return -5
return 1
def get_all_clubs(guild): # returns list of club categories
return AbstractChanSuite.get_all_chans(guild, Club.channel_type)
......@@ -162,7 +168,7 @@ class ClubSuite(AbstractChanSuite):
elif content.startswith('#!newptextchannel'):
await ClubSuite.add_private_text_chan(club, content[len('!newptextchannel '):])
elif content.startswith('!closeclub'):
await ClubSuite.delete_category(club); return True
await ClubSuite.delete_category(club); return 4
elif content.startswith('!addmember'):
member = get_member_by_discord_name(message.guild, content[len('!addmember '):])
await ClubSuite.add_member(club, member); return True
......@@ -211,27 +217,119 @@ class ClubSuite(AbstractChanSuite):
if await ClubSuite.remove_text_msg_from_chan(channel, content):
return True
await message.channel.send('Couldn\'t find "' + content + '" in ' + terms[1], delete_after = 10)
elif content.startswith('!schedule message'): #!schedule message date time channel message content
terms = message.content.split(' ')
await (await message.channel.send('MESSAGE SCHEDULED for ' + terms[2] + " @ " + terms[3] + ' "' + ' '.join(message_parts[5:]) + '" to ' + terms[4])).pin()
return 1
elif content.startswith('!unschedule '):
for pin in await message.channel.pins():
if pin.content == message.content[len('!unschedule '):]:
await pin.delete()
return 1
return -11
elif content.startswith('!weeklymeetingtime'): # !weeklymeetingtime date time (channels to alert)
terms = message.content.split(' ')
await (await message.channel.send('Now meeting weekly on ' + terms[1].lower() + ' at ' + terms[2])).pin()
return 1
elif content.startswith('!cancelmeetingtime'):
for message in message.pins():
if message.content == content[len('!cancelmeetingtime '):]:
message.delete()
return 1
return -12
elif content.startswith('!requestbot'):
await message.channel.send('We will get back to you soon with questions and information about your bot!')
return True#unimplemented. To implement Soon
return 6#unimplemented. To implement Soon
return False
async def process_user_commands(message):
content = message.content.lower()
message_parts = content.split(' ')
if content.startswith('!describeclub'):
cli = ClubSuite.get_cli(ClubSuite.get_club(ClubSuite.get_all_clubs(message.channel.guild), Club.channel_type + '-' + content[len('!describeclub '):].replace(' ', '-')))
# for case sensitive commands.
raw_text = message.content
raw_text_parts = raw_text.split(' ')
# for non case sensitive commands
lower_text = message.content.lower()
lower_text_parts = lower_text.split(' ')
'''
non case sensitive commands go first
'''
if lower_text.startswith('!describeclub') or lower_text.startswith('!describe'):
target_club_name = '-'.join(lower_text_parts[1:])
cli = ClubSuite.get_cli(ClubSuite.get_club(ClubSuite.get_all_clubs(message.channel.guild), Club.channel_type + '-' + target_club_name))
if cli != False:
for pin in await cli.pins():
if pin.content.startswith('DESCRIPTION SET TO: '):