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)
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)
Example #3
0
def create_resources(json, db):
    try:
        # Resources to return in the response
        created_resources = []
        # Serialized Resources to send to Algolia
        created_resources_algolia = []
        # Resource IDs to delete if Algolia fails to index
        resource_id_cache = []

        # Create each Resource in the database one by one
        for resource in json:
            langs, categ = get_attributes(resource)
            paid_bool = ensure_bool(resource.get('paid'))
            new_resource = Resource(name=resource.get('name'),
                                    url=resource.get('url'),
                                    category=categ,
                                    languages=langs,
                                    paid=paid_bool,
                                    notes=resource.get('notes'))

            try:
                db.session.add(new_resource)
                db.session.commit()
                created_resources_algolia.append(
                    new_resource.serialize_algolia_search)
                resource_id_cache.append(new_resource.id)

            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)

            created_resources.append(new_resource.serialize)

        # Take all the created resources and save them in Algolia with one API call
        try:
            index.save_objects(created_resources_algolia)

        except (AlgoliaUnreachableHostException, AlgoliaException) as e:
            if (environ.get("FLASK_ENV") != 'development'):
                logger.exception(e)

                # Remove created resources from the db to stay in sync with Algolia
                for res_id in resource_id_cache:
                    res = Resource.query.get(res_id)
                    res.languages.clear()
                    db.session.delete(res)
                db.session.commit()

                msg = "Algolia failed to index resources"
                error = {'errors': [{"algolia-failed": {"message": msg}}]}
                return utils.standardize_response(payload=error,
                                                  status_code=500)

        # Success
        return utils.standardize_response(payload=dict(data=created_resources),
                                          datatype="resources")
    except Exception as e:
        logger.exception(e)
        return utils.standardize_response(status_code=500)