def handle(self, payload: RequestFreeDaysPayload): user = self.get_user_by_slack_user_id(payload.user.id) if payload.submission: # handle add vacation - dialog submission start_date = parse_formatted_date(payload.submission.start_date) end_date = parse_formatted_date(payload.submission.end_date) self.validate_new_vacation(start_date, end_date, user) result = self.calendar_service.report_free_day( "{0} {1}".format(user.first_name, user.last_name), user.username, start_date, end_date) self.vacation_service.insert_user_vacation(user.user_id, start_date, end_date, result["id"]) self.send_message_to_client( payload.user.id, "Reported vacation from `{0}` to `{1}`".format( start_date.strftime("%A, %d %B"), end_date.strftime("%A, %d %B"))) else: action_name = next(iter(payload.actions)) if action_name == 'vacation_list': # confirmation vacation_id = payload.actions[action_name].selected_options[ 0].value return VacationCommandHandler.create_vacation_selected_message( vacation_id).dump() elif action_name == 'remove': # handle delete vacation vacation_id = payload.actions[action_name].value vacation: Vacation = self.vacation_service.get_vacation_by_id( user.user_id, vacation_id) self.calendar_service.delete_free_day(vacation.event_id) self.vacation_service.delete_vacation(user.user_id, vacation.vacation_id) return Message(text="Vacation removed! :wink:", response_type="ephemeral").dump() elif action_name == 'cancel': # cancellation return Message(text="Canceled :wink:", response_type="ephemeral").dump() else: logging.error( "Unsupported action name: {0}".format(action_name)) raise NotImplementedError()
def create_select_period_for_listing_model(self, command_body, inner_user_id): actions = [ Action(name=inner_user_id if inner_user_id is not None else command_body['user_id'], text="Select time range...", type=ActionType.SELECT.value, options=[ TextSelectOption(text=tr.value, value=tr.value) for tr in TimeRanges ]) ] attachments = [ Attachment(text="Show record for", fallback="Select time range to list saved time records", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( ListCommandPayload), actions=actions) ] return Message(text="I'm going to list saved time records...", response_type="ephemeral", mrkdwn=True, attachments=attachments)
def post(self): command_body = request.form # Verify that the request came from Slack if self.app.config['SLACK_VERIFICATION_TOKEN'] != command_body["token"]: self.app.logger.error( "Error: invalid verification token!" " Received {} but was expecting {}".format( command_body["token"], self.app.config['SLACK_VERIFICATION_TOKEN'])) return "Request contains invalid Slack verification token", 403 params = command_body["text"].split(" ") or [] action = params[0] arguments = params[1:] try: callback = self.dispatcher.get(action, self.handle_other) result = callback(command_body, arguments, action) return (result, 200) if result else (None, 204) except DataException as e: error_result: Dict = self.error_schema.dump({ 'errors': [Error(name=e.field, error=e.message)] }).data return error_result, 200 except SlackUserException as e: return Message(text=e.message, response_type="ephemeral").dump(), 200
def create_project_selected_message(last_time_entries, selected_project) -> Message: actions = [ Action(name="time_entries_list", text="Select time entry", type=ActionType.SELECT.value, options=[ TextSelectOption( text=string_helper.make_option_time_string(te), value=te.time_entry_id) for te in last_time_entries ], confirm=Confirmation(title="Delete confirmation", text="Click 'Remove' to confirm", ok_text="Remove", dismiss_text="Cancel")), ] attachments = [ Attachment(text="Select time entry to remove", fallback="Select time entry", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( DeleteTimeEntryPayload), actions=actions) ] return Message(text="There are the last time entries for *" + selected_project.name + "*:", response_type="ephemeral", mrkdwn=True, attachments=attachments)
def get_by_user_and_time_range(self, command_body, inner_user_id, selected_time_range): if inner_user_id is None: message = 'I do not know this guy: {0}'.format(inner_user_id) return Message(text=message, response_type='ephemeral') time_range = self.time_ranges.get(selected_time_range) if time_range is None: message_format = 'I am unable to understand `{0}`.\nSeems like it is not any of following: `{1}`.' message = message_format.format( selected_time_range, '`, `'.join(self.time_ranges.keys())) return Message(text=message, response_type='ephemeral', mrkdwn=True) return self._get_by_user_and_time_range(command_body, inner_user_id, time_range)
def select_vacation_to_remove(self, command_body, argument, action): user = self.get_user_by_slack_user_id(command_body['user_id']) user_vacations: List[ Vacation] = self.vacation_service.get_ten_newest_user_vacations( user.user_id) if not user_vacations: return Message(text="There is nothing to delete... ", response_type="ephemeral", mrkdwn=True).dump() actions = [ Action( name="vacation_list", text="Select vacation to delete", type=ActionType.SELECT.value, options=[ TextSelectOption( text=string_helper.make_option_vacations_string(vac), value=vac.vacation_id) for vac in user_vacations ]), ] attachments = [ Attachment(text="Select vacation to delete", fallback="Select vacation to delete", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( RequestFreeDaysPayload), actions=actions) ] return Message( text="I'm going to remove some vacations :wastebasket:...", response_type="ephemeral", mrkdwn=True, attachments=attachments).dump()
def handle(self, payload: DeleteTimeEntryPayload): action_name = next(iter(payload.actions)) action = payload.actions[action_name] user = self.get_user_by_slack_user_id(payload.user.id) if action_name == 'projects_list': # project selected project_id_selected = action.selected_options[0].value projects = self.project_service.get_projects() selected_project = list_find( lambda p: str(p.project_id) == project_id_selected, projects) last_time_entries: List[ TimeEntry] = self.user_service.get_last_ten_time_entries( user.user_id, selected_project.project_id) if len(last_time_entries) == 0: return Message(text="Can't find any time entries for *" + selected_project.name + "* :face_with_rolling_eyes:", response_type="ephemeral", mrkdwn=True).dump() return DeleteTimeCommandHandler.create_project_selected_message( last_time_entries, selected_project).dump() elif action_name == 'time_entries_list': # time entry selected time_entry_id_selected = action.selected_options[0].value self.user_service.delete_time_entry(user.user_id, time_entry_id_selected) return Message(text="Time entry removed! :wink:", response_type="ephemeral").dump() else: logging.error("Unsupported action name: {0}".format(action_name)) raise NotImplementedError()
def dispatch_project_command(self, command_body, arguments, action): user = self.get_user_by_slack_user_id(command_body['user_id']) if user.role.role != 'admin': return Message( text= "You have insufficient privileges to use this command... :neutral_face:", response_type="ephemeral", mrkdwn=True).dump() if not arguments: return self.show_dialog(command_body, arguments, action) elif arguments[0] == "assign": return self.select_project(command_body['user_id'], arguments) elif arguments[0] == "unassign": return self.select_project(command_body['user_id'], arguments) else: return Message( text= "Oops, I don't understand the command's parameters :thinking_face:", response_type="ephemeral", mrkdwn=True).dump()
def handle(self, form: ListCommandPayload): action_key = next(iter(form.actions), None) if action_key is None: return Message(text='No action key', response_type='ephemeral') action = form.actions[action_key] inner_user_id = action.name user_id = form.user.id user = self.get_user_by_slack_user_id(user_id) inner_user = self.get_user_by_slack_user_id(inner_user_id) next(iter(action.selected_options), None) time_range_selected = next(iter(action.selected_options), None).value return self.get_user_time_entries(user, inner_user, time_range_selected).dump()
def create_select_user_message(action_name, subaction_name, user_options_list): actions = [ Action(name=action_name + ":" + subaction_name, text="Select user...", type=ActionType.SELECT.value, options=user_options_list), ] attachments = [ Attachment(text="Select user for " + action_name + "...", fallback="Select user", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( ProjectAddPayload), actions=actions) ] return Message(text="", response_type="ephemeral", attachments=attachments)
def create_select_project_message(user_default_project_id, project_options_list): actions = [ Action(name="projects_list", text="Select project...", type=ActionType.SELECT.value, value=user_default_project_id, options=project_options_list), ] attachments = [ Attachment(text="Select project first", fallback="Select project", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( DeleteTimeEntryPayload), actions=actions) ] return Message(text="I'm going to remove time entry :wastebasket:...", response_type="ephemeral", attachments=attachments)
def create_select_project_message(action_name, user_default_project_id, project_options_list): actions = [ Action(name=str(action_name), text="Select project...", type=ActionType.SELECT.value, value=user_default_project_id, options=project_options_list), ] attachments = [ Attachment(text="Select project first", fallback="Select project", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( ProjectAddPayload), actions=actions) ] return Message(text="I'm going to (un)assign user to the project...", response_type="ephemeral", attachments=attachments)
def reminder_show(self, command_body, arguments, action): command_name = command_body["command"] user = self.get_user_by_slack_user_id(command_body['user_id']) day_configuration = self.reminder_service.get_user_reminder_config( user) attachments = [ Attachment(text=day_time, color="#D72B3F" if "OFF" in day_time else "#3AA3E3", attachment_type="default", mrkdwn_in=["text"]) for day_time in day_configuration ] attachments.append( Attachment(text="", footer=self.config['MESSAGE_REMINDER_SET_TIP'].format( command_name), mrkdwn_in=["text", "footer"])) return Message(text="Your reminder time is as follow:", response_type="ephemeral", mrkdwn=True, attachments=attachments).dump()
def report_pre_dialog(self, command_body, arguments, action): message_text = "I'm going to generate report..." inner_user_id = None if len(arguments): user = arguments[0] inner_user_id = self.extract_slack_user_id(user) self.get_user_by_slack_user_id(inner_user_id) actions = [ Action(name=inner_user_id if inner_user_id is not None else command_body['user_id'], text="Select time range...", type=ActionType.SELECT.value, options=[ TextSelectOption(text=tr.value, value=tr.value) for tr in TimeRanges ]) ] attachments = [ Attachment(text="Generate report for", fallback="Select time range to report", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( ReportGenerateFormPayload), actions=actions) ] return Message(text=message_text, response_type="ephemeral", mrkdwn=True, attachments=attachments).dump()
def create_vacation_selected_message(vacation_id): actions = [ Action(name="remove", text="Remove", style="danger", type=ActionType.BUTTON.value, value=str(vacation_id)), Action(name="cancel", text="Cancel", type=ActionType.BUTTON.value, value="remove") ] attachments = [ Attachment(text="Click 'Remove' to confirm:", color="#3AA3E3", attachment_type="default", callback_id=string_helper.get_full_class_name( RequestFreeDaysPayload), actions=actions) ] return Message(text="Vacation will be removed...", response_type="ephemeral", mrkdwn=True, attachments=attachments)
def create_help_command_message(self, command_body, arguments, action): command_name = command_body["command"] attachments = [ Attachment( text="*{0}* _(without any arguments)_: Submit working time". format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text="*{0} list*: See reported time".format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text="*{0} delete*: Remove reported time".format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment(text="*{0} reminder*: See reminder settings".format( command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text="*{0} report*: Generate report file".format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text='*{0} vacation*: Submit free time within range'.format( command_name), attachment_type="default", mrkdwn_in=['text']), Attachment( text='*{0} vacation delete*: Remove free time entry'.format( command_name), attachment_type="default", mrkdwn_in=['text']), Attachment( text= "*{0} reminder set [_mon:HH:MM,tue:HH:MM..._]*: Configure reminder time for particular day, or several days at once" .format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text="*{0} food [_URL_]*: Start food ordering for this channel" .format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment( text= "*{0} order*: Checkout order and display orders for today for this channel" .format(command_name), attachment_type="default", mrkdwn_in=["text"]), Attachment(text="*{0} pay*: Show your bills for food".format( command_name), attachment_type="default", mrkdwn_in=["text"]) ] user: User = self.get_user_by_slack_user_id(command_body['user_id']) if user.role.role == 'admin': attachments.append( Attachment(text="*{0} project*: Create new project".format( command_name), attachment_type="default", mrkdwn_in=["text"])) attachments.append( Attachment( text="*{0} project assign*: Assign user for project". format(command_name), attachment_type="default", mrkdwn_in=["text"])) attachments.append( Attachment( text="*{0} project unassign*: Unassign user from project". format(command_name), attachment_type="default", mrkdwn_in=["text"])) return Message( text= "*Nisse* is used for reporting working time. Following commands are available:", mrkdwn=True, response_type="default", attachments=attachments).dump()
def handle_other(commands_body, arguments, action): return Message(text="Oops, I don't understand *" + action + "* command :thinking_face:", response_type="ephemeral", mrkdwn=True).dump()
def handle(self, payload: ProjectAddPayload): if payload.submission: new_project_name: str = payload.submission.project_name self.project_service.create_project(new_project_name) self.send_message_to_client( payload.user.id, "New project *{0}* has been successfully created!".format( new_project_name)) else: action: str = next(iter(payload.actions)) action_name = action.split(":")[0] sub_action = action.split(":")[1] if action.startswith('projects_list'): # handle dialog with user selection project_id = payload.actions[action].selected_options[0].value users = [] if sub_action == "unassign": users = self.user_service.get_users_assigned_for_project( project_id) elif sub_action == "assign": users = self.user_service.get_users_not_assigned_for_project( project_id) if not users: return Message( text="There is no users to {0} :neutral_face:".format( sub_action), response_type="ephemeral", mrkdwn=True).dump() user_options_list = [ TextSelectOption(string_helper.get_user_name(p), p.user_id) for p in users ] return ProjectCommandHandler.create_select_user_message( sub_action, str(project_id), user_options_list).dump() elif action_name.startswith('assign'): # handle assign user to project project = self.project_service.get_project_by_id(sub_action) user = self.user_service.get_user_by_id( payload.actions[action].selected_options[0].value) self.project_service.assign_user_to_project(project=project, user=user) return Message( text= "User *{0}* has been successfully assigned for project *{1}* :grinning:" .format(string_helper.get_user_name(user), project.name), response_type="ephemeral", mrkdwn=True).dump() elif action_name.startswith('unassign'): # handle unassign user to project project = self.project_service.get_project_by_id(sub_action) user = self.user_service.get_user_by_id( payload.actions[action].selected_options[0].value) self.project_service.unassign_user_from_project( project=project, user=user) return Message( text= "User *{0}* has been successfully unassigned from project *{1}*" .format(string_helper.get_user_name(user), project.name), response_type="ephemeral", mrkdwn=True).dump()
def get_user_time_entries(self, user: User, inner_user: User, time_range): user_db_id = user.slack_user_id inner_user_db_id = inner_user.slack_user_id current_user_name = "You" if inner_user_db_id == user_db_id else "{0} {1}".format( inner_user.first_name, inner_user.last_name).strip() if inner_user_db_id != user_db_id and user.role.role != 'admin': message = "Sorry, but only admin user can see other users records :face_with_monocle:" return Message(text=message, response_type="ephemeral", mrkdwn=True) start_end = get_start_end_date(time_range) time_records = self.user_service.get_user_time_entries( inner_user.user_id, start_end[0], start_end[1]) time_records = sorted(time_records, key=lambda te: te.report_date, reverse=True) if len(time_records) == 0: message = "*{0}* have not reported anything for `{1}`".format( current_user_name, time_range) return Message(text=message, response_type="ephemeral", mrkdwn=True) projects = {} duration_total = 0 for time in time_records: duration_total += time.duration if projects.get(time.project.name): projects[time.project.name].text += "\n" + \ string_helper.make_time_string(time) else: projects[time.project.name] = Attachment( title=time.project.name, text=string_helper.make_time_string(time), color="#3AA3E3", attachment_type="default", mrkdwn_in=["text"]) total_duration = string_helper.format_duration_decimal(duration_total) total_message = "*{0}* reported *{1}* for `{2}`".format( current_user_name, total_duration, time_range) projects['total'] = Attachment(title="Total", text=total_message, color="#D72B3F", attachment_type="default", mrkdwn_in=["text"]) if inner_user_db_id == user_db_id: projects['footer'] = Attachment( text="", footer=self.config['MESSAGE_LIST_TIME_TIP'], mrkdwn_in=["footer"]) message = "These are hours submitted by *{0}* for `{1}`".format( current_user_name, time_range) attachments = list(projects.values()) return Message(text=message, mrkdwn=True, response_type="ephemeral", attachments=attachments)
def too_many_parameters(self): message = 'You have too much for me :confused:. I can only handle one or two parameters at once' return Message(text=message, response_type='ephemeral', mrkdwn=True)