def marketer_blogs(marketer_id): # Use marketplace app url to retrieve marketer by id uri = 'marketers/{}'.format(marketer_id) try: response = _send_marketplace_api_request(MARKETPLACE_APP_URL, uri) except APIConnectionError as e: return api_response(str(e), 500) if response.status_code != 200: return api_error('Unable to get marketer.', response.status_code) marketer = json.loads(response.content.decode('utf-8')) # Use marketer url to call /marketplace/blogs url = marketer['url'] try: response = _send_marketplace_api_request(url, 'marketed/blogs', request.args) except APIConnectionError as e: return api_response(str(e), 500) if response.status_code == 200: # Add marketer name to each blog content = json.loads(response.content.decode('utf-8')) for item in content['_items']: item['marketer_name'] = marketer['name'] response_content = json.dumps(content) return api_response(response_content, response.status_code, json_dumps=False) else: return api_error('Unable to get blogs of marketers.', response.status_code)
def get_refresh_token(): # as we don't use session from flask, then we save into user registry, at least for now if not app.auth.authorized([], 'global_preferences', 'POST'): return app.auth.authenticate() secrets = request.files.get('secretsFile', None) if secrets is None: return api_error('Please provide your youtube credentials', 400) secrets.seek(0) file_content = secrets.read() yt_data = json.loads(bytes2string(file_content)) if 'web' not in yt_data: return api_error( 'OAuth project has to be configured as web in google console', 400) # let's save secrets file content in db for future usage global_serv = get_resource_service('global_preferences') global_serv.save_preference(YT_KEY, yt_data) redirect_uri = flask.url_for('video_upload.oauth2callback', _external=True, _scheme=SCHEME) flow = Flow.from_client_config(yt_data, scopes=SCOPES, redirect_uri=redirect_uri) auth_url, _ = flow.authorization_url(prompt='consent', access_type='offline', include_granted_scopes='true') return make_response(auth_url, 200)
def producer_blogs_syndicate(producer_id, blog_id): data = request.get_json(silent=True) or {} consumer_blog_id = data.get('consumer_blog_id') auto_publish = data.get('auto_publish') auto_retrieve = data.get('auto_retrieve', True) start_date = data.get('start_date') if not consumer_blog_id: return api_error('Missing "consumer_blog_id" in form data.', 422) if start_date: try: start_date = str_to_date(start_date) except ValueError: return api_error('start_date is not valid.', 400) if request.method == 'DELETE': return _delete_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id) elif request.method == 'PATCH': return _update_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id, auto_retrieve, start_date) else: return _create_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id, auto_publish, auto_retrieve, start_date)
def _update_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id, auto_retrieve, start_date): producers = get_resource_service('producers') in_service = get_resource_service('syndication_in') in_syndication = in_service.get_syndication(producer_id, blog_id, consumer_blog_id) if not in_syndication: return api_error('Syndication not sent for blog "{}".'.format(blog_id), 409) try: response = producers.syndicate(producer_id, blog_id, consumer_blog_id, start_date, update=True, json_loads=False) except ProducerAPIError as e: return api_response(str(e), 500) else: if response.status_code == 200: syndication_in = in_service.get_syndication(producer_id, blog_id, consumer_blog_id) in_service.update(syndication_in['_id'], { 'auto_retrieve': auto_retrieve, 'start_date': start_date }, syndication_in) del syndication_in['blog_token'] return api_response(syndication_in, 200) elif response.status_code == 404: return api_error('Syndication not sent for blog "{}"'.format(blog_id), 409) else: return api_error('Unable to update blog syndication.', _response_status(response.status_code))
def get_blog_posts(blog_id): blog = Blog(blog_id) kwargs = {} # Get boolean arguments and cast string values to bool. try: kwargs['sticky'] = strtobool(request.args.get('sticky', '0')) kwargs['highlight'] = strtobool(request.args.get('highlight', '0')) except ValueError as e: return api_error(str(e), 403) # Get default ordering. ordering = request.args.get('ordering', Blog.default_ordering) if ordering not in Blog.ordering: return api_error('"{}" is not valid'.format(ordering), 403) kwargs['ordering'] = ordering # Get page & limit. try: kwargs['page'] = int(request.args.get('page', Blog.default_page)) kwargs['limit'] = int(request.args.get('limit', Blog.default_page_limit)) except ValueError as e: return api_error(str(e), 403) # Check page value. if kwargs['page'] < 1: return api_error('"page" value is not valid.', 403) # Check max page limit. if kwargs['limit'] > Blog.max_page_limit: return api_error('"limit" value is not valid.', 403) response_data = blog.posts(wrap=True, **kwargs) result_data = convert_posts(response_data, blog) return api_response(result_data, 200)
def _create_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id, auto_publish, auto_retrieve, start_date=None): producers = get_resource_service('producers') in_service = get_resource_service('syndication_in') in_syndication = in_service.get_syndication(producer_id, blog_id, consumer_blog_id) if in_syndication: return api_error('Syndication already sent for blog "{}".'.format(blog_id), 409) try: response = producers.syndicate(producer_id, blog_id, consumer_blog_id, auto_retrieve, start_date, json_loads=False) except ProducerAPIError as e: return api_response(str(e), 500) else: if response.status_code == 201: syndication = response.json() in_service.post([{ 'blog_id': syndication['consumer_blog_id'], 'blog_token': syndication['token'], 'producer_id': producer_id, 'producer_blog_id': blog_id, 'producer_blog_title': syndication['producer_blog_title'], 'auto_publish': auto_publish, 'auto_retrieve': auto_retrieve, 'start_date': start_date }]) return api_response(response.content, response.status_code, json_dumps=False) elif response.status_code == 409: return api_error('Syndication already sent for blog "{}"'.format(blog_id), 409) else: return api_error('Unable to syndicate producer blog.', _response_status(response.status_code))
def get_advertisements(blog_id, output): """@TODO: add docstrings""" # if the `output` is the `_id` get the data. if output: if isinstance(output, str): output = get_resource_service('outputs').find_one(req=None, _id=output) if not output: return api_error('output not found', 404) else: collection = get_resource_service('collections').find_one( req=None, _id=output.get('collection')) output['collection'] = collection ads = [] if output and output.get('collection', False): ads_ids = output['collection'].get('advertisements', []) ads_ids = list(map(lambda x: x['advertisement_id'], ads_ids)) ads_query = get_resource_service('advertisements').find( {"_id": { "$in": ads_ids }}) ads = list(ads_query) return api_response(ads, 200)
def marketers(): # Use marketplace app url to retrieve marketers try: response = _send_marketplace_api_request(MARKETPLACE_APP_URL, 'marketers', request.args) except APIConnectionError as e: return api_response(str(e), 500) if response.status_code == 200: # Update picture_url - bit of a hack until we settle on a storage solution for the marketplace app url = MARKETPLACE_APP_URL if not url.endswith('/'): url = '{}/'.format(url) response_content = '' try: content = json.loads(response.content.decode('utf-8')) for item in content['_items']: picture_url = item['picture_url'] picture_url = picture_url.replace("/api/", "") item['picture_url'] = url + picture_url response_content = json.dumps(content) except Exception as e: logger.warning('Exception on attempt to parse response from marketplace app: {}'.format(str(e))) return api_response(response_content, response.status_code, json_dumps=False) else: return api_error('Unable to get marketers.', response.status_code)
def _delete_producer_blogs_syndicate(producer_id, blog_id, consumer_blog_id): producers = get_resource_service('producers') in_service = get_resource_service('syndication_in') syndication_in = in_service.get_syndication(producer_id, blog_id, consumer_blog_id) if not syndication_in: logger.warning('Syndication not sent for blog "{}".'.format(blog_id)) return api_response({}, 204) else: try: response = producers.unsyndicate(producer_id, blog_id, consumer_blog_id, json_loads=False) except ProducerAPIError as e: return api_response(str(e), 500) else: if response.status_code == 204: syndication_id = syndication_in['_id'] in_service.delete_action(lookup={'_id': syndication_id}) return api_response(response.content, response.status_code, json_dumps=False) else: return api_error('Unable to unsyndicate producer blog.', _response_status(response.status_code))
def _create_blogs_syndicate(blog_id, consumer_blog_id, auto_retrieve, start_date): # Get the blog to be syndicated - must be enabled for syndication blogs_service = get_resource_service('blogs') blog = blogs_service.find_one(req=None, checkUser=False, _id=blog_id) if blog is None: return api_error( 'No blog available for syndication with given id "{}".'.format( blog_id), 409) if not blog.get('syndication_enabled', False): return api_error('blog is not enabled for syndication', 409) consumer = _get_consumer_from_auth() out_service = get_resource_service('syndication_out') consumer_id = str(consumer['_id']) out_syndication = out_service.get_syndication(consumer_id, blog_id, consumer_blog_id) if out_syndication: return api_error( 'Syndication already sent for blog "{}".'.format(blog_id), 409) if not start_date: # TODO: Find a way to force value to None, as it's ignoring schema settings. # we are forced to set a date in the past, as python-eve is saving by default to datetime.datetime.now(). start_date = datetime.datetime(2010, 1, 1, 0, 0, 0) doc = { 'blog_id': blog_id, 'consumer_id': consumer_id, 'consumer_blog_id': consumer_blog_id, 'start_date': start_date, 'auto_retrieve': auto_retrieve } syndication_id = out_service.post([doc])[0] syndication = out_service.find_one(_id=syndication_id, req=None) return api_response( { 'token': syndication['token'], 'producer_blog_title': blog['title'], 'consumer_blog_id': consumer_blog_id, # we return it anyway for consistency. '_status': 'OK' }, 201)
def producer_blog_posts(producer_id, blog_id): producers = get_resource_service('producers') try: response = producers.get_blog_posts(producer_id, blog_id, json_loads=False) except ProducerAPIError as e: return api_response(str(e), 500) else: if response.status_code == 200: return api_response(response.content, response.status_code, json_dumps=False) else: return api_error('Unable to get producer blog posts.', _response_status(response.status_code))
def blogs(): # Use marketplace app to retrieve blogs of all marketers try: response = _send_marketplace_api_request(MARKETPLACE_APP_URL, 'blogs', request.args) except APIConnectionError as e: return api_response(str(e), 500) if response.status_code == 200: return api_response(response.content, 200, json_dumps=False) else: return api_error('Unable to get blogs from marketplace.', response.status_code)
def get_token(): global_serv = get_resource_service('global_preferences').get_global_prefs() credentials = global_serv.get(YT_CREDENTIALS) if credentials: url = 'https://www.googleapis.com/oauth2/v4/token' try: params = { 'client_id': credentials['client_id'], 'client_secret': credentials['client_secret'], 'refresh_token': credentials['refresh_token'], 'grant_type': 'refresh_token' } response = requests.post(url, data=params) response = json.loads(response.text) return api_response(response['access_token'], 200) except Exception as err: msg = 'Unexpected error getting youtube access token. {0}'.format( err) logger.warning(msg) return api_error(msg, 501) else: return api_error('Youtube credentials not configured yet', 501)
def _update_blogs_syndicate(blog_id, consumer_blog_id, auto_retrieve, start_date): consumer = _get_consumer_from_auth() out_service = get_resource_service('syndication_out') consumer_id = str(consumer['_id']) syndication_out = out_service.get_syndication(consumer_id, blog_id, consumer_blog_id) if not syndication_out: return api_error('Syndication not sent for blog "{}".'.format(blog_id), 404) out_service.update(syndication_out['_id'], { 'start_date': start_date, 'auto_retrieve': auto_retrieve }, syndication_out) return api_response({'_status': 'OK'}, 200)
def marketer_languages(): try: response = _send_marketplace_api_request(MARKETPLACE_APP_URL, 'languages', request.args) except APIConnectionError as e: return api_response(str(e), 500) if response.status_code == 200: content = json.loads(response.content.decode('utf-8')) response = [] for language_code in content: if language_code not in SUPPORTED_LANGUAGES['languages'].keys(): logger.warning('Language code {} not in SUPPORTED_LANGUAGES'.format(language_code)) continue response.append({'code': language_code, 'name': SUPPORTED_LANGUAGES['languages'][language_code]}) return api_response(response, 200) else: return api_error('Unable to get languages from marketplace.', response.status_code)
def get_advertisements(blog_id, output): """ Returns the list of advertisements for a given output id Args: :blog_id: string :output: string of the desired output channel """ if output: if isinstance(output, str): output = get_resource_service('outputs').find_one(req=None, _id=output) if not output: return api_error('output not found', 404) else: collection = get_resource_service('collections').find_one( req=None, _id=output.get('collection')) output['collection'] = collection ads = get_advertisements_list(output) return api_response(ads, 200)
def get_blog_posts(blog_id): blog = Blog(blog_id) kwargs = {} # Get boolean arguments and cast string values to bool. try: kwargs['sticky'] = strtobool(request.args.get('sticky', '0')) kwargs['highlight'] = strtobool(request.args.get('highlight', '0')) except ValueError as e: return api_error(str(e), 403) # Get default ordering. ordering = request.args.get('ordering', Blog.default_ordering) if ordering not in Blog.ordering: return api_error('"{}" is not valid'.format(ordering), 403) kwargs['ordering'] = ordering # Get page & limit. try: kwargs['page'] = int(request.args.get('page', Blog.default_page)) kwargs['limit'] = int( request.args.get('limit', Blog.default_page_limit)) except ValueError as e: return api_error(str(e), 403) # Check page value. if kwargs['page'] < 1: return api_error('"page" value is not valid.', 403) # Check max page limit. if kwargs['limit'] > Blog.max_page_limit: return api_error('"limit" value is not valid.', 403) response_data = blog.posts(wrap=True, **kwargs) fields = [ '_id', '_etag', '_created', '_updated', 'blog', 'lb_highlight', 'sticky', 'deleted', 'post_status', 'published_date', 'unpublished_date' ] # Convert posts for i, post in enumerate(response_data['_items']): doc = {k: post.get(k) for k in fields} # add items in post doc['items'] = [] for g in post.get('groups', []): if g['id'] != 'main': continue for item in g['refs']: doc['items'].append(_get_converted_item(item['item'])) # add authorship publisher = {} publisher['display_name'] = post['publisher']['display_name'] publisher['picture_url'] = post['publisher'].get('picture_url', '') doc['publisher'] = publisher response_data['_items'][i] = doc # Add additional blog metadata to response _meta. response_data['_meta']['last_updated_post'] = blog._blog.get( 'last_updated_post') response_data['_meta']['last_created_post'] = blog._blog.get( 'last_created_post') return api_response(response_data, 200)
def syndication_webhook(): in_service = get_resource_service('syndication_in') blog_token = request.headers.get('Authorization') # assume if there is no blog token that a get request is just checking for a response from the webhook if not blog_token and request.method == 'GET': return api_response({}, 200) in_syndication = in_service.find_one(blog_token=blog_token, req=None) if in_syndication is None: return api_error('Blog is not being syndicated', 406) blog_service = get_resource_service('client_blogs') blog = blog_service.find_one(req=None, _id=in_syndication['blog_id']) if blog is None: return api_error('Blog not found', 404) if blog['blog_status'] != 'open': return api_error( 'Updates should not be sent for a blog which is not open', 409) data = request.get_json() try: items, producer_post = data['items'], data['post'] except KeyError: return api_error('Bad Request', 400) logger.info('Webhook Request - method: {} items: {} post: {}'.format( request.method, items, producer_post)) posts_service = get_resource_service('posts') producer_post_id = get_producer_post_id(in_syndication, producer_post['_id']) post = posts_service.find_one(req=None, producer_post_id=producer_post_id) post_id = None publisher = None if post: post_id = str(post['_id']) publisher = get_post_creator(post) if publisher: return api_error( 'Post "{}" cannot be updated: already updated by "{}"'.format( post_id, publisher), 409) if request.method == 'GET': return api_response({}, 200) elif request.method in ('POST', 'PUT'): new_post = create_syndicated_blog_post(producer_post, items, in_syndication) if request.method == 'POST': # Create post if post: # Post may have been previously deleted if post.get('deleted'): posts_service.update(post_id, new_post, post) return api_response({'post_id': post_id}, 200) else: return api_error('Post already exist', 409) new_post_id = posts_service.post([new_post])[0] return api_response({'post_id': str(new_post_id)}, 201) else: # Update post if not post: return api_error('Post does not exist', 404) posts_service.patch(post_id, new_post) return api_response({'post_id': post_id}, 200) else: # Delete post posts_service.patch(post_id, {'deleted': True}) return api_response({'post_id': post_id}, 200)