def __init__(self, request):
     BaseController.__init__(self, request)
     self.role_repo = RoleRepo()
     self.user_role_repo = UserRoleRepo()
     self.permission_repo = PermissionRepo()
     self.andela_service = AndelaService()
     self.redis_set = RedisSet()
Exemple #2
0
 def __init__(self, request):
     BaseController.__init__(self, request)
     self.slackhelper = SlackHelper()
     self.menu_repo = MenuRepo()
     self.meal_repo = MealItemRepo()
     self.engagement_repo = VendorEngagementRepo()
     self.andela_service = AndelaService()
     self.vendor_rating_repo = VendorRatingRepo()
    def test_call_returns_json(
        self,
        mock_request_class
    ):
        service = AndelaService()

        response = self.construct_mock_response({"key":"value"}, 200)

        mock_request_class.return_value = response

        assert service.call("POST", "/andelserviceapi", email="*****@*****.**").get("key") == "value"
    def test_get_user_by_email_or_id_returns_none(
        self,
        mock_Cache_get_method,
        mock_AndelaService_call_method
    ):
        mock_Cache_get_method.return_value = None
        mock_AndelaService_call_method.return_value = {"values":""}

        service = AndelaService()

        user = service.get_user_by_email_or_id("123")

        assert user is None
Exemple #5
0
    def __init__(self, request):
        '''
        Constructor.

        Parameters:
        -----------
            request 
        '''

        BaseController.__init__(self, request)
        self.user_role_repo = UserRoleRepo()
        self.role_repo = RoleRepo()
        self.andela_service = AndelaService()
        self.user_repo = UserRepo()
    def test_get_user_by_email_or_id_returns_user(
        self,
        mock_AndelaService_call_method,
        mock_Catch_set_method,
        mock_Catch_get_method
    ):
        mock_AndelaService_call_method.return_value = {"values":["user_1","user_2"]}
        mock_Catch_set_method.return_value = None
        mock_Catch_get_method.return_value = None

        service = AndelaService()

        user = service.get_user_by_email_or_id("*****@*****.**")

        assert user == "user_1"
    def test_call_returns_exception(
        self,
        mock_request_class
    ):
        service = AndelaService()

        response = self.construct_mock_response({"key":"value"}, 400)

        mock_request_class.return_value = response

        self.assertRaises(Exception, service.call, "POST", "/andelserviceapi", email="*****@*****.**")
 def __init__(self, request):
     BaseController.__init__(self, request)
     self.order_repo = OrderRepo()
     self.meal_item_repo = MealItemRepo()
     self.andela_service = AndelaService()
     self.rating_repo = VendorRatingRepo()
class OrderController(BaseController):

    default_meal_item_return_fields = ['name', 'image', 'id', 'meal_type']

    def __init__(self, request):
        BaseController.__init__(self, request)
        self.order_repo = OrderRepo()
        self.meal_item_repo = MealItemRepo()
        self.andela_service = AndelaService()
        self.rating_repo = VendorRatingRepo()

    def list_orders(self):
        """
		List all orders in the application: should rarely be should
		:return:
		"""
        location_id = Auth.get_location()
        yesterday = date.today() - timedelta(days=1)
        tomorrow = date.today() + timedelta(days=1)

        orders = self.order_repo.get_range_paginated_options_all(
            start_date=yesterday, end_date=tomorrow, location_id=location_id)
        order_list = []
        if len(orders.items) > 0:
            for order in orders.items:
                meal_items = self.order_repo.get(order.id).meal_item_orders
                try:
                    user = self.andela_service.get_user_by_email_or_id(
                        order.user_id)
                except Exception as e:
                    return str(e)

                order_item = order.serialize()
                order_item['mealItems'] = [
                    item.to_dict(
                        only=OrderController.default_meal_item_return_fields)
                    for item in meal_items
                ]

                order_item['user'] = '******'.format(
                    user['first_name'], user['last_name']) if user else None

                rating = self.order_repo.get_rating(user['id'], 'order',
                                                    order.id) if user else None

                order_item['user_rating'] = rating

                order_list.append(order_item)

        return self.handle_response('OK',
                                    payload={
                                        'orders': order_list,
                                        'meta': self.pagination_meta(orders)
                                    })

    def list_orders_date(self, start_date):
        """
		List all orders for a particular date
		:param start_date:
		:return:
		"""
        location_id = Auth.get_location()
        orders = self.order_repo.get_unpaginated(is_deleted=False,
                                                 date_booked_for=start_date,
                                                 location_id=location_id)

        order_list = []
        if len(orders) > 0:
            for order in orders:
                meal_items = self.order_repo.get(order.id).meal_item_orders
                try:
                    user = self.andela_service.get_user_by_email_or_id(
                        order.user_id)
                except Exception as e:
                    return str(e)

                order_item = order.serialize()
                order_item['mealItems'] = [
                    item.to_dict(
                        only=OrderController.default_meal_item_return_fields)
                    for item in meal_items
                ]
                order_item['user'] = '******'.format(
                    user['first_name'], user['last_name']) if user else None

                rating = self.order_repo.get_rating(user['id'], 'order',
                                                    order.id) if user else None
                order_item['user_rating'] = rating

                order_list.append(order_item)
        return self.handle_response('OK', payload={'orders': order_list})

    def list_orders_date_range(self, start_date, end_date):
        """
		List all orders for a particular date
		:param start_date:
		:param end_date:
		:return:
		"""
        location_id = Auth.get_location()
        orders = self.order_repo.get_range_paginated_options_all(
            start_date=start_date, end_date=end_date, location_id=location_id)

        order_list = []
        if len(orders.items) > 0:
            for order in orders.items:
                meal_items = self.order_repo.get(order.id).meal_item_orders
                try:
                    user = self.andela_service.get_user_by_email_or_id(
                        order.user_id)
                except Exception as e:
                    return str(e)
                order_item = order.serialize()
                order_item['mealItems'] = [
                    item.to_dict(
                        only=OrderController.default_meal_item_return_fields)
                    for item in meal_items
                ]
                order_item['user'] = '******'.format(
                    user['first_name'], user['last_name']) if user else None

                rating = self.order_repo.get_rating(user['id'], 'order',
                                                    order.id) if user else None

                order_item['user_rating'] = rating

                order_list.append(order_item)
        return self.handle_response('OK', payload={'orders': order_list})

    def get_order(self, order_id):
        """
		Gets all orders for an order_id
		:param order_id:
		:return:
		"""
        order = self.order_repo.get(order_id)
        if order:
            order_serialized = order.serialize()
            order_serialized['mealItems'] = [
                item.to_dict(
                    only=OrderController.default_meal_item_return_fields)
                for item in order.meal_item_orders
            ]

            try:
                user = self.andela_service.get_user_by_email_or_id(
                    order.user_id)
            except Exception as e:
                return str(e)
            order_serialized['user'] = '******'.format(
                user['first_name'], user['last_name']) if user else None

            rating = self.order_repo.get_rating(user['id'], 'order',
                                                order.id) if user else None

            order_serialized['user_rating'] = rating

            return self.handle_response('OK',
                                        payload={'order': order_serialized})
        return self.handle_response('Order not found', status_code=400)

    def get_order_by_user_id(self, user_id):
        """
		Gets all orders for a user by the user id
		:param user_id:
		:return: list of orders in json model
		"""
        orders = self.order_repo.filter_by(user_id=user_id, is_deleted=False)
        orders_list = []
        if len(orders.items) > 0:
            for order in orders.items:
                meal_items = self.order_repo.get(order.id).meal_item_orders
                try:
                    user = self.andela_service.get_user_by_email_or_id(
                        order.user_id)
                except Exception as e:
                    return str(e)
                order_item = order.serialize()
                order_item['mealItems'] = [
                    item.to_dict(
                        only=OrderController.default_meal_item_return_fields)
                    for item in meal_items
                ]
                order_item['user'] = '******'.format(
                    user['first_name'], user['last_name']) if user else None

                rating = self.order_repo.get_rating(user['id'], 'order',
                                                    order.id) if user else None

                order_item['user_rating'] = rating

                orders_list.append(order_item)
        return self.handle_response('OK', payload={'orders': orders_list})

    def get_order_by_user_id_date_range(self, user_id, start_date, end_date):
        """

		:param user_id:
		:param start_date:
		:param end_date:
		:return:
		"""
        orders = self.order_repo.get_range_paginated_options(
            user_id=user_id, start_date=start_date, end_date=end_date)
        order_list = []
        if len(orders.items) > 0:
            for order in orders.items:
                meal_items = self.order_repo.get(order.id).meal_item_orders
                user = self.andela_service.get_user_by_email_or_id(
                    order.user_id)
                order_item = order.serialize()
                order_item['mealItems'] = [
                    item.to_dict(
                        only=OrderController.default_meal_item_return_fields)
                    for item in meal_items
                ]
                order_item['user'] = '******'.format(
                    user['first_name'], user['last_name']) if user else None

                rating = self.order_repo.get_rating(user['id'], 'order',
                                                    order.id) if user else None

                order_item['user_rating'] = rating

                order_list.append(order_item)
        return self.handle_response('OK', payload={'orders': order_list})

    def create_order(self):
        """
		creates an order
		:return: order object
		"""
        user_id = Auth.user('id')
        location_id = Auth.get_location()
        date_booked_for, channel, meal_period, meal_items, menu_id = self.request_params(
            'dateBookedFor', 'channel', 'mealPeriod', 'mealItems', 'menuId')
        if self.order_repo.user_has_order(user_id, date_booked_for,
                                          meal_period):
            return self.handle_response(
                'You have already booked for this meal period.',
                status_code=400)

        location = LocationRepo().get(location_id)
        current_time = current_time_by_zone(location.zone)

        if datetime.strptime(date_booked_for, "%Y-%m-%d") < datetime.now():
            return self.handle_response(
                'You are not allowed to book for a date in the past',
                status_code=400)

        if int(current_time_by_zone(location.zone).strftime('%H')) > 15:
            if check_date_current_vs_date_for(
                    current_time, datetime.strptime(date_booked_for,
                                                    "%Y-%m-%d")):
                return self.handle_response(
                    'It is too late to book a meal for the selected date ',
                    status_code=400)

        meal_object_items = self.meal_item_repo.get_meal_items_by_ids(
            meal_items)

        new_order = self.order_repo.create_order(user_id, date_booked_for,
                                                 meal_object_items,
                                                 location_id, menu_id, channel,
                                                 meal_period).serialize()

        new_order['mealItems'] = [
            item.to_dict(only=OrderController.default_meal_item_return_fields)
            for item in meal_object_items
        ]
        return self.handle_response('OK',
                                    payload={'order': new_order},
                                    status_code=201)

    def update_order(self, order_id):
        """
		updates an order based on the order Id
		:param order_id:
		:return:
		"""
        date_booked_for, channel, meal_items, menu_id = self.request_params(
            'dateBookedFor', 'channel', 'mealItems', 'menuId')

        meal_object_items = []
        for meal_item_id in meal_items:
            meal_item = self.meal_item_repo.get(meal_item_id)
            meal_object_items.append(meal_item)

        order = self.order_repo.get(order_id)
        if order:
            if order.is_deleted:
                return self.handle_response('Order has already been deleted',
                                            status_code=400)
            updates = {}
            if date_booked_for:
                order_date_midnight = datetime.strptime(
                    date_booked_for, '%Y-%m-%d').replace(hour=00).replace(
                        minute=00).replace(second=00)
                current_time = datetime.now()
                if order_date_midnight - current_time < timedelta(
                        'hours' == 7):
                    return self.handle_response(
                        'It is too late to book meal for the selected date ',
                        status_code=400)
                updates['date_booked_for'] = datetime.strptime(
                    date_booked_for, '%Y-%m-%d')

            if menu_id:
                updates['menu_id'] = menu_id

            if channel:
                updates['channel'] = channel
            if meal_items:
                updates['meal_item_orders'] = meal_object_items

            updated_order = self.order_repo.update(order,
                                                   **updates).serialize()
            updated_order['mealItems'] = [
                item.to_dict(
                    only=OrderController.default_meal_item_return_fields)
                for item in order.meal_item_orders
            ]
            return self.handle_response('OK', payload={'order': updated_order})

        return self.handle_response('Invalid or incorrect order_id provided',
                                    status_code=400)

    def collect_order(self):
        """
		Collects order and mark as collected for a user Id
		:param user_id:
		:param order_type:
		:param order_date:
		:return:
		"""
        user_id, order_type, order_date = self.request_params(
            'userId', 'orderType', 'orderDate')

        order = self.order_repo.find_first(user_id=user_id,
                                           meal_period=order_type,
                                           date_booked_for=order_date,
                                           is_deleted=False)
        if not order:
            return self.handle_response(
                f'User has no {order_type} order for the date.',
                status_code=400)

        if order.order_status == OrderStatus.collected:
            return self.handle_response('Order already collected',
                                        status_code=400)

        updates = {}
        updates['order_status'] = OrderStatus.collected
        self.order_repo.update(order, **updates)

        return self.handle_response('Order successfully collected',
                                    payload={'order': order.serialize()})

    def check_order(self):
        """
		Checks if a user has an order for a particular date and period

		:return:
		"""
        user_id, order_type, order_date = self.request_params(
            'userId', 'orderType', 'orderDate')
        # get user_id from another method and reform to db's user id
        order = self.order_repo.find_first(user_id=user_id,
                                           meal_period=order_type,
                                           date_booked_for=order_date,
                                           is_deleted=False)
        if not order:
            return self.handle_response(
                f'User has no {order_type} order for this date')
        return self.handle_response('OK', payload={'order': order.serialize()})

    def delete_order(self, order_id):

        order = self.order_repo.get(order_id)

        if order:
            if order.is_deleted:
                return self.handle_response('Order has already been deleted',
                                            status_code=400)
            if Auth.user('id') != order.user_id:
                return self.handle_response(
                    'You cannot delete an order that is not yours',
                    status_code=403)

            updates = {}
            updates['is_deleted'] = True

            self.order_repo.update(order, **updates)
            return self.handle_response('Order deleted',
                                        payload={"status": "success"})
        return self.handle_response('Invalid or incorrect order_id provided',
                                    status_code=400)
Exemple #10
0
class UserController(BaseController):
    '''
    User Controller.
    '''
    def __init__(self, request):
        '''
        Constructor.

        Parameters:
        -----------
            request 
        '''

        BaseController.__init__(self, request)
        self.user_role_repo = UserRoleRepo()
        self.role_repo = RoleRepo()
        self.andela_service = AndelaService()
        self.user_repo = UserRepo()

    def list_admin_users(self, admin_role_id: int = 1) -> list:
        '''
        List admin users.

        Parameters:
        -----------
        admin_role_id {int}
            Admin role ID (default: {1}).

        Returns:
        --------
        list
            List of admin users' profiles.
        '''

        user_roles = self.user_role_repo.filter_by(role_id=admin_role_id,
                                                   is_active=True)

        admin_users_list = []
        for user_role in user_roles.items:
            admin_user_profile = {}
            andela_user_profile = self.andela_service.get_user_by_email_or_id(user_role.user_id) or \
                                  self.andela_service.get_user_by_email_or_id(user_role.email)

            if andela_user_profile:
                associated_roles = [
                    user_role.role_id
                    for user_role in self.user_role_repo.filter_by(
                        user_id=user_role.user_id).items
                ]
                role_objects = Role.query.filter(
                    Role.id.in_(associated_roles)).all()
                roles = [{
                    'role_id': role.id,
                    'role_name': role.name
                } for role in role_objects]
                admin_user_profile['email'] = andela_user_profile['email']
                admin_user_profile['name'] = andela_user_profile['name']
                admin_user_profile['id'] = andela_user_profile['id']
                admin_user_profile['roles'] = roles

                admin_users_list.append(admin_user_profile)

        return self.handle_response('OK',
                                    payload={
                                        'adminUsers': admin_users_list,
                                        'meta':
                                        self.pagination_meta(user_roles)
                                    })

    def list_all_users(self):

        params = self.get_params_dict()
        page = params.get('page')
        per_page = params.get('per_page')

        users = self.user_repo.paginate(error_out=False,
                                        page=page,
                                        per_page=per_page)
        if users.items:
            user_list = [user.serialize() for user in users.items]
            for user in user_list:
                associated_roles = [
                    user_role.role_id
                    for user_role in self.user_role_repo.filter_by(
                        user_id=user['userId']).items
                ]
                role_objects = Role.query.filter(
                    Role.id.in_(associated_roles)).all()
                roles = [{
                    'id': role.id,
                    'name': role.name
                } for role in role_objects]
                user['userRoles'] = roles
                del user['userTypeId']
            return self.handle_response('OK',
                                        payload={
                                            'users': user_list,
                                            'meta': self.pagination_meta(users)
                                        })
        return self.handle_response('No users found', status_code=404)

    def delete_user(self, id):
        user = self.user_repo.get(id)
        if user:
            if user.is_deleted:
                return self.handle_response('User has already been deleted',
                                            status_code=400)

            updates = {}
            updates['is_deleted'] = True

            self.user_repo.update(user, **updates)

            return self.handle_response('User deleted',
                                        payload={"status": "success"})
        return self.handle_response('Invalid or incorrect id provided',
                                    status_code=404)

    def create_user(self):
        push_id = PushID()
        next_id = push_id.next_id()

        user_info = self.request_params('firstName', 'lastName', 'imageUrl',
                                        'slackId', 'userId', 'roleId')

        first_name, last_name, image_url, slack_id, user_id, role_id = user_info

        role = self.role_repo.find_first(id=role_id)

        if not role:
            return self.handle_response(
                f"Role with userTypeId(roleId) {role_id} does not exist",
                status_code=400)

        if self.user_repo.exists(slack_id=slack_id):
            return self.handle_response(
                f"User with slackId '{slack_id}' already exists",
                status_code=400)

        if self.user_repo.exists(user_id=user_id) and user_id is not None:
            return self.handle_response(
                f"User with userId '{user_id}' already exists",
                status_code=400)

        slack_id = slack_id if slack_id else next_id
        user_id = user_id if user_id else slack_id

        user_type = self.user_role_repo.find_first(user_id=user_id) or \
                    self.user_role_repo.new_user_role(
                        role_id=role_id, user_id=user_id, location_id=Auth.get_location(),email=None)

        user = self.user_repo.new_user(*user_info,
                                       user_id=user_id,
                                       slack_id=slack_id,
                                       user_type=user_type).serialize()

        user.__setitem__(
            'userRoles',
            [role.to_dict(only=['id', 'name', 'help', "timestamps"])])
        user.pop('userTypeId')

        return self.handle_response('OK',
                                    payload={'user': user},
                                    status_code=201)

    def list_user(self, slack_id):

        user = self.user_repo.find_first(slack_id=slack_id)

        if user:
            user_data = user.serialize()
            del user_data['userTypeId']
            user_data['userRoles'] = [
                self.role_repo.get(
                    user.user_type.role_id).to_dict(only=['id', 'name'])
            ]
            return self.handle_response('OK',
                                        payload={'user': user_data},
                                        status_code=200)

        return self.handle_response('User not found', status_code=404)

    def update_user(self, user_id):
        user = self.user_repo.get(user_id)

        if not user:
            return self.handle_response(msg="FAIL",
                                        payload={'user': '******'},
                                        status_code=404)

        if user.is_deleted:
            return self.handle_response(
                msg="FAIL",
                payload={'user': '******'},
                status_code=400)

        user_info = self.request_params_dict('slackId', 'firstName',
                                             'lastName', 'userId', 'imageUrl',
                                             'roleId')

        slack_id = user_info.get('slack_id')
        user_id_sent = user_info.get('user_id')

        if slack_id and self.user_repo.check_exists_else_where(
                User, 'slack_id', slack_id, 'id', user_id):
            return self.handle_response(
                msg="FAIL",
                payload={
                    'user':
                    '******'
                },
                status_code=403)

        if user_id_sent and self.user_repo.check_exists_else_where(
                User, 'user_id', user_id_sent, 'id', user_id):
            return self.handle_response(
                msg="FAIL",
                payload={
                    'user':
                    '******'
                },
                status_code=403)

        if user_info.get('role_id'):
            role_id = user_info['role_id']
            if not self.role_repo.exists(id=role_id):
                return self.handle_response(
                    f'Role with id {role_id} doesnot exist', status_code=400)
            self.user_role_repo.update(user.user_type, role_id=role_id)

        user = self.user_repo.update(user, **user_info)
        user_data = user.serialize()

        user_data['userRoles'] = [
            self.role_repo.get(
                user.user_type.role_id).to_dict(only=['id', 'name'])
        ]

        return self.handle_response('OK',
                                    payload={'user': user_data},
                                    status_code=200)
Exemple #11
0
class BotController(BaseController):
    def __init__(self, request):
        BaseController.__init__(self, request)
        self.slackhelper = SlackHelper()
        self.menu_repo = MenuRepo()
        self.meal_repo = MealItemRepo()
        self.engagement_repo = VendorEngagementRepo()
        self.andela_service = AndelaService()
        self.vendor_rating_repo = VendorRatingRepo()

    def bot(self):
        locations = LocationRepo().fetch_all()
        location_buttons = [{
            'name': 'location',
            'text': f'{location.name}',
            'type': "button",
            'value': location.id
        } for location in locations.items]

        request_buttons = [{
            "text": "",
            "callback_id": "center_selector",
            "color": "#3AA3E3",
            "attachment_type": "default",
            "actions": location_buttons
        }]

        return self.handle_response(slack_response={
            'text': f'Welcome To Andela Eats',
            'attachments': request_buttons
        })

    def interactions(self):
        request_payload, trigger_id = self.post_params('payload', 'trigger_id')
        payload = json.loads(request_payload)

        webhook_url = payload["response_url"]
        slack_id = payload['user']['id']

        if payload['type'] == 'dialog_submission':
            slack_user_info = self.slackhelper.user_info(slack_id)
            slack_user_email = slack_user_info['user']['profile']['email']

            if payload['callback_id'] == 'final_selection':

                state = payload['state'].split('_')
                menu_id = state[0]
                meal_period = state[1]
                date_booked_for = state[2]
                location_id = state[4]
                submitted_values = payload['submission']
                meal_items = [int(v) for k, v in submitted_values.items()]
                meal_items.append(MenuRepo().get(menu_id).main_meal_id)
                meal_items = [
                    meal for meal in MealItemRepo().get_meal_items_by_ids(
                        meal_items)
                ]
                channel = 'slack'

                # Retrieve User Object
                user = self.andela_service.get_user_by_email_or_id(
                    slack_user_email)
                user_id = user['id']

                order = OrderRepo().create_order(
                    user_id=user_id,
                    date_booked_for=date_booked_for,
                    meal_items=meal_items,
                    location_id=location_id,
                    menu_id=menu_id,
                    channel=channel,
                    meal_period=meal_period)

                if order:
                    slack_data = {'text': 'Booking Confirmed!'}
                    requests.post(webhook_url,
                                  data=json.dumps(slack_data),
                                  headers={'Content-Type': 'application/json'})
                else:
                    slack_data = {'text': 'Booking Failed. Please Retry'}
                    requests.post(webhook_url,
                                  data=json.dumps(slack_data),
                                  headers={'Content-Type': 'application/json'})

            if payload['callback_id'] == 'submit_rating':

                state = payload['state'].split('_')
                menu_id = state[0]
                menu = self.menu_repo.get(menu_id)
                service_date = menu.date
                rating_type = RatingType.meal
                type_id = menu.main_meal_id
                engagement_id = menu.vendor_engagement_id
                vendor_id = self.engagement_repo.get(engagement_id).vendor_id
                rating_value = payload['submission']['rating value']
                channel = 'slack'
                comment = payload['submission']['comment']

                # Retrieve User Object
                user = self.andela_service.get_user_by_email_or_id(
                    slack_user_email)
                user_id = user['id']

                rating = self.vendor_rating_repo.new_rating(
                    vendor_id, user_id, rating_value, service_date,
                    rating_type, type_id, engagement_id, channel, comment,
                    type_id)

                if rating:
                    slack_data = {'text': 'Rating Successful!'}
                    requests.post(webhook_url,
                                  data=json.dumps(slack_data),
                                  headers={'Content-Type': 'application/json'})
                else:
                    slack_data = {'text': 'Rating Failed. Please Retry'}
                    requests.post(webhook_url,
                                  data=json.dumps(slack_data),
                                  headers={'Content-Type': 'application/json'})

            return make_response('', 200)

        if payload['type'] == 'interactive_message' and payload[
                'callback_id'] == 'center_selector':
            location_id = payload['actions'][0]['value']

            location = LocationRepo().get(location_id)
            menu_start_end_on = BotController.get_menu_start_end_on(location)
            start_on = menu_start_end_on[0]
            end_on = menu_start_end_on[1]

            date_buttons = [{
                'name':
                'selected_date',
                'type':
                'button',
                'text':
                '{}, {}'.format(day.strftime('%a'), day.strftime('%b %-d')),
                'value':
                '{}_{}'.format(day.strftime('%Y-%m-%d'), location.id)
            } for day in daterange(start_on, end_on)]

            request_buttons = [{
                "text": "",
                "callback_id": "day_selector",
                "color": "#3AA3E3",
                "attachment_type": "default",
                "actions": date_buttons
            }]

            return self.handle_response(slack_response={
                'text': f'Select Date',
                'attachments': request_buttons
            })

        if payload['type'] == 'interactive_message' and payload[
                'callback_id'] == 'day_selector':
            payload_action_value = payload['actions'][0]['value']
            selected_date = payload_action_value.split('_')[0]
            location_id = payload_action_value.split('_')[1]

            period_buttons = [
                # {'name': 'meal_period', 'type': 'button', 'text': 'Breakfast',
                #  'value': 'breakfast_{}'.format(payload_action_value)},
                {
                    'name': 'meal_period',
                    'type': 'button',
                    'text': 'Lunch',
                    'value': 'lunch_{}'.format(payload_action_value)
                }
            ]

            request_buttons = [{
                "text": "",
                "callback_id": "period_selector",
                "color": "#3AA3E3",
                "attachment_type": "default",
                "actions": period_buttons
            }]

            return self.handle_response(slack_response={
                'text': f'Select Meal Period',
                'attachments': request_buttons
            })

        if payload['type'] == 'interactive_message' and payload[
                'callback_id'] == 'period_selector':
            period = payload['actions'][0]['value'].split('_')[0]
            date = payload['actions'][0]['value'].split('_')[1]
            location_id = payload['actions'][0]['value'].split('_')[2]
            actions = {
                "attachments": [{
                    "text":
                    'What do you want to do?',
                    "callback_id":
                    "action_selector",
                    "color":
                    "#3AA3E3",
                    "attachment_type":
                    "default",
                    "actions": [{
                        "name": "main meal",
                        "text": "View Menu List",
                        "type": "button",
                        "value": f'{period}_{date}_menu_{location_id}'
                    }, {
                        "name": "main meal",
                        "text": "Place order",
                        "type": "button",
                        "value": f'{period}_{date}_order_{location_id}'
                    }]
                }]
            }
            return self.handle_response(slack_response=actions)

        if payload['type'] == 'interactive_message' and payload[
                'callback_id'] == 'action_selector':
            payload_action_value = payload['actions'][0]['value']
            if payload_action_value.split('_')[2] == 'menu':
                date = payload_action_value.split('_')[1]
                period = payload_action_value.split('_')[0]
                location_id = payload_action_value.split('_')[3]
                menus = self.menu_repo.get_unpaginated(date=date,
                                                       meal_period=period,
                                                       is_deleted=False)
                if not menus:
                    #   No Menu for provided date
                    back_buttons = [{
                        'name': 'back',
                        'text': 'Back',
                        'type': "button",
                        'value': location_id
                    }]
                    request_buttons = [{
                        "text": "",
                        "callback_id": "center_selector",
                        "color": "#3AA3E3",
                        "attachment_type": "default",
                        "actions": back_buttons
                    }]
                    return self.handle_response(
                        slack_response={
                            'text':
                            f'Sorry No Menu found for Date: {date}, Meal Period: {period}',
                            'attachments': request_buttons
                        })
                text = ''

                for menu in menus:
                    side_items_list = menu.side_items.split(',')
                    protein_items_list = menu.protein_items.split(',')

                    main = self.meal_repo.get(menu.main_meal_id).name
                    sides = [
                        side.name for side in
                        self.meal_repo.get_meal_items_by_ids(side_items_list)
                    ]
                    proteins = [
                        protein.name
                        for protein in self.meal_repo.get_meal_items_by_ids(
                            protein_items_list)
                    ]
                    menu_info = f'Main meal: *{main}*\n Side items: {", ".join(sides)}\nProtein items: {", ".join(proteins)}\n\n\n'
                    text += menu_info

                meals = {
                    "text":
                    f'{period.upper()}',
                    "attachments": [{
                        "text":
                        text,
                        "callback_id":
                        "after_menu_list",
                        "color":
                        "#3AA3E3",
                        "attachment_type":
                        "default",
                        "actions": [{
                            "name":
                            "main meal",
                            "text":
                            "Rate meal",
                            "type":
                            "button",
                            "value":
                            f'{period}_{date}_rate_{location_id}_{location_id}'
                        }, {
                            "name":
                            "main meal",
                            "text":
                            "Place an order",
                            "type":
                            "button",
                            "value":
                            f'{period}_{date}_order_{location_id}_{location_id}'
                        }]
                    }]
                }
                return self.handle_response(slack_response=meals)

        if (payload['type'] == 'interactive_message'
                and payload['callback_id'] == 'action_selector'
                and payload['actions'][0]['value'].split('_')[2] == 'order'
            ) or (payload['callback_id'] == 'after_menu_list'
                  and payload['actions'][0]['value'].split('_')[2] == 'order'):
            payload_action_value = payload['actions'][0]['value']
            meal_period = payload_action_value.split('_')[0]
            selected_date = payload_action_value.split('_')[1]
            location_id = payload_action_value.split('_')[3]
            menus = self.menu_repo.get_unpaginated(date=selected_date,
                                                   meal_period=meal_period,
                                                   is_deleted=False)
            if not menus:
                #   No Menu for provided date
                back_buttons = [{
                    'name': 'back',
                    'text': 'Back',
                    'type': "button",
                    'value': location_id
                }]

                request_buttons = [{
                    "text": "",
                    "callback_id": "center_selector",
                    "color": "#3AA3E3",
                    "attachment_type": "default",
                    "actions": back_buttons
                }]
                return self.handle_response(
                    slack_response={
                        'text':
                        f'Sorry No Menu found for Date: {selected_date}, Meal Period: {meal_period}',
                        'attachments': request_buttons
                    })

            meal_buttons = [{
                'name': 'main_meal',
                'type': 'button',
                'text': f'{menu.main_meal.name}',
                'value': f'{menu.id}_{payload_action_value}'
            } for menu in menus]

            request_buttons = [{
                "text": "",
                "callback_id": "meal_action_selector",
                "color": "#3AA3E3",
                "attachment_type": "default",
                "actions": meal_buttons
            }]

            return self.handle_response(slack_response={
                'text': 'Select Main Meal',
                'attachments': request_buttons
            })

        if payload['type'] == 'interactive_message' and payload[
                'callback_id'] == 'meal_action_selector':
            payload_action_value = payload['actions'][0]['value']
            if payload_action_value.find('order') > -1:
                menu_id = payload_action_value.split('_')[0]
                menu = self.menu_repo.get(menu_id)
                slack_id = payload['user']['id']
                slack_user_info = self.slackhelper.user_info(slack_id)
                slack_user_email = slack_user_info['user']['profile']['email']
                user = self.andela_service.get_user_by_email_or_id(
                    slack_user_email)

                # check if user already has an order
                if OrderRepo().user_has_order(user['id'],
                                              menu.date.strftime('%Y-%m-%d'),
                                              menu.meal_period):
                    slack_data = {
                        'text':
                        'You already have an order for this meal period.'
                    }
                    requests.post(webhook_url,
                                  data=json.dumps(slack_data),
                                  headers={'Content-Type': 'application/json'})
                    return self.handle_response(status_code=400)
                trigger_id = payload['trigger_id']

                side_items_list = menu.side_items.split(',')
                protein_items_list = menu.protein_items.split(',')

                side_items = self.meal_repo.get_meal_items_by_ids(
                    side_items_list)
                protein_items = self.meal_repo.get_meal_items_by_ids(
                    protein_items_list)

                request_dialog_element = []

                for i in range(1, menu.allowed_side + 1):
                    request_dialog_element.append({
                        'label':
                        f'Select Side {i}',
                        'type':
                        'select',
                        'name':
                        f'side_{i}',
                        'options': [{
                            'label': f'{side.name}',
                            'value': f'{side.id}'
                        } for side in side_items]
                    })

                for i in range(1, menu.allowed_protein + 1):
                    request_dialog_element.append({
                        'label':
                        f'Select Protein {i}',
                        'type':
                        'select',
                        'name':
                        f'protein_{i}',
                        'options': [{
                            'label': f'{protein.name}',
                            'value': f'{protein.id}'
                        } for protein in protein_items]
                    })

                state = f'{payload_action_value}'
                self.create_dialog(dialog_elem=request_dialog_element,
                                   trigger_id=trigger_id,
                                   title='Select Protein & Sides',
                                   callback_id='final_selection',
                                   state=state)

                return self.handle_response(
                    slack_response={'text': 'Select Meal Protein and Sides'})

        if payload['callback_id'] == 'after_menu_list' and payload['actions'][
                0]['value'].split('_')[2] == 'rate':

            payload_action_value = payload['actions'][0]['value']
            meal_period = payload_action_value.split('_')[0]
            selected_date = payload_action_value.split('_')[1]
            location_id = payload_action_value.split('_')[2]
            menus = self.menu_repo.get_unpaginated(date=selected_date,
                                                   meal_period=meal_period,
                                                   is_deleted=False)
            if not menus:
                #   No Menu for provided date
                back_buttons = [{
                    'name': 'back',
                    'text': 'Back',
                    'type': "button",
                    'value': location_id
                }]

                request_buttons = [{
                    "text": "",
                    "callback_id": "center_selector",
                    "color": "#3AA3E3",
                    "attachment_type": "default",
                    "actions": back_buttons
                }]
                return self.handle_response(
                    slack_response={
                        'text':
                        f'Sorry No Menu found forr Date: {selected_date}, Meal Period: {meal_period}',
                        'attachments': request_buttons
                    })

            meal_buttons = [{
                'name': 'main_meal',
                'type': 'button',
                'text': f'{menu.main_meal.name}',
                'value': f'{menu.id}_{payload_action_value}'
            } for menu in menus]

            request_buttons = [{
                "text": "",
                "callback_id": "rating_selector",
                "color": "#3AA3E3",
                "attachment_type": "default",
                "actions": meal_buttons
            }]

            return self.handle_response(slack_response={
                'text': 'Select Main Meal',
                'attachments': request_buttons
            })

        if payload['callback_id'] == 'rating_selector':

            menu_id = payload['actions'][0]['value'].split('_')[0]
            menu = self.menu_repo.get(menu_id)
            trigger_id = payload['trigger_id']
            main_meal = menu.main_meal_id

            request_dialog_element = [{
                'label':
                f'Rate meal: {self.meal_repo.get(main_meal).name}',
                'type':
                'select',
                'name':
                'rating value',
                'options': [{
                    'label': f'{value}',
                    'value': f'{value}'
                } for value in range(1, 6)]
            }, {
                'label': 'Add a short comment',
                'type': 'text',
                'name': 'comment'
            }]

            state = f'{payload["actions"][0]["value"]}'
            self.create_dialog(dialog_elem=request_dialog_element,
                               trigger_id=trigger_id,
                               title='Rate a meal',
                               callback_id='submit_rating',
                               state=state)

            return self.handle_response(slack_response={'text': 'Meal rating'})

    def create_dialog(self,
                      dialog_elem,
                      trigger_id,
                      title,
                      callback_id,
                      state=None):
        dialog = {
            "title": title,
            "submit_label": "Submit",
            "callback_id": callback_id,
            "notify_on_cancel": True,
            "state": state,
            "elements": dialog_elem
        }
        return self.slackhelper.dialog(dialog=dialog, trigger_id=trigger_id)

    @staticmethod
    def get_menu_start_end_on(location):
        """This method takes a location id, and attempts to return a start date and an end date based on the conditions
        the application expects.

        Conditions:
            If current datetime is over 3PM , skip a day and return next days.
            If day is thursday and not yet 3PM, return only friday
            If current datetime is friday, saturday or sunday, return next week from monday till friday.
            If No conditions matches, return None for both dates.

        """
        start_on = end_on = None

        current_date = current_time_by_zone(location.zone)

        if current_date.strftime('%a') == 'Mon' and int(
                current_date.strftime('%H')) >= 15:
            start_on = current_date + timedelta(days=2)
            end_on = start_on + timedelta(days=2)

        elif current_date.strftime('%a') == 'Tue' and int(
                current_date.strftime('%H')) >= 15:
            start_on = current_date + timedelta(days=2)
            end_on = start_on + timedelta(days=1)

        elif current_date.strftime('%a') == 'Wed' and int(
                current_date.strftime('%H')) >= 15:
            start_on = end_on = current_date + timedelta(days=2)

        elif current_date.strftime('%a') == 'Thu' and int(
                current_date.strftime('%H')) >= 15:
            start_on = end_on = current_date + timedelta(days=4)

        else:

            start_on = current_date + timedelta(days=1)
            if current_date.strftime('%a') == 'Mon':
                end_on = start_on + timedelta(3)
            if current_date.strftime('%a') == 'Tue':
                end_on = start_on + timedelta(2)
            if current_date.strftime('%a') == 'Wed':
                end_on = start_on + timedelta(1)
            if current_date.strftime('%a') == 'Thu':
                end_on = start_on

            else:
                if current_date.strftime('%a') == 'Fri':
                    start_on = current_date + timedelta(days=3)
                    end_on = current_date + timedelta(days=7)

                if current_date.strftime('%a') == 'Sat':
                    start_on = current_date + timedelta(days=2)
                    end_on = current_date + timedelta(days=6)

                if current_date.strftime('%a') == 'Sun':
                    next_day = 1 if int(
                        current_date.strftime('%H')) < 15 else 2
                    start_on = current_date + timedelta(days=next_day)
                    end_on = current_date + timedelta(days=5)

        return tuple((start_on, end_on))
class RoleController(BaseController):
    def __init__(self, request):
        BaseController.__init__(self, request)
        self.role_repo = RoleRepo()
        self.user_role_repo = UserRoleRepo()
        self.permission_repo = PermissionRepo()
        self.andela_service = AndelaService()
        self.redis_set = RedisSet()

    ''' ROLES '''

    def list_roles(self):
        roles = self.role_repo.filter_by(is_deleted=False)
        role_list = [role.serialize() for role in roles.items]
        return self.handle_response('OK',
                                    payload={
                                        'roles': role_list,
                                        'meta': self.pagination_meta(roles)
                                    })

    def get_role(self, role_id):
        role = self.role_repo.get(role_id)
        if role:
            return self.handle_response('OK',
                                        payload={'role': role.serialize()})
        return self.handle_response('Invalid or Missing role_id',
                                    status_code=400)

    def create_role(self):
        name, help_ = self.request_params('name', 'help')
        role1 = self.role_repo.find_first(name=name)
        if not role1:
            role = self.role_repo.new_role(name=name, help_=help_)
            return self.handle_response('OK',
                                        payload={'role': role.serialize()},
                                        status_code=201)
        return self.handle_response('Role with this name already exists',
                                    status_code=400)

    def update_role(self, role_id):
        name, help_ = self.request_params('name', 'help')
        role = self.role_repo.get(role_id)
        if role:
            updates = {}
            if name:
                role1 = self.role_repo.find_first(name=name)
                if role1:
                    return self.handle_response(
                        'Role with this name already exists', status_code=400)
                updates['name'] = name
            if help_:
                updates['help'] = help_

            self.role_repo.update(role, **updates)
            return self.handle_response('OK',
                                        payload={'role': role.serialize()})
        return self.handle_response('Invalid or incorrect role_id provided',
                                    status_code=400)

    def delete_role(self, role_id):
        role = self.role_repo.get(role_id)
        if role:
            updates = {}
            updates['is_deleted'] = True
            self.role_repo.update(role, **updates)
            return self.handle_response('role deleted',
                                        payload={"status": "success"})
        return self.handle_response('Invalid or incorrect role_id provided',
                                    status_code=404)

    ''' USER ROLES '''

    def get_user_roles(self, user_id):
        user_roles = self.user_role_repo.get_unpaginated(user_id=user_id)
        if user_roles:
            role_list = [role.serialize() for role in user_roles]
            return self.handle_response('OK', payload={'user_role': role_list})
        return self.handle_response('There are no roles for this user',
                                    status_code=404)

    def create_user_role(self):
        location = Auth.get_location()
        role_id, email_address = self.request_params('roleId', 'emailAddress')
        user = self.andela_service.get_user_by_email_or_id(email_address)
        if user is None:
            return self.handle_response('This user record does not exist',
                                        status_code=400)
        user_id = user['id']
        user_role = self.user_role_repo.get_unpaginated(role_id=role_id,
                                                        user_id=user_id,
                                                        is_deleted=False)
        if not user_role:
            role = self.role_repo.get(role_id)
            if role:
                user_role = self.user_role_repo.new_user_role(
                    role_id=role_id,
                    user_id=user_id,
                    location_id=location,
                    email=email_address)
                user_role_data = user_role.serialize()
                user_role_data.update({'name': user.get('name')})
                return self.handle_response(
                    'OK',
                    payload={'user_role': user_role_data},
                    status_code=201)
            return self.handle_response('This role does not exist',
                                        status_code=400)
        return self.handle_response('This User has this Role already',
                                    status_code=400)

    def delete_user_role(self, user_role_id):
        user_role = self.user_role_repo.get(user_role_id)
        if user_role:
            updates = {}
            updates['is_deleted'] = True
            self.user_role_repo.update(user_role, **updates)
            return self.handle_response('user_role deleted for user',
                                        payload={"status": "success"})
        return self.handle_response(
            'Invalid or incorrect user_role_id provided', status_code=404)

    def disable_user_role(self):
        user_id, role_id = self.request_params('userId', 'roleId')
        user_role = self.user_role_repo.get_unpaginated(user_id=user_id,
                                                        role_id=role_id)[0]
        if user_role:
            updates = {}
            updates['is_active'] = False
            self.user_role_repo.update(user_role, **updates)
            return self.handle_response('user_role disabled for user',
                                        payload={"status": "success"})
        return self.handle_response(
            'Invalid or incorrect user_role_id provided', status_code=404)

    ''' PERMISSIONS '''

    def get_role_permissions(self, role_id):
        permissions = self.permission_repo.get_unpaginated(
            **{'role_id': role_id})
        perm_list = [permission.serialize() for permission in permissions]
        return self.handle_response('OK',
                                    payload={
                                        'role_id': role_id,
                                        'role_permissions': perm_list
                                    })

    def get_single_permission(self, role_id, permission_id):
        permission = self.permission_repo.filter_by(role_id=role_id,
                                                    id=permission_id)
        permissions = [
            permission.serialize() for permission in permission.items
        ]
        return self.handle_response('OK', payload={'permission': permissions})

    def get_all_permissions(self):
        permissions = self.permission_repo.get_unpaginated()
        perm_list = [permission.serialize() for permission in permissions]
        return self.handle_response('OK', payload={'permissions': perm_list})

    def create_role_permission(self):
        role_id, name, keyword = self.request_params('role_id', 'name',
                                                     'keyword')
        permission = self.permission_repo.get_unpaginated(name=name,
                                                          is_deleted=False,
                                                          role_id=role_id)
        if not permission:
            role = self.role_repo.get(role_id)
            if role:
                permission = self.permission_repo.new_permission(
                    role_id=role_id, name=name, keyword=keyword)
                return self.handle_response(
                    'OK',
                    payload={'permission': permission.serialize()},
                    status_code=201)
            return self.handle_response('This role does not exist',
                                        status_code=400)
        return self.handle_response('This permission already exists',
                                    status_code=400)

    def update_permission(self, permission_id):
        role_id, name, keyword = self.request_params('role_id', 'name',
                                                     'keyword')
        permission = self.permission_repo.get(permission_id)
        if permission:
            updates = {}
            if name:
                permission1 = self.permission_repo.find_first(name=name)
                if permission1:
                    return self.handle_response(
                        'Permission with this name already exists',
                        status_code=400)
                updates['name'] = name
            if role_id:
                updates['role_id'] = role_id
            if keyword:
                updates['keyword'] = keyword

            self.role_repo.update(permission, **updates)
            return self.handle_response(
                'OK', payload={'permission': permission.serialize()})
        return self.handle_response(
            'Invalid or incorrect permission id provided', status_code=400)

    def delete_role_permission(self, permission_id):
        permission = self.permission_repo.get(permission_id)
        if permission:
            updates = {}
            updates['is_deleted'] = True
            self.role_repo.update(permission, **updates)
            return self.handle_response('permission deleted',
                                        payload={"status": "success"})
        return self.handle_response(
            'Invalid or incorrect permission id provided', status_code=404)

    def autocomplete(self):
        params = self.get_params('q')
        rows = []
        if params:
            for value in self.redis_set.get(params[0]):
                if value:
                    rows.append(value)
        return self.handle_response(rows, status_code=200)
    def test_get_user_by_email_or_id_returns_none_if_a_null_key_is_supplied(self):

        user = AndelaService().get_user_by_email_or_id(key=None)

        assert user is None