#must include user agent, accept, content type (if post), otherwise ssc will complain
#if no pname+tname specified, session cookie is needed to avoid "Please wait while your request is processed - this may take up to a minute to complete."
headers={
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0",
#there should only be one of the cases below: either existing pinger(s) are subsets of the current one, or this pinger is a subset of an existing pinger
#otherwise it shouldve been optimized out since it is sequentially added and this optimzation runs every time
ifcourses.issuperset(against):
logger.info(f' Optimization: merging {pinger_name} into {name}')
obj.metadata.user+=pinger_obj.metadata.user
deldata[pinger_name]
elifagainst.issuperset(courses):
#this should be a terminating action to avoid adding it into multiple pingers when one is already handling it
#(think of a case where existing courses are [1234, 1256] and our pinger is [12] - 2 pingers match, but only 1 is needed)
pinger_obj.metadata.user+=obj.metadata.user
logger.info(f' Optimization: merging {name} into {pinger_name}')
name=pinger_name
merged=True
break
ifnotmerged:
data[name]=obj
set_data(data)
#returns the list of courses this pinger will ping, and the name (changed if merged)
returnname,"\n".join(obj.metadata.user[0].list)
else:
raiseValueError('No sections found!')
#done add ppl to existing pingers? see above
#done optimization for when multiple people are looking at the same course but want different sections pinged (and not all of them)
#TODO currently the way courses in section mode are handled means that they basically dont get optimized into search modes
#it would be better if pinger.metadata.courses tracks the total set of courses its users are pinging instead,
#and then have the optimizer do special code on reading section mode to not match on the courses in the list, but on the course names
#aka if everything a user is pinging has the same prefix of CPSC 110 for example,
#then just throw it into CPSC 110 section mode regardless even if currently the CPSC 110 pinger.metadata.courses does not have it
#this means that the following has to be changed:
# - instead of obj.metadata.courses = list(resp.keys()), do obj.metadata.courses = <total of all user lists>
# - at the superset checks, add check on whether everything being added is in the same course, and if there is a course pinger in section mode for that already
#edit the menu instead of sending another ephemeral msg since we cant delete the old one
#TODO figure out a better way to print since ill be using that to show a dropdown menu for the removal ui too
awaitinteraction.response.edit_message(content=f'The pinger `{name}` is now tracking the requested classes! This includes the following:\n```\n{added}\n```\nYou will now get pinged when it opens up.',view=None)
exceptExceptionase:
logger.error('AddCourseSearch fail:',exc_info=e)
awaitinteraction.response.edit_message(content=f'Something went wrong (likely wrong params): {type(e)}\n{e}',view=None)
section=ui.TextInput(label='Section',placeholder='e.g. 101, T2*, 10*/201/T1D, leave blank to open search menu',min_length=1,max_length=3,required=False)
session=ui.TextInput(label='Session',placeholder='e.g. 2022S, 2023W, defaults to coming session',min_length=5,max_length=5,required=False)
#response in this case is the same msg as the button, dont do anything to it
awaitinteraction.response.defer()
#parse session
self.sesobj={}
ifself.session.value:
self.sesobj={
'sessyr':self.session.value[:4],
'sesscd':self.session.value[-1],
}
ifnotself.section.value:
#discord doesnt allow us to send another modal right away? (yep check InteractionResponseType, 9 is modal and not in the list)
awaitinteraction.followup.send('Configure the search parameters below:',view=AddCourseSearch(self),ephemeral=True)
else:
if'*'inself.subj.valueor'*'inself.course.value:
awaitinteraction.response.send_message('Wildcards for subject and courses are not allowed in section mode! Leave section blank to do a broad search.',ephemeral=True)
return
obj=coursedict({
'subj':self.subj.value,
'crsno':self.course.value,
#even though we dont actually use the wildcard we need to differentiate between no section and a fully wildcard section so dont remove yet
awaitinteraction.followup.send(f'The pinger `{name}` is now tracking the requested classes! This includes the following:\n```\n{added}\n```\nYou will now get pinged when it opens up.',ephemeral=True)
exceptExceptionase:
logger.error('AddCourseBase fail:',exc_info=e)
awaitinteraction.followup.send(content=f'Something went wrong (likely wrong params): {type(e)}\n{e}',ephemeral=True)
#TODO dm option? or maybe just only allow dms (iirc the reason why i dont dm is coz theres no mechanism to dm multiple ppl or sth so i just send a single msg to ping everyone)
awaitinteraction.followup.send("Choose a course to remove:",view=awaitRemoveCourseList.create(interaction.user),ephemeral=True)
#done remove button (only allow ppl to remove their own, except if user id matches me so i can actually do cleanup and stuff without going into the server)
#TODO button for viewing what courses you get pinged for in a pinger? rn its not too descriptive since the optimizer makes it the broadest possible