Пример #1
0
def get_profile(id_user, user_input):
    """
    Retrieve the a user profile, in this case the profile only contains
    maximum calories permitted per day
    :param id_user: user id to retrieve the profile
    :type: int
    :param user_input: user id to which the profile belongs
    :type: User Model
    :return: user profile. HTTP status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection(
        {ADMIN_ROLE, MANAGER_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        profile = Profile.query.filter(Profile.user_id == id_user).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            response = marshal(profile, PROFILE_MODEL)
            code = CODE_OK
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #2
0
def get_meals(id_user, request, user_input):
    """
    Retrieve the list of meals corresponding to an user
    :param id_user: user id to retrieve list of meals
    :type: int
    :param request: context information about the current request
    :type: LocalProxy
    :param user_input: User who made the request
    :type: User Model
    :return: list of meals corresponding to the user id
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection({ADMIN_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            args = PAGE_ARGUMENTS_MEALS.parse_args(request)
            page = args.get('page', 1)
            per_page = args.get('per_page', 10)
            sort = args.get('sort', 'id')
            if sort == 'id':
                sort = "meal_" + sort
            if sort not in FIELDS_MEALS:
                response = dict(RESPONSES_CATALOG['error_sort'])
                response['error'] = response['error'].format(sort)
                code = CODE_NOT_ACCEPTABLE
                return response, code
            search = args.get('search')
            filter_query = ""
            model = 'Meal'
            try:
                if search:
                    search = search.lower()
                    query_string = process_query(model, search)
                    filter_query = ".filter({})".format(query_string)
                string_filter = model + ".query.order_by(Meal." + sort + \
                                ").filter(" + model + \
                                ".user_id == user.id)" + filter_query + \
                                ".paginate(page, per_page, error_out=False)"
                entries_page = eval(string_filter)
                response = marshal(entries_page, PAGE_OF_MEALS)
                code = CODE_OK
            except ParseException:
                response = RESPONSES_CATALOG['error_parse_query_values']
                code = CODE_NOT_ACCEPTABLE
            except AttributeError as error:
                response = dict(RESPONSES_CATALOG['error_parse_query_fields'])
                response['error'] = response['error'].format(field_error=error)
                code = CODE_NOT_ACCEPTABLE
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #3
0
def get_users(request, user):
    """
    Get the list of users registered on the server. The requester must
    have permission to get list of users. Only admins and managers can request
    an user from database.
    :param request: Information about the request done
    :type: LocalProxy
    :param user: User who made the request
    :type: User Model
    :return: List of users in json format. HTTP status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user)
    if roles.intersection({ADMIN_ROLE, MANAGER_ROLE}):
        if roles.intersection({ADMIN_ROLE}):
            model_serializer = PAGE_OF_USERS_ADMIN
        else:
            model_serializer = PAGE_OF_USERS_MANAGER
        args = PAGE_ARGUMENTS_USERS.parse_args(request)
        page = args.get('page', 1)
        per_page = args.get('per_page', 10)
        sort = args.get('sort', 'id')
        if sort not in FIELDS_USERS:
            response = {'error': 'Non acceptable ordering: ' + sort}
            code = CODE_NOT_ACCEPTABLE
            return response, code
        search = args.get('search')
        filter_query = ""
        model = 'User'
        try:
            if search:
                search = search.lower()
                query_string = process_query(model, search)
                filter_query = ".filter({})".format(query_string)
            string_filter = model + ".query.order_by(" + model + "." + sort + \
                            ")" + filter_query + ".paginate(page, per_page, " \
                                                 "error_out=False)"
            users_page = eval(string_filter)
            response = marshal(users_page, model_serializer)
            code = CODE_OK
        except ParseException:
            response = RESPONSES_CATALOG['error_parse_query_values']
            code = CODE_NOT_ACCEPTABLE
        except AttributeError as error:
            response = dict(RESPONSES_CATALOG['error_parse_query_fields'])
            response['error'] = response['error'].format(field_error=error)
            code = CODE_NOT_ACCEPTABLE
        except Exception as error:
            response = dict(RESPONSES_CATALOG['internal_error_server'])
            response['error'] = response['error'] + str(error)
            code = CODE_INTERNAL_ERROR
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #4
0
def create_meal(id_user, data, user_input):
    """
    Create and store a new meal in database.
    :param id_user: User's id who the new meal will be assigned
    :type: int
    :param data: Information about the new meal to create
    :type: json
    :param user_input: User who made the request
    :type: User Model
    :return: The new meal created is success, error message otherwise. HTTP
    status
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection({ADMIN_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            try:
                date_str = data.get('date')
                date = datetime.strptime(date_str, '%Y-%m-%d')
                time_in_datetime = datetime.strptime(data.get('time'),
                                                     '%H:%M:%S')
                time = datetime.time(time_in_datetime)
                description = data.get('description')
                calories = data.get('calories')
                if calories is None:
                    calories = get_calories_meal(description)
                profile = \
                    Profile.query.filter(Profile.user_id == id_user).first()
                maximum_calories_user = profile.maximum_calories
                less_calories = compute_calories_day(id_user, date_str, time,
                                                     calories,
                                                     maximum_calories_user)
                new_meal = Meal(date, time, description, calories, user)
                new_meal.calories_less_expected = less_calories
                DB.session.add(new_meal)
                DB.session.commit()
                response = marshal(new_meal, MEAL_API_MODEL)
                code = CODE_CREATED
            except (SyntaxError, ValueError) as error:
                response = {
                    'error': "Error parsing input value: " + str(error)
                }
                code = CODE_NOT_ACCEPTABLE
    else:
        response = dict(RESPONSES_CATALOG['no_permission_update_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #5
0
def patch_user(id_user, data, user_input):
    """
    Update information of an user on database. Not all fields are required in
    this case, this function can be used to unblock users accounts for instance
    :param id_user: user id corresponding to user to update information
    :type: int
    :param data: new information to store in the user
    :type: json
    :param user_input: User who made the request
    :type: User Model
    :return: User updated if success, error message otherwise. HTTP status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if roles.intersection({ADMIN_ROLE, MANAGER_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            if data.get('username') is not None:
                user.username = data.get('username')
            if data.get('first_name') is not None:
                user.first_name = data.get('first_name')
            if data.get('last_name') is not None:
                user.last_name = data.get('last_name')
            if data.get('confirmed') is not None:
                user.confirmed = bool(data.get('confirmed'))
            if data.get('confirmed_on') is not None:
                user.confirmed_on = datetime.strptime(data.get('confirmed_on'),
                                                      '%Y-%m-%d')
            if data.get('attempts_login') is not None:
                user.attempts_login = int(data.get('attempts_login'))
            if data.get('blocked') is not None:
                user.blocked = bool(data.get('blocked'))
            if data.get('roles') is not None:
                new_role_user = data.get('roles')
                user.roles = []
                for role in new_role_user:
                    name_role = role["name"]
                    role_object = Role.query.filter(
                        Role.name == name_role).first()
                    user.roles.append(role_object)
            DB.session.add(user)
            DB.session.commit()
            response = marshal(user, USER_DESCRIPTION)
            code = CODE_OK
    else:
        response = dict(RESPONSES_CATALOG['no_permission_update_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #6
0
def create_invitation(data, user_input):
    """
    Create a new invitation in the server and store in database. Send the
    email of acceptation to future user
    :param data: Information about the new invitation (email)
    :type: json
    :param user_input: User who made the request
    :type: User Model
    :return: A message about the invitation was successfully created, or an
    error message if not success. HTTP status code
    :type: tuple(json,int)
    """
    roles = get_roles_user(user_input)
    if roles.intersection({ADMIN_ROLE}):
        email = data.get('email')
        if EMAIL_REGEX.match(email):
            user_in_db = User.query.filter(User.username == email).first()
            invitation_in_db = Invitation.query.filter(
                Invitation.email == email).first()
            if user_in_db:
                response = RESPONSES_CATALOG['existing_user']
                code = CODE_CONFLICT
            elif invitation_in_db:
                response = RESPONSES_CATALOG['existing_invitation']
                code = CODE_CONFLICT
            else:
                invitation = Invitation(email)
                DB.session.add(invitation)
                DB.session.commit()
                token_account_verification = \
                    generate_confirmation_token(invitation.email)
                acceptation_url = \
                    url_for('api.v1/users/invitations_invitation_confirmation',
                            id_invitation=invitation.id,
                            token=token_account_verification, _external=True)

                html = render_template('invitation.html',
                                       acceptation_url=acceptation_url)
                subject = "Mangiato: keeping track of your meals and calories"
                send_email(invitation.email, subject, html)
                response = marshal(invitation, INVITATION_MODEL)
                code = CODE_CREATED
        else:
            response = RESPONSES_CATALOG['no_format_email_invitation']
            code = CODE_NOT_ACCEPTABLE
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #7
0
def patch_invitation(id_invitation, data, user_input):
    """
    Update information of a invitation on database. In this case only the
    status of invitation can be change. Updating an email may cause conflicts
    in the server
    :param id_invitation: invitation id to update
    :type: int
    :param data: new status of invitation
    :type: json
    :param user_input: User who made the request
    :type: User Model
    :return: Invitation updated if success, error message otherwise. HTTP
    status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if roles.intersection({ADMIN_ROLE}):
        invitation = Invitation.query.filter(
            Invitation.id == id_invitation).first()
        email = data.get('email')
        status = data.get('status')
        if not invitation:
            response = dict(RESPONSES_CATALOG['no_invitation_server'])
            response['error'] = \
                response['error'].format(id_invitation=id_invitation)
            code = CODE_NOT_FOUND
        elif email is not None and email != invitation.email:
            response = RESPONSES_CATALOG['no_change_email_invitation']
            code = CODE_FORBIDDEN
        elif status in STATUS_INVITATION:
            invitation.status = data.get('status')
            DB.session.add(invitation)
            DB.session.commit()
            response = marshal(invitation, INVITATION_MODEL)
            code = CODE_OK
        else:
            response = {
                'error':
                'Possible values for status: pending, '
                'accepted. No available: ' + status
            }
            code = CODE_NOT_ACCEPTABLE
    else:
        response = dict(RESPONSES_CATALOG['no_permission_update_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #8
0
def delete_meal(id_user, id_meal, user_input):
    """
    Delete a meal from database server. The requester must have
    permission to perform deletion. The meal must to belong it or must have
    admin permission. The deletion of a meal also trigger the recalculation of
    flag of maximum calories reached for that day
    :param id_user: user id which the meal belong
    :type: int
    :param id_meal: meal id to delete
    :type: int
    :param user_input: User who made the request
    :type: User Model
    :return: An message of deletion confirmation. error message otherwise.
    HTTP status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection({ADMIN_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        meal = Meal.query.filter(Meal.meal_id == id_meal).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        elif not meal:
            response = dict(RESPONSES_CATALOG['no_meal_server'])
            response['error'] = response['error'].format(id_meal=id_meal)
            code = CODE_NOT_FOUND
        elif meal.user_id != id_user:
            response = dict(RESPONSES_CATALOG['no_meal_user'])
            response['error'] = response['error'].format(id_meal=id_meal,
                                                         id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            date_meal = meal.date
            time_meal = meal.time
            DB.session.delete(meal)
            DB.session.commit()
            _recalculate_calories_less_expected(id_user, date_meal, time_meal)
            response = RESPONSES_CATALOG['meal_deleted']
            code = CODE_NO_CONTENT
    else:
        response = dict(RESPONSES_CATALOG['no_permission_delete_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #9
0
def get_invitations(request, user_input):
    """
    Retrieve the list of invitations made in the API by the administrators
    :param request: context information about the current request
    :type: LocalProxy
    :param user_input: User who made the request
    :type: User Model
    :return: list of invitations made by administrators on the Mangiato API
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if roles.intersection({ADMIN_ROLE}):
        args = PAGE_ARGUMENTS_INV.parse_args(request)
        page = args.get('page', 1)
        per_page = args.get('per_page', 10)
        sort = args.get('sort', 'id')
        if sort not in FIELDS_INVITATION:
            response = {'error': 'Non acceptable ordering: ' + sort}
            code = CODE_NOT_ACCEPTABLE
            return response, code
        search = args.get('search')
        filter_query = ""
        model = "Invitation"
        if search:
            query_string = process_query(model, search)
            filter_query = ".filter({})".format(query_string)
        string_filter = model + ".query.order_by(" + model + "." + sort + \
                        ")" + filter_query + ".paginate(page, per_page, " \
                                             "error_out=False)"
        invitation_pages = eval(string_filter)
        response = marshal(invitation_pages, PAGE_OF_INVITATIONS)
        code = CODE_OK
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #10
0
def get_meal(id_user, id_meal, user_input):
    """
    Retrieve a specific meal corresponding to an user with id <id_user>
    :param id_user: user id to retrieve the meal requested
    :type: int
    :param id_meal: meal id to get from server
    :type: int
    :param user_input: User who made the request
    :type: User Model
    :return: list of meals corresponding to the user id
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection({ADMIN_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        meal = Meal.query.filter(Meal.meal_id == id_meal).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        elif not meal:
            response = dict(RESPONSES_CATALOG['no_meal_server'])
            response['error'] = response['error'].format(id_meal=id_meal)
            code = CODE_NOT_FOUND
        elif meal.user.id != id_user:
            response = dict(RESPONSES_CATALOG['no_meal_user'])
            response['error'] = response['error'].format(id_meal=id_meal,
                                                         id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            response = marshal(meal, MEAL_API_MODEL)
            code = CODE_OK
    else:
        response = dict(RESPONSES_CATALOG['no_permission_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #11
0
def patch_meal(id_user, id_meal, data, user_input):
    """
    Update some or all information of a meal on database. In this case not all
    fields of meal are required.
    Having in account a modification of a meal impacts in de flag if the user
    reach maximum calories permitted per day, if the meal is modified or the
    date or time, this trigger the re-calculation of the flag for all meals in
    the day that the change impacts
    :param id_user: user id corresponding to user which the meal belongs
    :type: int
    :param id_meal: meal id to update
    :type: int
    :param data: new information to store of the meal
    :type: json
    :param user_input: User who made the request
    :type: User Model
    :return: Meal updated if success, error message otherwise. HTTP status code
    :type: tuple(json, int)
    """
    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection({ADMIN_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        meal = Meal.query.filter(Meal.meal_id == id_meal).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        elif not meal:
            response = dict(RESPONSES_CATALOG['no_meal_server'])
            response['error'] = response['error'].format(id_meal=id_meal)
            code = CODE_NOT_FOUND
        elif meal.user_id != id_user:
            response = dict(RESPONSES_CATALOG['no_meal_user'])
            response['error'] = response['error'].format(id_meal=id_meal,
                                                         id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            try:
                old_date_meal = meal.date
                old_time_entry = meal.time
                old_description_meal = meal.description
                if data.get('date') is not None:
                    meal.date = datetime.strptime(data.get('date'), '%Y-%m-%d')
                if data.get('time') is not None:
                    time_in_datetime = datetime.strptime(
                        data.get('time'), '%H:%M:%S')
                    meal.time = datetime.time(time_in_datetime)
                if data.get('description') is not None:
                    meal.description = data.get('description')
                if data.get('calories') is not None:
                    meal.calories = data.get('calories')
                if old_description_meal != meal.description or \
                        meal.description is None:
                    meal.calories = get_calories_meal(meal.description)
                DB.session.add(meal)
                DB.session.commit()
                _recalculate_calories_less_expected(id_user, meal.date,
                                                    meal.time)
                if old_date_meal != meal.date:
                    _recalculate_calories_less_expected(
                        id_user, old_date_meal, old_time_entry)
                response = marshal(meal, MEAL_API_MODEL)
                code = CODE_OK
            except (SyntaxError, ValueError) as error:
                response = {
                    'error': "Error parsing input value: " + str(error)
                }
                code = CODE_NOT_ACCEPTABLE
    else:
        response = dict(RESPONSES_CATALOG['no_permission_update_resource'])
        response['error'] = response['error'].format(id_user=user_input.id)
        code = CODE_FORBIDDEN
    return response, code
Пример #12
0
def update_avatar(id_user, files, user_input):
    """
    Update of an user image profile. Get file path from files and upload the
    new image to replace the last one stored in the server
    :param id_user: user id corresponding to user to update image profile
    :type: int
    :param files: path to upload the new image from the client
    :type: str
    :param user_input: User who made the request
    :type: User Model
    :return: New Image updated if success, error message otherwise. HTTP status
    code
    :type: tuple(image, int)
    """

    roles = get_roles_user(user_input)
    if id_user == user_input.id or roles.intersection(
        {ADMIN_ROLE, MANAGER_ROLE}):
        user = User.query.filter(User.id == id_user).first()
        profile = Profile.query.filter(Profile.user_id == id_user).first()
        if not user:
            response = dict(RESPONSES_CATALOG['no_user_server'])
            response['error'] = response['error'].format(id_user=id_user)
            code = CODE_NOT_FOUND
        else:
            if 'file' not in files:
                return RESPONSES_CATALOG['no_file_found'], CODE_BAD_REQUEST
            file = files['file']
            if file and allowed_file(file.filename):
                try:
                    file.save(
                        os.path.join(APP.config['AVATARS_SAVE_PATH'],
                                     profile.name_picture_l))
                except Exception:
                    response = RESPONSES_CATALOG['internal_error']
                    code = CODE_INTERNAL_ERROR
                    return response, code
            pic = Image.open(
                os.path.join(APP.config['AVATARS_SAVE_PATH'],
                             profile.name_picture_l))
            pic_small = pic.resize((SMALL_SIZE_AVATAR, SMALL_SIZE_AVATAR),
                                   Image.ANTIALIAS)
            pic_small.save(
                os.path.join(APP.config['AVATARS_SAVE_PATH'],
                             profile.name_picture_s))
            pic_medium = pic.resize((MEDIUM_SIZE_AVATAR, MEDIUM_SIZE_AVATAR),
                                    Image.ANTIALIAS)
            pic_medium.save(
                os.path.join(APP.config['AVATARS_SAVE_PATH'],
                             profile.name_picture_m))
            pic_large = pic.resize((LARGE_SIZE_AVATAR, LARGE_SIZE_AVATAR),
                                   Image.ANTIALIAS)
            pic_large.save(
                os.path.join(APP.config['AVATARS_SAVE_PATH'],
                             profile.name_picture_l))
            response = RESPONSES_CATALOG['profile_image_changed']
            code = CODE_OK
    else:
        response = dict(RESPONSES_CATALOG['no_permission_other_user'])
        response['error'] = response['error'].format(id_user=user_input.id,
                                                     id_user_2=id_user)
        code = CODE_FORBIDDEN
    return response, code