async def run_rename(self, context, opts): """ Rename a project :param context: :param opts: :return: """ user = User(context.message.author.id, context.guild.id, context) original_shortname = opts[0].lower() new_shortname = opts[1].lower() new_title = " ".join(opts[2:]) # Make sure the project exists project = user.get_project(original_shortname) if not project: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(original_shortname)) # Make sure they don't already have one with that new shortname. project_with_new_shortname = user.get_project(new_shortname) if project_with_new_shortname is not None and project_with_new_shortname.get_id() != project.get_id(): return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:exists', user.get_guild()).format(new_shortname)) # Get the original title. original_title = project.get_name() # Rename it. project.rename(new_shortname, new_title) return await context.send(user.get_mention() + ', ' + lib.get_string('project:renamed', user.get_guild()).format(original_title, original_shortname, new_title, new_shortname))
async def run_image(self, context, opts): """ Update the image link of a project @param context: @param opts: @return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() if opts else None img = opts[1] if len(opts) > 1 else None # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Check it's a valid image link. if not checkers.is_url(img) and img is not None: return await context.send( user.get_mention() + ', ' + lib.get_string( 'project:err:link', user.get_guild()).format(img)) project.set_image(img) return await context.send( user.get_mention() + ', ' + lib.get_string('project:image', user.get_guild()))
async def run_update(self, context, opts): """ Update a project's word count :param context: :param opts: :return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() amount = opts[1] if len(opts) > 1 else None # Make sure the amount is valid. amount = lib.is_number(amount) if not amount: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:amount', user.get_guild())) # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Update the word count. project.update(amount) return await context.send( user.get_mention() + ', ' + lib.get_string('project:updated', user.get_guild()).format( amount, project.get_name(), project.get_shortname()))
async def run_genre(self, context, opts): """ Update the genre of a project @param context: @param opts: @return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() if opts else None genre = opts[1].lower() if len(opts) > 1 else None # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Make sure the genre is valid. if not genre in self._genres: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:genre', user.get_guild()).format( genre, ', '.join(self._genres))) project.set_genre(genre) return await context.send( user.get_mention() + ', ' + lib.get_string('project:genre', user.get_guild()).format( lib.get_string('project:genre:' + genre, user.get_guild())))
async def run_description(self, context, opts): """ Update the description of a project @param context: @param opts: @return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() description = " ".join(opts[1:]) # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Description cannot be longer than 200 words. words = description.split(' ') if len(words) > 200: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:desc:length', user.get_guild()).format(len(words))) project.set_description(description) return await context.send( user.get_mention() + ', ' + lib.get_string('project:description', user.get_guild()))
async def run_project(self, context, shortname): """ Set the project the user wants to sprint in. :param context: :param shortname: :return: """ user = User(context.message.author.id, context.guild.id, context) sprint = Sprint(user.get_guild()) # If there is no active sprint, then just display an error if not sprint.exists(): return await context.send( user.get_mention() + ', ' + lib.get_string('sprint:err:noexists', user.get_guild())) # If the user is not sprinting, then again, just display that error if not sprint.is_user_sprinting(user.get_id()): return await context.send( user.get_mention() + ', ' + lib.get_string('sprint:err:notjoined', user.get_guild())) # Make sure the project exists. shortname = shortname.lower() if shortname is not None else None project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) sprint.set_project(project.get_id(), user.get_id()) return await context.send(user.get_mention() + ', ' + lib.get_string( 'sprint:project', user.get_guild()).format(project.get_title()))
async def run_complete(self, context, opts): """ Mark a project as completed :param context: :param opts: :return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) already_completed = project.is_completed() project.complete() # Was this the first time they completed it? if already_completed == 0: # Calculate how much XP to give them (1xp per 100 words). Min 10. Max 5000. xp = math.ceil(project.get_words() / 100) if xp < 10: xp = 10 elif xp > 5000: xp = 5000 # Give them the xp and print the message. await user.add_xp(xp) return await context.send(user.get_mention() + ', ' + lib.get_string('project:completed', user.get_guild()).format(project.get_title(), xp)) else: return await context.send(user.get_mention() + ', ' + lib.get_string('project:recompleted', user.get_guild()))
async def run_create(self, context, opts): """ Try to create a project with the given names :param context: :param shortname: :param title: :return: """ user = User(context.message.author.id, context.guild.id, context) # Get the shortname and title out of the argument list. shortname = opts[0].lower() title = " ".join(opts[1:]) # Every argument after the first one, joined with spaces. # Make sure the shortname and title are set. if len(shortname) == 0 or len(title) == 0: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:names', user.get_guild())) # Make sure they don't already have a project with this shortname project = user.get_project(shortname) if project is not None: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:exists', user.get_guild()).format(shortname)) # Create the project user.create_project(shortname, title) return await context.send(user.get_mention() + ', ' + lib.get_string('project:created', user.get_guild()).format(title, shortname))
async def run_view(self, context, opts=None): """ View a list of the user's projects :return: """ user = User(context.message.author.id, context.guild.id, context) projects = user.get_projects() # If they have no projects, then we can't display them. if not projects: return await context.send( user.get_mention() + ', ' + lib.get_string('project:noprojects', user.get_guild())) # Did they specify a shortname to look at? if opts: shortname = opts[0].lower() # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Re-create the array, but with just this one element in it. projects = [project] message = '' for project in projects: if project.is_completed(): message += ':sparkler: ' message += '**' + project.get_name( ) + '** (' + project.get_shortname() + ')\n' message += lib.get_string('wordcount', user.get_guild()) + ': ' + str( project.get_words()) + '\n\n' # Project lists can get very long. If it is over 2000 characters, we need to split it. if len(message) >= 2000: return await self.split_send( context, user, lib.get_string('project:list', user.get_guild()) + message) else: return await context.send( user.get_mention() + ', ' + lib.get_string('project:list', user.get_guild()) + message)
async def run_join(self, context, starting_wc=None, shortname=None): """ Join the sprint, with an optional starting word count and project shortname :param starting_wc: :param shortname: Shortname of Project :return: """ user = User(context.message.author.id, context.guild.id, context) sprint = Sprint(user.get_guild()) # If there is no active sprint, then just display an error if not sprint.exists(): return await context.send(user.get_mention() + ', ' + lib.get_string('sprint:err:noexists', user.get_guild())) # Convert starting_wc to int if we can starting_wc = lib.is_number(starting_wc) if starting_wc is False: starting_wc = 0 # If the user is already sprinting, then just update their starting wordcount if sprint.is_user_sprinting(user.get_id()): # Update the sprint_users record. We set their current_wc to the same as starting_wc here, otherwise if they join with, say 50 and their current remains 0 # then if they run a status, or in the ending calculations, it will say they wrote -50. sprint.update_user(user.get_id(), start=starting_wc, current=starting_wc) # Send message back to channel letting them know their starting word count was updated await context.send(user.get_mention() + ', ' + lib.get_string('sprint:join:update', user.get_guild()).format(starting_wc)) else: # Join the sprint sprint.join(user.get_id(), starting_wc) # Send message back to channel letting them know their starting word count was updated await context.send(user.get_mention() + ', ' + lib.get_string('sprint:join', user.get_guild()).format(starting_wc)) # If a project shortname is supplied, try to set that as what the user is sprinting for. if shortname is not None: # Convert to lowercase for searching. shortname = shortname.lower() # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) sprint.set_project(project.get_id(), user.get_id()) return await context.send(user.get_mention() + ', ' + lib.get_string('sprint:project', user.get_guild()).format(project.get_title()))
async def run_restart(self, context, opts): """ Mark a project as not completed :param context: :param opts: :return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) project.uncomplete() return await context.send(user.get_mention() + ', ' + lib.get_string('project:uncompleted', user.get_guild()))
async def run_status(self, context, opts): """ Update the status of a project @param context: @param opts: @return: """ user = User(context.message.author.id, context.guild.id, context) shortname = opts[0].lower() if opts else None status = opts[1].lower() if len(opts) > 1 else None # Make sure the project exists. project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Make sure the status is valid. if not status in self._statuses: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:status', user.get_guild()).format( status, ', '.join(self._statuses))) # If we are marking it finished or published for the first time, add xp. if (status == 'finished' or status == 'published') and not project.is_complete(): xp = math.ceil(project.get_words() / 100) if xp < 10: xp = 10 elif xp > 5000: xp = 5000 await user.add_xp(xp) await context.send( user.get_mention() + ', ' + lib.get_string('project:completed', user.get_guild()).format( project.get_title(), xp)) project.set_status(status) return await context.send( user.get_mention() + ', ' + lib.get_string('project:status', user.get_guild()).format( lib.get_string('project:status:' + status, user.get_guild())))
async def run_delete(self, context, opts): """ Try to delete a project with the given shortname :param context: :param opts: :return: """ user = User(context.message.author.id, context.guild.id, context) # Make sure the project exists first shortname = opts[0].lower() project = user.get_project(shortname) if not project: return await context.send(user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Delete it. project.delete() return await context.send(user.get_mention() + ', ' + lib.get_string('project:deleted', user.get_guild()).format(project.get_name(), project.get_shortname()))
async def run_view(self, context, opts): """ View a specific project :return: """ user = User(context.message.author.id, context.guild.id, context) # Make sure the project exists. if not opts: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:empty', user.get_guild())) shortname = opts[0].lower() project = user.get_project(shortname) if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) # Display the embedded message response for this project. return await project.display(context)
async def run_join(self, context, arg1=None, arg2=None): """ Join the sprint, with an optional starting word count and project shortname :param opt1: Argument 1 of the join command :param opt2: Argument 2 of the join command :return: """ user = User(context.message.author.id, context.guild.id, context) sprint = Sprint(user.get_guild()) project_id = None starting_wc = None sprint_type = None # If there is no active sprint, then just display an error if not sprint.exists(): return await context.send( user.get_mention() + ', ' + lib.get_string('sprint:err:noexists', user.get_guild())) # Are we using the `same` keyword? if arg1 == "same": # Okay, check for their most recent sprint record most_recent = user.get_most_recent_sprint(sprint) if most_recent is not None: starting_wc = most_recent['ending_wc'] project_id = most_recent['project'] sprint_type = most_recent['sprint_type'] # Can't use the second argument in this case. arg2 = None # Are we doing a no wordcount sprint? E.g. we are sprinting or using the functionality for something else. elif arg1 in ["edit", "non-wc"]: sprint_type = Sprint.SPRINT_TYPE_NO_WORDCOUNT # Can't use the second argument in this case. arg2 = None else: # Convert starting_wc to int if we can starting_wc = lib.is_number(arg1) # If the starting_wc is still False at this point, just set it to 0 if not starting_wc: starting_wc = 0 # If the user is already sprinting, then just update their starting wordcount if sprint.is_user_sprinting(user.get_id()): # Update the sprint_users record. We set their current_wc to the same as starting_wc here, otherwise if they join with, say 50 and their current remains 0 # then if they run a status, or in the ending calculations, it will say they wrote -50. sprint.update_user(user.get_id(), start=starting_wc, current=starting_wc, sprint_type=sprint_type) # If it's a non-wordcount sprint, send a different message. if sprint_type == Sprint.SPRINT_TYPE_NO_WORDCOUNT: await context.send(user.get_mention() + ', ' + lib.get_string( 'sprint:join:update:no_wordcount', user.get_guild())) else: # Send message back to channel letting them know their starting word count was updated await context.send(user.get_mention() + ', ' + lib.get_string( 'sprint:join:update', user.get_guild()).format(starting_wc) ) else: # Join the sprint sprint.join(user.get_id(), starting_wc=starting_wc, sprint_type=sprint_type) if sprint_type == Sprint.SPRINT_TYPE_NO_WORDCOUNT: await context.send(user.get_mention() + ', ' + lib.get_string( 'sprint:join:update:no_wordcount', user.get_guild())) else: # Send message back to channel letting them know their starting word count was updated await context.send(user.get_mention() + ', ' + lib.get_string( 'sprint:join', user.get_guild()).format(starting_wc)) # Currently this is the only usage of argument 2. shortname = arg2 # If a project shortname is supplied, try to set that as what the user is sprinting for. if shortname is not None or project_id is not None: # Did we supply the project by name? if shortname is not None: # Convert to lowercase for searching. shortname = shortname.lower() # Make sure the project exists. project = user.get_project(shortname) # Or do we already have the ID from using 'same' and getting from previous sprint? elif project_id is not None: project = Project(project_id) # If that did not yield a valid project, send an error message. if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) sprint.set_project(project.get_id(), user.get_id()) return await context.send( user.get_mention() + ', ' + lib.get_string('sprint:project', user.get_guild()).format( project.get_title()))
async def wrote(self, context, amount=None, shortname=None): """ Adds to your total words written statistic. Examples: !wrote 250 - Adds 250 words to your total words written !wrote 200 sword - Adds 200 words to your Project with the shortname "sword". (See: Projects for more info). """ user = User(context.message.author.id, context.guild.id, context) # Check the arguments are valid args = await self.check_arguments(context, amount=amount, shortname=shortname) if not args: return amount = args['amount'] shortname = args['shortname'] message = None # If they were writing in a Project, update its word count. if shortname is not None: project = user.get_project(shortname.lower()) # Make sure the project exists. if not project: return await context.send( user.get_mention() + ', ' + lib.get_string('project:err:noexists', user.get_guild()).format(shortname)) project.add_words(amount) written_stat = user.get_stat('total_words_written') if written_stat is None: written_stat = 0 total = int(written_stat) + int(amount) message = lib.get_string('wrote:addedtoproject', user.get_guild()).format( str(amount), project.get_title(), project.get_words(), total) # # Is there an Event running? event = Event.get_by_guild(user.get_guild()) if event and event.is_running(): event.add_words(user.get_id(), amount) # Increment their words written statistic user.add_stat('total_words_written', amount) # Update their words towards their daily goal await user.add_to_goal('daily', amount) # Output message if message is None: total = user.get_stat('total_words_written') message = lib.get_string('wrote:added', user.get_guild()).format( str(amount), str(total)) await context.send(user.get_mention() + ', ' + message)