def update_resource(id, json, db):
    resource = Resource.query.get(id)

    if not resource:
        return redirect('/404')

    langs, categ = get_attributes(json)
    index_object = {'objectID': id}

    try:
        logger.info(f"Updating resource. Old data: {resource.serialize}")
        if json.get('languages'):
            resource.languages = langs
            index_object['languages'] = resource.serialize['languages']
        if json.get('category'):
            resource.category = categ
            index_object['category'] = categ.name
        if json.get('name'):
            resource.name = json.get('name')
            index_object['name'] = json.get('name')
        if json.get('url'):
            resource.url = json.get('url')
            index_object['url'] = json.get('url')
        if 'paid' in json:
            paid = json.get('paid')

            # Converts "false" and "true" to their bool
            if type(paid) is str and paid.lower() in ["true", "false"]:
                paid = paid.lower().strip() == "true"
            resource.paid = paid
            index_object['paid'] = paid
        if 'notes' in json:
            resource.notes = json.get('notes')
            index_object['notes'] = json.get('notes')

        try:
            index.partial_update_object(index_object)

        except (AlgoliaUnreachableHostException, AlgoliaException) as e:
            if environ.get("FLASK_ENV") != 'development':
                logger.exception(e)
                msg = f"Algolia failed to update index for resource '{resource.name}'"
                logger.warn(msg)
                error = {'errors': [{"algolia-failed": {"message": msg}}]}
                return utils.standardize_response(payload=error,
                                                  status_code=500)

        # Wait to commit the changes until we know that Aloglia was updated
        db.session.commit()

        return utils.standardize_response(payload=dict(
            data=resource.serialize))

    except IntegrityError as e:
        logger.exception(e)
        return utils.standardize_response(status_code=422)

    except Exception as e:
        logger.exception(e)
        return utils.standardize_response(status_code=500)
예제 #2
0
def search_results():
    term = request.args.get('q', '', str)
    page = request.args.get('page', 0, int)
    page_size = request.args.get('page_size', Config.RESOURCE_PAGINATOR.per_page, int)

    # Fetch the filter params from the url, if they were provided.
    free = request.args.get('free')
    category = request.args.get('category')
    languages = request.args.getlist('languages')
    filters = []

    # Filter on free
    if free:
        free = free.lower()
        # algolia filters boolean attributes with either 0 or 1
        if free == 'true':
            filters.append('free=1')
        elif free == 'false':
            filters.append('free=0')

    # Filter on category
    if category:
        # to not let double quotes conflict with algolia filter format
        category = category.replace('"', "'")

        filters.append(
            f'category: "{category}"'
        )

    # Filter on languages
    if languages and '' not in languages:
        for i, _ in enumerate(languages):
            # to not let double quotes conflict with algolia filter format
            languages[i] = 'languages:"{}"'.format(languages[i].replace('"', "'"))

        # joining all possible language values to algolia filter query
        filters.append(f"( {' OR '.join(languages)} )")

    try:
        search_result = index.search(f'{term}', {
            'filters': " AND ".join(filters),
            'page': page,
            'hitsPerPage': page_size
        })

    except (AlgoliaUnreachableHostException, AlgoliaException) as e:
        logger.exception(e)
        msg = "Failed to get resources from Algolia"
        logger.warn(msg)
        error = {'errors': [{"algolia-failed": {"message": msg}}]}
        return utils.standardize_response(payload=error, status_code=500)

    if page >= int(search_result['nbPages']):
        return redirect('/404')

    results = [utils.format_resource_search(result) for result in search_result['hits']]

    details = {
        "details": {
            "page": search_result['page'],
            "number_of_pages": search_result['nbPages'],
            "records_per_page": search_result['hitsPerPage'],
            "total_count": search_result['nbHits'],
        }
    }
    return utils.standardize_response(
        payload=dict(data=results, **details),
        datatype="resources")
def update_resource(id, json, db):
    resource = Resource.query.get(id)
    api_key = g.auth_key.apikey

    if not resource:
        return redirect('/404')

    langs, categ = get_attributes(json)
    index_object = {'objectID': id}

    def get_unique_resource_categories_as_strings():
        resources = Resource.query.all()
        return {resource.category.name for resource in resources}

    def get_unique_resource_languages_as_strings():
        resources = Resource.query.all()
        return {
            language.name
            for resource in resources for language in resource.languages
        }

    try:
        logger.info(f"Updating resource. Old data: "
                    f"{json_module.dumps(resource.serialize(api_key))}")
        if json.get('languages') is not None:
            old_languages = resource.languages[:]
            resource.languages = langs
            index_object['languages'] = resource.serialize(
                api_key)['languages']
            resource_languages = get_unique_resource_languages_as_strings()
            for language in old_languages:
                if language.name not in resource_languages:
                    db.session.delete(language)
        if json.get('category'):
            old_category = resource.category
            resource.category = categ
            index_object['category'] = categ.name
            resource_categories = get_unique_resource_categories_as_strings()
            if old_category.name not in resource_categories:
                db.session.delete(old_category)
        if json.get('name'):
            resource.name = json.get('name')
            index_object['name'] = json.get('name')
        if json.get('url'):
            resource.url = json.get('url')
            index_object['url'] = json.get('url')
        if 'free' in json:
            free = ensure_bool(json.get('free'))
            resource.free = free
            index_object['free'] = free
        if 'notes' in json:
            resource.notes = json.get('notes')
            index_object['notes'] = json.get('notes')

        try:
            index.partial_update_object(index_object)

        except (AlgoliaUnreachableHostException, AlgoliaException) as e:
            if environ.get("FLASK_ENV") != 'development':
                logger.exception(e)
                msg = f"Algolia failed to update index for resource '{resource.name}'"
                logger.warn(msg)
                error = {'errors': [{"algolia-failed": {"message": msg}}]}
                return utils.standardize_response(payload=error,
                                                  status_code=500)

        # Wait to commit the changes until we know that Aloglia was updated
        db.session.commit()

        return utils.standardize_response(
            payload=dict(data=resource.serialize(api_key)),
            datatype="resource")

    except IntegrityError as e:
        logger.exception(e)
        return utils.standardize_response(status_code=422)

    except Exception as e:
        logger.exception(e)
        return utils.standardize_response(status_code=500)