def update_link_info_by_id(link_id): """ Update the info of a link represented by link_id. Attributes that can change: link_title: the title of the article link_description: a description of the link :param link_id: ID of the link to be updated :return: JSON response with the updated link entity """ try: data = request.json link = Link.query.get(link_id) if link: link.link_title = data['link_title'] link.link_description = data['link_description'] db.session.commit() return APIResponseBuilder.success({ "link": link }) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find link with ID of {link_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def update_link_categories_by_id(link_id): """ Update the categories of a link represented by link_id. Attributes that can change: categories: The new list of category ids that the link belongs to :param link_id: ID of the link to be updated :return: JSON response with the updated link entity """ try: data = request.json link = Link.query.get(link_id) if link: for category_id in json.loads(data['categories']): category = Category.query.filter_by(id=category_id).first() if category: link.categories.append(category) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find category with ID of {category_id}" }) link.processing_state = ProcessingState.PROCESSED db.session.commit() return APIResponseBuilder.success({ "link": link }) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find link with ID of {link_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def update_category_by_id(category_id): """ Update a category represented by category_id. Attributes that can change: is_archived: Archive status category_name: category can be renamed :param category_id: ID of the category to be updated :return: JSON response with the updated category entity """ try: data = request.json category = Category.query.get(category_id) if category: if 'category_name' in data: category.category_name = data['category_name'] if 'is_archived' in data: category.is_archived = data['is_archived'] db.session.commit() return APIResponseBuilder.success({"category": category}) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find category with ID of {category_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def create_link(): """ Create a new link for a given user :return: JSON of new link if successful, error response if not """ # TODO: validate user ID try: data = request.json # See if this specific user has a link entity with this specific url # This should prevent a link from being added twice but also run it through regardless link = Link.query.filter_by(user_id=data['user_id'], url=data['url']).first() if not link: link = Link( user_id=data['user_id'], url=data['url'], ) db.session.add(link) db.session.commit() process_link(link) return APIResponseBuilder.success({ "link": link }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def categorize_link(link_id): """ Categorizes a link by link_id :param link_id: ID of the link to be marked as unread """ # TODO: validate user ID try: link = Link.query.get(link_id) if link: link.processing_state = ProcessingState.UNPROCESSED link.categories = [] db.session.add(link) db.session.commit() process_link(link) return APIResponseBuilder.success({ "link": link }) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find link with ID of {link_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def export_data_by_user_id(user_id): try: export_data = jsonify(DataPortabilityService.export_user_data(user_id)) export_data.headers[ 'Content-Disposition'] = f"attachment;filename={user_id}_export.json" return export_data except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_all_categories(): """ Returns a JSON response of all categories in the system Does not include associated keywords """ try: categories = Category.query.all() return APIResponseBuilder.success({"categories": categories}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def delete_keyword_by_id(keyword_id): try: keyword = Keyword.query.filter_by(id=keyword_id).delete() db.session.commit() if keyword: return APIResponseBuilder.success({"deleted": True}) return APIResponseBuilder.failure( {"invalid_id": f"Unable to delete keyword with ID {keyword_id}"}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_relevant_keywords_for_link(link_id): try: keywords = RelevantKeyword.query.filter_by(link_id=link_id).order_by( desc(RelevantKeyword.relevance)).all() if keywords: return APIResponseBuilder.success({"keywords": keywords}) else: return APIResponseBuilder.failure( {"invalid_id": f"Unable to find link with ID of {link_id}"}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def create_keyword(): try: # TODO: verify category belongs to passed user ID data = request.json keyword = Keyword(keyword=data['keyword'], is_excluded=data["is_excluded"], category_id=data['category_id']) db.session.add(keyword) db.session.commit() return APIResponseBuilder.success({"keyword": keyword}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_all_links_by_category(category_id): """ Returns a JSON response of all links by category Does not include associated categories :param :category_id """ # TODO: validate category ID try: category = Category.query.get(category_id) return APIResponseBuilder.success({"links": category.links}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def update_keyword_by_id(keyword_id): try: data_dict = request.json keyword = Keyword.query.get(keyword_id) if keyword: keyword.keyword = data_dict['keyword'] keyword.is_excluded = data_dict['is_excluded'] db.session.commit() return APIResponseBuilder.success({"keyword": keyword}) return APIResponseBuilder.failure( {"invalid_id": f"Unable to find keyword with id {keyword_id}"}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def create_new_user(): """ Creates a new user :return: JSON representing the new User entity """ try: data = request.json user = User(email=data['email'], uuid=data['uuid']) db.session.add(user) db.session.commit() return APIResponseBuilder.success({"user": user}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_all_links_by_user(user_id): """ Returns a JSON response of all links by user :param :user_id """ # TODO: validate user ID try: links = Link.query.filter_by(user_id=user_id).all() return APIResponseBuilder.success({ "links": links, }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def delete_user_by_id(user_id): """ Delete a user with firebase id user_id :param user_id: :return: JSON boolean representing whether the user was successfully create """ try: user = User.query.filter_by(uuid=user_id).delete() if user: return APIResponseBuilder.success({"deleted": True}) return APIResponseBuilder.failure( {"invalid_id": f"Cannot find user with id {user_id}"}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_user_by_id(user_id): """ Returns information for a single user by ID :param user_id: UUID from firebase :return: JSON response representing the user """ try: user = User.query.filter_by(uuid=user_id).first() if user: return APIResponseBuilder.success({"user": user}) return APIResponseBuilder.failure( {"invalid_id": f"Unable to find user with uuid {user_id}"}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def update_forwarding_settings(forwarding_settings_id): """ Update a forwarding_settings represented by forwarding_settings_id. Attributes that can change: api_key: the api key for authorization to third party integration default_forwarding_url: the forwarding url to use for all links :param forwarding_settings_id: ID of the forwarding_settings to be updated :return: JSON response with the updated forwarding_settings entity """ try: data = request.json forwarding_settings = ForwardingSettings.query.get( forwarding_settings_id) if forwarding_settings: forwarding_settings.api_key = data['api_key'] forwarding_settings.default_forwarding_url = data[ 'default_forwarding_url'] new_fs = ForwardingSettings( user_id=forwarding_settings.user_id, forwarding_app=forwarding_settings.forwarding_app, api_key=data["api_key"], default_forwarding_url=data['default_forwarding_url'], ) ForwardingSettings.query.filter_by( id=forwarding_settings_id).delete() db.session.add(new_fs) # update the default integration user = User.query.filter_by( uuid=forwarding_settings.user_id).first() user.default_integration = forwarding_settings.forwarding_app db.session.commit() return APIResponseBuilder.success({"forwarding_settings": new_fs}) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find forwarding_settings with ID of {forwarding_settings_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def create_new_forwarding_settings(): """ Create a new forwarding_settings :return: JSON of new forwarding_settings if successful, error response if not """ try: data = request.json valid_apps = set(item.value for item in ThirdPartyIntegration) forwarding_app = int(data['forwarding_app']) print(forwarding_app) print(valid_apps) print(forwarding_app in valid_apps) print(forwarding_app == ThirdPartyIntegration.DEFAULT.value) # not a valid app or the default app if (forwarding_app not in valid_apps ) or forwarding_app == ThirdPartyIntegration.DEFAULT.value: return APIResponseBuilder.failure({ "invalid_id": f"Not a valid forwarding app for value of {forwarding_app}" }) # make sure only one forwarding setting per third party integration exists for the user #ForwardingSettings.query. forwarding_settings = ForwardingSettings( user_id=data["user_id"], forwarding_app=forwarding_app, api_key=data["api_key"], default_forwarding_url=data['default_forwarding_url'], ) db.session.add(forwarding_settings) # update the default integration user = User.query.filter_by(uuid=forwarding_settings.user_id).first() user.default_integration = forwarding_settings.forwarding_app db.session.commit() return APIResponseBuilder.success( {"forwarding_settings": forwarding_settings}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def delete_forwarding_settings(forwarding_settings_id): """ Delete a forwarding_settings with id forwarding_settings_id :param forwarding_settings_id: :return: JSON boolean representing whether the user was successfully create """ try: forwarding_settings = ForwardingSettings.query.filter_by( id=forwarding_settings_id).delete() db.session.commit() if forwarding_settings: return APIResponseBuilder.success({"deleted": True}) return APIResponseBuilder.failure({ "invalid_id": f"Unable to delete forwarding_settings with ID {forwarding_settings_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def delete_link_by_id(link_id): """ Delete a link with id link_id :param link_id: :return: JSON boolean representing whether the user was successfully create """ try: link = Link.query.filter_by(id=link_id).delete() db.session.commit() if link: return APIResponseBuilder.success({ "deleted": True }) return APIResponseBuilder.failure({ "invalid_id": f"Unable to delete link with ID {link_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def create_new_category(): """ Create a new category with the passed information :return: JSON of new category if successful, error response if not """ try: data = request.json # We'll never want a category to be archived by default so we can ignore the is_archived param # and just go with the default category = Category( user_id=data["user_id"], category_name=data["category_name"], ) db.session.add(category) db.session.commit() return APIResponseBuilder.success({"category": category}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_link_by_id(link_id): """ Returns a JSON response of a single link with id of link_id Includes all categories associated with that link :param link_id: ID of the specific link to be found :return: JSON response """ try: link = Link.query.get(link_id) if link: return APIResponseBuilder.success({ "link": link }) return APIResponseBuilder.failure({ "invalid_id": f"No link with id {link_id} found" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def import_data_for_user(): data = request.json try: for category in data["categories"]: # Create new category cat = Category(user_id=data["uuid"], category_name=category["name"]) db.session.add(cat) db.session.commit() # add keywords for keyword in category["keywords"]: k = Keyword(keyword=keyword["keyword"], is_excluded=keyword["is_excluded"], category_id=cat.id) db.session.add(k) db.session.commit() return APIResponseBuilder.success({"success": True}) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def get_category_by_id(category_id): """ Returns a JSON response of a single category with id of category_id Includes all single keywords associated with that category :param category_id: ID of the specific category to be found :return: JSON response """ try: category = Category.query.get(category_id) # Return category if successful, return fail if category not found matching that id if category: return APIResponseBuilder.success({"category": category}) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find category with id {category_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def recategorize_link(link_id): try: data = request.json link = Link.query.get(link_id) if link: link.categories = [] # Remove all current relations to_add = [category for category in data if category["is_categorized_as"] is True] for category_to_add in to_add: category = Category.query.get(category_to_add["id"]) link.categories.append(category) db.session.commit() else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find link with ID of {link_id}" }) return APIResponseBuilder.success({ "link": link }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: print(e) return APIResponseBuilder.error(f"Error encountered: {e}")
def delete_category_by_id(category_id): """ Returns a JSON response of a single category with id of category_id Includes all single keywords associated with that category :param category_id: ID of the specific category to be found :return: JSON response """ try: category = Category.query.get(category_id) if category: db.session.delete(category) db.session.commit() return APIResponseBuilder.success( {"category": "deleted successfully"}) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find category with id {category_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def update_category_forwarding(category_id): """ Update the forwarding settings for a category represented by category_id. Attributes that can change: forwarding_app: The third party integration forwarding_url: The url used to forward links to :param category_id: ID of the category to be updated :return: JSON response with the updated category entity """ try: data = request.json valid_apps = set(item.value for item in ThirdPartyIntegration) forwarding_app = data['forwarding_app'] if forwarding_app not in valid_apps: return APIResponseBuilder.failure({ "invalid_id": f"Not a valid forwarding app for value of {forwarding_app}" }) category = Category.query.get(category_id) if category: category.forwarding_app = forwarding_app category.forwarding_url = data['forwarding_url'] db.session.commit() return APIResponseBuilder.success({"category": category}) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find category with ID of {category_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")
def mark_link_as_unread(link_id): """ Marks a specific link as unread identified by link_id :param link_id: ID of the link to be marked as unread :return: JSON object of updated Link """ # TODO: validate user ID from post param - for now we'll assume it's the correct user try: link = Link.query.get(link_id) if link: link.is_marked_as_read = False db.session.commit() return APIResponseBuilder.success({ "link": link, }) else: return APIResponseBuilder.failure({ "invalid_id": f"Unable to find link with ID of {link_id}" }) except SQLAlchemyError as e: return APIResponseBuilder.error(f"Issue running query: {e}") except Exception as e: return APIResponseBuilder.error(f"Error encountered: {e}")