def _feed_entry_read_post(request, uuid_): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) read_feed_entry_user_mapping = None with transaction.atomic(): feed_entry = None try: feed_entry = models.FeedEntry.objects.get(uuid=uuid_) except models.FeedEntry.DoesNotExist: return HttpResponseNotFound('feed entry not found') try: read_feed_entry_user_mapping = models.ReadFeedEntryUserMapping.objects.get( feed_entry=feed_entry, user=request.user) except models.ReadFeedEntryUserMapping.DoesNotExist: read_feed_entry_user_mapping = models.ReadFeedEntryUserMapping.objects.create( feed_entry=feed_entry, user=request.user) ret_obj = context.format_datetime(read_feed_entry_user_mapping.read_at) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _user_category_get(request, uuid_): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) field_maps = None try: fields = query_utils.get_fields__query_dict(request.GET) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) user_category = None try: user_category = models.UserCategory.objects.get(uuid=uuid_, user=request.user) except models.UserCategory.DoesNotExist: return HttpResponseNotFound('user category not found') ret_obj = query_utils.generate_return_object(field_maps, user_category, context) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _feed_get(request): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) url = request.GET.get('url') if not url: return HttpResponseBadRequest('\'url\' missing') url = url_normalize(url) field_maps = None try: fields = query_utils.get_fields__query_dict(request.GET) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) feed = None try: feed = models.Feed.annotate_subscription_data( models.Feed.objects.all(), request.user).get(feed_url=url) except models.Feed.DoesNotExist: try: feed = _save_feed(url) except QueryException as e: return HttpResponse(e.message, status=e.httpcode) ret_obj = query_utils.generate_return_object(field_maps, feed, context) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _feed_subscription_progress_get(request, uuid_): feed_subscription_progress_entry = None try: feed_subscription_progress_entry = models.FeedSubscriptionProgressEntry.objects.get( uuid=uuid_, user=request.user) except models.FeedSubscriptionProgressEntry.DoesNotExist: return HttpResponseNotFound('progress not found') progress_statuses = list( models.FeedSubscriptionProgressEntryDescriptor.objects.filter( feed_subscription_progress_entry=feed_subscription_progress_entry). values_list('is_finished', flat=True)) total_count = len(progress_statuses) finished_count = sum(1 for is_finished in progress_statuses if is_finished) ret_obj = { 'totalCount': total_count, 'finishedCount': finished_count, } if feed_subscription_progress_entry.status == models.FeedSubscriptionProgressEntry.NOT_STARTED: ret_obj['state'] = 'notstarted' elif feed_subscription_progress_entry.status == models.FeedSubscriptionProgressEntry.STARTED: ret_obj['state'] = 'started' else: ret_obj['state'] = 'finished' content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _facebook_login_session_post(request): if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest('JSON body must be object') # pragma: no cover if 'token' not in json_: return HttpResponseBadRequest('\'token\' missing') if type(json_['token']) is not str: return HttpResponseBadRequest('\'token\' must be string') fb_id = None fb_email = None try: fb_id, fb_email = facebook.get_id_and_email(json_['token']) except ValueError: # pragma: no cover return HttpResponseBadRequest('bad Facebook token') facebook_login = None try: facebook_login = models.FacebookLogin.objects.get( profile_id=fb_id) except models.FacebookLogin.DoesNotExist: ret_obj = { 'token': json_['token'], 'email': fb_email, } content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type, status=422) session = models.Session.objects.create( user=facebook_login.user, expires_at=datetime.datetime.utcnow() + _SESSION_EXPIRY_INTERVAL, ) content, content_type = query_utils.serialize_content(str(session.uuid)) return HttpResponse(content, content_type)
def test_serialize_content(self): content, content_type = query_utils.serialize_content({ 'test1': 1, 'test2': True }) self.assertEqual(content_type, 'application/json') self.assertEqual(content, '{"test1":1,"test2":true}')
def _my_login_session_post(request): if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest('JSON body must be object') # pragma: no cover if 'email' not in json_: return HttpResponseBadRequest('\'email\' missing') if type(json_['email']) is not str: return HttpResponseBadRequest('\'email\' must be string') if 'password' not in json_: return HttpResponseBadRequest('\'password\' missing') if type(json_['password']) is not str: return HttpResponseBadRequest('\'password\' must be string') my_login = None try: my_login = models.MyLogin.objects.get( user__email__iexact=json_['email']) except models.MyLogin.DoesNotExist: return HttpResponseForbidden() try: password_hasher().verify(my_login.pw_hash, json_['password']) except argon2.exceptions.VerifyMismatchError: return HttpResponseForbidden() session = models.Session.objects.create( user=my_login.user, expires_at=datetime.datetime.utcnow() + _SESSION_EXPIRY_INTERVAL, ) content, content_type = query_utils.serialize_content(str(session.uuid)) return HttpResponse(content, content_type)
def _user_category_post(request): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) field_maps = None try: fields = query_utils.get_fields__query_dict(request.GET) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest( 'JSON body must be object') # pragma: no cover if 'text' not in json_: return HttpResponseBadRequest('\'text\' missing') if type(json_['text']) is not str: return HttpResponseBadRequest('\'text\' must be string') user_category = models.UserCategory(user=request.user, text=json_['text']) try: user_category.save() except IntegrityError: return HttpResponse('user category already exists', status=409) ret_obj = query_utils.generate_return_object(field_maps, user_category, context) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _feed_entries_query_stable_create_post(request): cache = caches['stable_query'] context = Context() context.parse_request(request) context.parse_query_dict(request.GET) if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest( 'JSON body must be object') # pragma: no cover sort = None try: sort = query_utils.get_sort(json_, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) search = None try: search = query_utils.get_search(context, json_, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) token = f'feedentry-{uuid.uuid4().int}' cache.set( token, list( models.FeedEntry.annotate_search_vectors( models.FeedEntry.objects.all()).filter(*search).order_by( *sort).values_list('uuid', flat=True))) content, content_type = query_utils.serialize_content(token) return HttpResponse(content, content_type)
def _user_get(request): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) user = request.user field_maps = None try: fields = query_utils.get_fields__query_dict(request.GET) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) ret_obj = query_utils.generate_return_object(field_maps, user, context) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _feed_entries_query_stable_post(request): cache = caches['stable_query'] context = Context() context.parse_request(request) context.parse_query_dict(request.GET) if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest( 'JSON body must be object') # pragma: no cover token = None try: token = json_['token'] except KeyError: return HttpResponseBadRequest('\'token\' missing') if type(token) is not str: return HttpResponseBadRequest('\'token\' must be string') if re.search(r'^feedentry-\d+$', token) is None: return HttpResponseBadRequest('\'token\' malformed') count = None try: count = query_utils.get_count(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) skip = None try: skip = query_utils.get_skip(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) field_maps = None try: fields = query_utils.get_fields__json(json_) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) return_objects = None try: return_objects = query_utils.get_return_objects(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) return_total_count = None try: return_total_count = query_utils.get_return_total_count(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) cache.touch(token) uuids = cache.get(token, []) ret_obj = {} if return_objects: current_uuids = uuids[skip:skip + count] feed_entries = { feed_entry.uuid: feed_entry for feed_entry in models.FeedEntry.objects.filter( uuid__in=current_uuids) } objs = [] if len(current_uuids) == len(feed_entries): for uuid_ in current_uuids: feed_entry = feed_entries[uuid_] obj = query_utils.generate_return_object( field_maps, feed_entry, context) objs.append(obj) ret_obj['objects'] = objs if return_total_count: ret_obj['totalCount'] = len(uuids) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _feed_entries_query_post(request): context = Context() context.parse_request(request) context.parse_query_dict(request.GET) if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover json_ = None try: json_ = ujson.loads(request.body) except ValueError: # pragma: no cover return HttpResponseBadRequest('HTTP body cannot be parsed') if type(json_) is not dict: return HttpResponseBadRequest( 'JSON body must be object') # pragma: no cover count = None try: count = query_utils.get_count(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) skip = None try: skip = query_utils.get_skip(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) sort = None try: sort = query_utils.get_sort(json_, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) search = None try: search = query_utils.get_search(context, json_, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) field_maps = None try: fields = query_utils.get_fields__json(json_) field_maps = query_utils.get_field_maps(fields, _OBJECT_NAME) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) return_objects = None try: return_objects = query_utils.get_return_objects(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) return_total_count = None try: return_total_count = query_utils.get_return_total_count(json_) except QueryException as e: # pragma: no cover return HttpResponse(e.message, status=e.httpcode) feed_entries = models.FeedEntry.annotate_search_vectors( models.FeedEntry.objects.all()).filter(*search) ret_obj = {} if return_objects: objs = [] for feed_entry in feed_entries.order_by(*sort)[skip:skip + count]: obj = query_utils.generate_return_object(field_maps, feed_entry, context) objs.append(obj) ret_obj['objects'] = objs if return_total_count: ret_obj['totalCount'] = feed_entries.count() content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)
def _opml_post(request): if not request.body: return HttpResponseBadRequest('no HTTP body') # pragma: no cover opml_element = None try: opml_element = defused_fromstring(request.body) except defused_ParseError: return HttpResponseBadRequest('HTTP body cannot be parsed') try: opml_util.schema().validate(opml_element) except xmlschema.XMLSchemaException: return HttpResponseBadRequest('OPML not valid') outline_dict = {} for outer_outline_element in opml_element.findall('./body/outline'): outer_outline_name = outer_outline_element.attrib['title'] if outer_outline_name not in outline_dict: outline_dict[outer_outline_name] = set() for outline_element in outer_outline_element.findall('./outline'): outline_name = outline_element.attrib['title'] outline_xml_url = url_normalize(outline_element.attrib['xmlUrl']) outline_dict[outer_outline_name].add( (outline_name, outline_xml_url)) existing_subscriptions = set( models.SubscribedFeedUserMapping.objects.filter( user=request.user).values_list('feed__feed_url', flat=True)) existing_categories = { user_category.text: user_category for user_category in models.UserCategory.objects.filter( user=request.user) } existing_category_mappings = {} for feed_user_category_mapping in models.FeedUserCategoryMapping.objects.select_related( 'feed', 'user_category').filter(user_category__user=request.user): if feed_user_category_mapping.user_category.text not in existing_category_mappings: existing_category_mappings[ feed_user_category_mapping.user_category.text] = set() existing_category_mappings[ feed_user_category_mapping.user_category.text].add( feed_user_category_mapping.feed.feed_url) feeds_dict = {} feed_subscription_progress_entry = None feed_subscription_progress_entry_descriptors = [] for outer_outline_name, outline_set in outline_dict.items(): for outline_name, outline_xml_url in outline_set: if outline_xml_url not in feeds_dict: try: feeds_dict[outline_xml_url] = models.Feed.objects.get( feed_url=outline_xml_url) except models.Feed.DoesNotExist: if feed_subscription_progress_entry is None: feed_subscription_progress_entry = models.FeedSubscriptionProgressEntry( user=request.user) feed_subscription_progress_entry_descriptor = models.FeedSubscriptionProgressEntryDescriptor( feed_subscription_progress_entry= feed_subscription_progress_entry, feed_url=outline_xml_url, custom_feed_title=outline_name, user_category_text=outer_outline_name) feed_subscription_progress_entry_descriptors.append( feed_subscription_progress_entry_descriptor) feeds_dict[outline_xml_url] = None user_categories = [] subscribed_feed_user_mappings = [] feed_user_category_mappings = [] for outer_outline_name, outline_set in outline_dict.items(): user_category = existing_categories.get(outer_outline_name) if user_category is None: user_category = models.UserCategory(user=request.user, text=outer_outline_name) user_categories.append(user_category) existing_categories[user_category.text] = user_category existing_category_mapping_set = existing_category_mappings.get( outer_outline_name) if existing_category_mapping_set is None: existing_category_mapping_set = set() existing_category_mappings[ outer_outline_name] = existing_category_mapping_set for outline_name, outline_xml_url in outline_set: feed = feeds_dict[outline_xml_url] if feed is not None: custom_title = outline_name if outline_name != feed.title else None if outline_xml_url not in existing_subscriptions: subscribed_feed_user_mapping = models.SubscribedFeedUserMapping( feed=feed, user=request.user, custom_feed_title=custom_title) subscribed_feed_user_mappings.append( subscribed_feed_user_mapping) existing_subscriptions.add(outline_xml_url) if outline_xml_url not in existing_category_mapping_set: feed_user_category_mapping = models.FeedUserCategoryMapping( feed=feed, user_category=user_category) feed_user_category_mappings.append( feed_user_category_mapping) existing_category_mapping_set.add(outline_xml_url) with transaction.atomic(): for user_category in user_categories: user_category.save() models.SubscribedFeedUserMapping.objects.bulk_create( subscribed_feed_user_mappings) models.FeedUserCategoryMapping.objects.bulk_create( feed_user_category_mappings) for feed in feeds_dict.values(): if feed is not None: archived_feed_entry_util.mark_archived_entries( archived_feed_entry_util.read_mapping_generator_fn( feed, request.user)) if feed_subscription_progress_entry is not None: feed_subscription_progress_entry.save() models.FeedSubscriptionProgressEntryDescriptor.objects.bulk_create( feed_subscription_progress_entry_descriptors) if feed_subscription_progress_entry is None: return HttpResponse(status=204) else: content, content_type = query_utils.serialize_content( str(feed_subscription_progress_entry.uuid)) return HttpResponse(content, content_type, status=202)
def _explore_get(request): # TODO for the time being, this will just be static data (based on my personal OPML for now), because a recommendation engine is quite an endeavour section_lookups = [ { 'tag': 'Gaming', 'feeds': [ { 'feed_url': 'http://feeds.feedburner.com/GamasutraFeatureArticles', 'image_src': '/assets/images/explore_banner.png', }, { 'feed_url': 'http://feeds.wolfire.com/WolfireGames', 'image_src': '/assets/images/explore_banner.png', }, ], }, { 'tag': 'Technology', 'feeds': [ { 'feed_url': 'http://rss.slashdot.org/Slashdot/slashdot', 'image_src': None, }, { 'feed_url': 'http://feeds.arstechnica.com/arstechnica/index', 'image_src': None, }, ], }, { 'tag': 'World News', 'feeds': [ { 'feed_url': 'https://www.ctvnews.ca/rss/ctvnews-ca-top-stories-public-rss-1.822009', 'image_src': None, }, ], }, { 'tag': 'Programming', 'feeds': [ { 'feed_url': 'http://feeds.feedburner.com/codinghorror', 'image_src': None, }, { 'feed_url': 'http://feeds.wolfire.com/WolfireGames', 'image_src': None, }, { 'feed_url': 'http://syndication.thedailywtf.com/TheDailyWtf', 'image_src': None, }, ], }, { 'tag': 'Music', 'feeds': [ { 'feed_url': 'http://battlehelm.com/feed/', 'image_src': '/assets/images/explore_banner.png', }, { 'feed_url': 'http://www.theblackplanet.org/feed/', 'image_src': '/assets/images/explore_banner.png', }, { 'feed_url': 'http://www.angrymetalguy.com/feed/', 'image_src': '/assets/images/explore_banner.png', }, { 'feed_url': 'http://www.terrorizer.com/feed/', 'image_src': '/assets/images/explore_banner.png', }, { 'feed_url': 'http://deadrhetoric.com/feed/', 'image_src': '/assets/images/explore_banner.png', }, ], }, ] ret_obj = [] for section_lookup in section_lookups: feed_objs = [] for feed_lookup in section_lookup['feeds']: feed = None try: feed = models.Feed.annotate_subscription_data( models.Feed.objects.all(), request.user).get(feed_url=feed_lookup['feed_url']) except models.Feed.DoesNotExist: continue some_feed_entries = list(models.FeedEntry.objects.filter( feed=feed, title__isnull=False).order_by('published_at').values_list('title', flat=True)[:5]) if len(some_feed_entries) < 1: continue feed_objs.append({ 'name': feed.title, 'feedUrl': feed.feed_url, 'homeUrl': feed.home_url, 'imageSrc': feed_lookup['image_src'], 'entryTitles': some_feed_entries, 'isSubscribed': feed.is_subscribed, }) if len(feed_objs) > 0: ret_obj.append({ 'tagName': section_lookup['tag'], 'feeds': feed_objs, }) content, content_type = query_utils.serialize_content(ret_obj) return HttpResponse(content, content_type)