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()
예제 #2
0
    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)
예제 #3
0
    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)
예제 #5
0
    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()
예제 #9
0
    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)
예제 #13
0
    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()
예제 #14
0
    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()
예제 #17
0
 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()
예제 #19
0
    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)
예제 #20
0
 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)