def _feed_subscribe_post(request): user = request.user url = request.GET.get('url') if not url: return HttpResponseBadRequest('\'url\' missing') url = url_normalize(url) feed = None try: feed = models.Feed.objects.get(feed_url=url) except models.Feed.DoesNotExist: try: feed = _save_feed(url) except QueryException as e: return HttpResponse(e.message, status=e.httpcode) custom_title = request.GET.get('customtitle') existing_subscription_list = list(models.SubscribedFeedUserMapping.objects.filter( user=user).values_list('feed__feed_url', 'custom_feed_title')) existing_feed_urls = frozenset(t[0] for t in existing_subscription_list) existing_custom_titles = frozenset( t[1] for t in existing_subscription_list if t[1] is not None) if custom_title is not None and custom_title in existing_custom_titles: return HttpResponse('custom title already used', status=409) if feed.feed_url in existing_feed_urls: return HttpResponse('user already subscribed', status=409) read_mapping_generator = archived_feed_entry_util.read_mapping_generator_fn( feed, user) with transaction.atomic(): models.SubscribedFeedUserMapping.objects.create( user=user, feed=feed, custom_feed_title=custom_title) archived_feed_entry_util.mark_archived_entries(read_mapping_generator) return HttpResponse(status=204)
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 test_read_mapping_generator_fn_morethanmincount(self): with self.settings( USER_UNREAD_GRACE_INTERVAL=datetime.timedelta(days=-7), USER_UNREAD_GRACE_MIN_COUNT=1): user = models.User.objects.create(email='*****@*****.**') feed = models.Feed.objects.create( feed_url='http://example.com/rss.xml', title='Sample Feed', home_url='http://example.com', published_at=datetime.datetime.utcnow(), updated_at=None, db_updated_at=None) feed_entry1 = models.FeedEntry( id=None, feed=feed, created_at=None, updated_at=None, title='Feed Entry 1 Title', url='http://example.com/entry1.html', content='Some Entry content', author_name='John Doe', db_updated_at=None) feed_entry2 = models.FeedEntry( id=None, feed=feed, created_at=None, updated_at=None, title='Feed Entry 2 Title', url='http://example.com/entry2.html', content='Some Entry content', author_name='John Doe', db_updated_at=None) feed_entry3 = models.FeedEntry( id=None, feed=feed, created_at=None, updated_at=None, title='Feed Entry 3 Title', url='http://example.com/entry3.html', content='Some Entry content', author_name='John Doe', db_updated_at=None) feed_entry4 = models.FeedEntry( id=None, feed=feed, created_at=None, updated_at=None, title='Feed Entry 4 Title', url='http://example.com/entry4.html', content='Some Entry content', author_name='John Doe', db_updated_at=None) models.FeedEntry.objects.bulk_create( [feed_entry1, feed_entry2, feed_entry3, feed_entry4]) feed_entry1.published_at = user.created_at + \ settings.USER_UNREAD_GRACE_INTERVAL + \ datetime.timedelta(days=-1, minutes=-10) feed_entry1.save(update_fields=['published_at']) feed_entry2.published_at = user.created_at + \ settings.USER_UNREAD_GRACE_INTERVAL + \ datetime.timedelta(days=-1, minutes=-20) feed_entry2.save(update_fields=['published_at']) read_mappings = list( archived_feed_entry_util.read_mapping_generator_fn(feed, user)) self.assertEqual(len(read_mappings), 2)