def test_synonyms_work_in_search_view(self): d1 = DocumentFactory(title='frob') d2 = DocumentFactory(title='glork') RevisionFactory(document=d1, is_approved=True) RevisionFactory(document=d2, is_approved=True) self.refresh() # First search without synonyms response = self.client.get(reverse('search'), {'q': 'frob'}) doc = pq(response.content) header = doc.find('#search-results h2').text().strip() eq_(header, 'Found 1 result for frob for All Products') # Now add a synonym. SynonymFactory(from_words='frob', to_words='frob, glork') update_synonyms_task() self.refresh() # Forward search response = self.client.get(reverse('search'), {'q': 'frob'}) doc = pq(response.content) header = doc.find('#search-results h2').text().strip() eq_(header, 'Found 2 results for frob for All Products') # Reverse search response = self.client.get(reverse('search'), {'q': 'glork'}) doc = pq(response.content) header = doc.find('#search-results h2').text().strip() eq_(header, 'Found 1 result for glork for All Products')
def test_needs_change(self): """Test setting and unsetting the needs change flag""" # Create a new document and edit it, setting needs_change. comment = 'Please update for Firefix.next' doc = RevisionFactory().document data = new_document_data() data.update({'needs_change': True, 'needs_change_comment': comment, 'form': 'doc'}) # Verify that needs_change can't be set if the user doesn't have # the permission. self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert not doc.needs_change assert not doc.needs_change_comment # Give the user permission, now it should work. add_permission(self.u, Document, 'edit_needs_change') self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert doc.needs_change eq_(comment, doc.needs_change_comment) # Clear out needs_change. data.update({'needs_change': False, 'needs_change_comment': comment}) self.client.post(reverse('wiki.edit_document', args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert not doc.needs_change eq_('', doc.needs_change_comment)
def test_removing_template_category(self): d = TemplateDocumentFactory() RevisionFactory(document=d) eq_(d.category, TEMPLATES_CATEGORY) assert d.title.startswith(TEMPLATE_TITLE_PREFIX) # First try and change the category without also changing the title. It should fail. data = new_document_data() data.update({ 'title': d.title, 'category': CATEGORIES[0][0], 'slug': d.slug, 'form': 'doc' }) url = reverse('wiki.edit_document', args=[d.slug]) res = self.client.post(url, data, follow=True) eq_(Document.objects.get(id=d.id).category, TEMPLATES_CATEGORY) # This message gets HTML encoded. assert ('Documents with titles that start with "Template:" must be in the ' 'templates category.' in res.content) # Now try and change the title while also changing the category. data['title'] = 'not a template' url = reverse('wiki.edit_document', args=[d.slug]) self.client.post(url, data) eq_(Document.objects.get(id=d.id).category, CATEGORIES[0][0])
def test_needs_change(self): """Test setting and unsetting the needs change flag""" # Create a new document and edit it, setting needs_change. comment = "Please update for Firefix.next" doc = revision(save=True).document data = new_document_data() data.update({"needs_change": True, "needs_change_comment": comment, "form": "doc"}) # Verify that needs_change can't be set if the user doesn't have # the permission. self.client.post(reverse("wiki.edit_document", args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert not doc.needs_change assert not doc.needs_change_comment # Give the user permission, now it should work. add_permission(self.u, Document, "edit_needs_change") self.client.post(reverse("wiki.edit_document", args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert doc.needs_change eq_(comment, doc.needs_change_comment) # Clear out needs_change. data.update({"needs_change": False, "needs_change_comment": comment}) self.client.post(reverse("wiki.edit_document", args=[doc.slug]), data) doc = Document.objects.get(pk=doc.pk) assert not doc.needs_change eq_("", doc.needs_change_comment)
def test_changing_products(self): """Changing products works as expected.""" r = ApprovedRevisionFactory() d = r.document prod_desktop = ProductFactory(title=u'desktop') prod_mobile = ProductFactory(title=u'mobile') data = new_document_data() data.update({'products': [prod_desktop.id, prod_mobile.id], 'title': d.title, 'slug': d.slug, 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[d.slug]), data) eq_(sorted(Document.objects.get(id=d.id).products .values_list('id', flat=True)), sorted([prod.id for prod in [prod_desktop, prod_mobile]])) data.update({'products': [prod_desktop.id], 'form': 'doc'}) self.client.post(reverse('wiki.edit_document', args=[data['slug']]), data) eq_(sorted(Document.objects.get(id=d.id).products .values_list('id', flat=True)), sorted([prod.id for prod in [prod_desktop]]))
def test_new_user(self, get_current): get_current.return_value.domain = 'su.mo.com' response = self.client.post(reverse('users.register', locale='en-US'), {'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foobar22'}, follow=True) eq_(200, response.status_code) u = User.objects.get(username='******') assert u.password.startswith('sha256') assert not u.is_active eq_(1, len(mail.outbox)) assert mail.outbox[0].subject.find('Please confirm your') == 0 key = RegistrationProfile.objects.all()[0].activation_key assert mail.outbox[0].body.find('activate/%s/%s' % (u.id, key)) > 0 # By default, users aren't added to any groups eq_(0, len(u.groups.all())) # Now try to log in u.is_active = True u.save() response = self.client.post(reverse('users.login', locale='en-US'), {'username': '******', 'password': '******'}, follow=True) eq_(200, response.status_code) eq_('http://testserver/en-US/home?fpa=1', response.redirect_chain[0][0])
def test_retitling_template(self): d = TemplateDocumentFactory() RevisionFactory(document=d) old_title = d.title new_title = 'Not a template' # First try and change the title without also changing the category. It should fail. data = new_document_data() data.update({ 'title': new_title, 'category': d.category, 'slug': d.slug, 'form': 'doc' }) url = reverse('wiki.edit_document', args=[d.slug]) res = self.client.post(url, data, follow=True) eq_(Document.objects.get(id=d.id).title, old_title) # This message gets HTML encoded. assert ('Documents in the Template category must have titles that start with ' '"Template:".' in res.content) # Now try and change the title while also changing the category. data['category'] = CATEGORIES[0][0] url = reverse('wiki.edit_document', args=[d.slug]) self.client.post(url, data, follow=True) eq_(Document.objects.get(id=d.id).title, new_title)
def login(request, template): """Try to log the user in.""" if request.method == 'GET' and not request.MOBILE: url = reverse('users.auth') + '?' + request.GET.urlencode() return HttpResponsePermanentRedirect(url) next_url = get_next_url(request) or reverse('home') form = handle_login(request) if request.user.is_authenticated(): # Add a parameter so we know the user just logged in. # fpa = "first page authed" or something. next_url = urlparams(next_url, fpa=1) res = HttpResponseRedirect(next_url) max_age = (None if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE else settings.SESSION_COOKIE_AGE) res.set_cookie(settings.SESSION_EXISTS_COOKIE, '1', secure=False, max_age=max_age) return res if request.MOBILE: return render(request, template, { 'form': form, 'next_url': next_url}) return user_auth(request, login_form=form)
def test_new_contributor(self, get_current): """Verify that interested contributors are added to group.""" get_current.return_value.domain = 'su.mo.com' group_name = 'Registered as contributor' group(name=group_name, save=True) data = { 'username': '******', 'email': '*****@*****.**', 'password': '******', 'password2': 'foobar22', 'interested': 'yes'} response = self.client.post(reverse('users.register', locale='en-US'), data, follow=True) eq_(200, response.status_code) u = User.objects.get(username='******') eq_(group_name, u.groups.all()[0].name) # Activate user and verify email is sent. key = RegistrationProfile.objects.all()[0].activation_key url = reverse('users.activate', args=[u.id, key]) response = self.client.get(url, follow=True) eq_(200, response.status_code) eq_(2, len(mail.outbox)) assert mail.outbox[1].subject.find('Welcome to') == 0 assert u.username in mail.outbox[1].body
def test_created(self): """Basic functionality of created filter.""" created_ds = datetime(2010, 6, 19, 12, 00) # on 6/19/2010 q1 = question(title=u'q1 audio', created=created_ds, save=True) q1.tags.add(u'desktop') ans = answer(question=q1, save=True) answervote(answer=ans, helpful=True, save=True) # on 6/21/2010 q2 = question(title=u'q2 audio', created=(created_ds + timedelta(days=2)), save=True) q2.tags.add(u'desktop') ans = answer(question=q2, save=True) answervote(answer=ans, helpful=True, save=True) self.refresh() qs = {'a': 1, 'w': 2, 'format': 'json', 'sortby': 2, 'created_date': '06/20/2010'} qs['created'] = constants.INTERVAL_BEFORE response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([q1.get_absolute_url()], [r['url'] for r in results]) qs['created'] = constants.INTERVAL_AFTER response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([q2.get_absolute_url()], [r['url'] for r in results])
def test_forums_filter_updated(self): """Filter for updated date.""" post_updated_ds = datetime(2010, 5, 3, 12, 00) thread1 = thread(title=u't1 audio', save=True) post(thread=thread1, created=post_updated_ds, save=True) thread2 = thread(title=u't2 audio', save=True) post(thread=thread2, created=(post_updated_ds + timedelta(days=2)), save=True) self.refresh() qs = {'a': 1, 'w': 4, 'format': 'json', 'sortby': 1, 'updated_date': '05/04/2010'} qs['updated'] = constants.INTERVAL_BEFORE response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([thread1.get_absolute_url()], [r['url'] for r in results]) qs['updated'] = constants.INTERVAL_AFTER response = self.client.get(reverse('search'), qs) results = json.loads(response.content)['results'] eq_([thread2.get_absolute_url()], [r['url'] for r in results])
def test_advanced_search_sortby_documents_helpful(self): """Tests advanced search with a sortby_documents by helpful""" r1 = revision(is_approved=True, save=True) r2 = revision(is_approved=True, save=True) helpful_vote(revision=r2, helpful=True, save=True) # Note: We have to wipe and rebuild the index because new # helpful_votes don't update the index data. self.setup_indexes() self.reindex_and_refresh() # r2.document should come first with 1 vote. response = self.client.get(reverse('search'), { 'w': '1', 'a': '1', 'sortby_documents': 'helpful', 'format': 'json'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(r2.document.title, content['results'][0]['title']) # Vote twice on r1, now it should come first. helpful_vote(revision=r1, helpful=True, save=True) helpful_vote(revision=r1, helpful=True, save=True) self.setup_indexes() self.reindex_and_refresh() response = self.client.get(reverse('search'), { 'w': '1', 'a': '1', 'sortby_documents': 'helpful', 'format': 'json'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(r1.document.title, content['results'][0]['title'])
def test_advanced_search_questions_num_votes(self): """Tests advanced search for questions num_votes filter""" q = question(title=u'tags tags tags', save=True) # Add two question votes questionvote(question=q, save=True) questionvote(question=q, save=True) self.refresh() # Advanced search for questions with num_votes > 5. The above # question should be not in this set. response = self.client.get(reverse('search'), { 'q': '', 'tags': 'desktop', 'w': '2', 'a': '1', 'num_voted': 2, 'num_votes': 5, 'format': 'json' }) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 0) # Advanced search for questions with num_votes < 1. The above # question should be not in this set. response = self.client.get(reverse('search'), { 'q': '', 'tags': 'desktop', 'w': '2', 'a': '1', 'num_voted': 1, 'num_votes': 1, 'format': 'json' }) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 0)
def new_message(request, template): """Send a new private message.""" to = request.GET.get('to') if to: try: User.objects.get(username=to) except User.DoesNotExist: contrib_messages.add_message( request, contrib_messages.ERROR, _('Invalid username provided. Enter a new username below.')) return HttpResponseRedirect(reverse('messages.new')) form = MessageForm(request.POST or None, initial={'to': to}) if (request.method == 'POST' and form.is_valid() and not is_ratelimited(request, increment=True, rate='50/d', ip=False, keys=user_or_ip('private-message-day'))): send_message(form.cleaned_data['to'], form.cleaned_data['message'], request.user) if form.cleaned_data['in_reply_to']: irt = form.cleaned_data['in_reply_to'] try: m = InboxMessage.objects.get(pk=irt, to=request.user) m.update(replied=True) except InboxMessage.DoesNotExist: pass contrib_messages.add_message(request, contrib_messages.SUCCESS, _('Your message was sent!')) return HttpResponseRedirect(reverse('messages.inbox')) return render(request, template, {'form': form})
def _format_row_with_out_of_dateness(readout_locale, eng_slug, eng_title, slug, title, visits, significance, needs_review): """Format a row for a readout that has the traffic-light-style categorization of how seriously out of date a translation is.""" if slug: # A translation exists but may not be approved. locale = readout_locale status, view_name, status_class = SIGNIFICANCE_STATUSES.get( significance, REVIEW_STATUSES[needs_review]) status_url = (reverse(view_name, args=[slug], locale=locale) if view_name else '') else: slug = eng_slug title = eng_title locale = settings.WIKI_DEFAULT_LANGUAGE status = _(u'Translation Needed') # When calling the translate view, specify locale to translate to: status_url = reverse('wiki.translate', args=[slug], locale=readout_locale) status_class = 'untranslated' return dict(title=title, url=reverse('wiki.document', args=[slug], locale=locale), visits=visits, status=status, status_class=status_class, status_url=status_url)
def test_locale_filter(self): """Test filtering results by locale.""" today = date.today() # Create 3 wikimetrics for es: for i in range(3): wikimetric( locale='es', date=today - timedelta(days=i), save=True) # Create 1 for fr: wikimetric(locale='fr', save=True) # Call and verify the API for locale=es. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', locale='es')) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(3, len(results)) # Call and verify the API for locale=fr. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', locale='fr')) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(1, len(results))
def delete_post(request, forum_slug, thread_id, post_id): """Delete a post.""" forum = get_object_or_404(Forum, slug=forum_slug) thread = get_object_or_404(Thread, pk=thread_id, forum=forum) post = get_object_or_404(Post, pk=post_id, thread=thread) if request.method == 'GET': # Render the confirmation page return render(request, 'forums/confirm_post_delete.html', { 'forum': forum, 'thread': thread, 'post': post}) # Handle confirm delete form POST log.warning("User %s is deleting post with id=%s" % (request.user, post.id)) post.delete() statsd.incr('forums.delete_post') try: Thread.objects.get(pk=thread_id) goto = reverse('forums.posts', args=[forum_slug, thread_id]) except Thread.DoesNotExist: # The thread was deleted, go to the threads list page goto = reverse('forums.threads', args=[forum_slug]) return HttpResponseRedirect(goto)
def _get_wiki_link(title, locale): """Checks the page exists, and returns its URL or the URL to create it. Return value is a dict: {'found': boolean, 'url': string}. found is False if the document does not exist. """ # Prevent circular import. sumo is conceptually a utils apps and # shouldn't have import-time (or really, any, but that's not going # to happen) dependencies on client apps. from kitsune.wiki.models import Document d = get_object_fallback(Document, locale=locale, title=title, is_template=False) if d: # If the article redirects use its destination article while d.redirect_document(): d = d.redirect_document() # The locale in the link urls should always match the current # document's locale even if the document/slug being linked to # is in the default locale. url = reverse("wiki.document", locale=locale, args=[d.slug]) return {"found": True, "url": url, "text": d.title} # To avoid circular imports, wiki.models imports wiki_to_html from kitsune.sumo.helpers import urlparams return {"found": False, "text": title, "url": urlparams(reverse("wiki.new_document", locale=locale), title=title)}
def test_code_filter(self): """Test filtering results by code.""" today = date.today() # Create 3 wikimetrics for active_contributors: for i in range(3): wikimetric( code=METRIC_CODE_CHOICES[0][0], date=today - timedelta(days=i), save=True) # Create 1 for percent_localized_all: wikimetric(code=METRIC_CODE_CHOICES[1][0], save=True) # Call and verify the API for code=METRIC_CODE_CHOICES[0]. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', code=METRIC_CODE_CHOICES[0][0])) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(3, len(results)) # Call and verify the API for code=METRIC_CODE_CHOICES[1]. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', code=METRIC_CODE_CHOICES[1][0])) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(1, len(results))
def test_advanced_search_questions_num_votes(self): """Tests advanced search for questions num_votes filter""" q = question(title=u"tags tags tags", save=True) # Add two question votes questionvote(question=q, save=True) questionvote(question=q, save=True) self.refresh() # Advanced search for questions with num_votes > 5. The above # question should be not in this set. response = self.client.get( reverse("search"), {"q": "", "tags": "desktop", "w": "2", "a": "1", "num_voted": 2, "num_votes": 5, "format": "json"}, ) eq_(200, response.status_code) content = json.loads(response.content) eq_(content["total"], 0) # Advanced search for questions with num_votes < 1. The above # question should be not in this set. response = self.client.get( reverse("search"), {"q": "", "tags": "desktop", "w": "2", "a": "1", "num_voted": 1, "num_votes": 1, "format": "json"}, ) eq_(200, response.status_code) content = json.loads(response.content) eq_(content["total"], 0)
def test_created(self): """Basic functionality of created filter.""" created_ds = datetime(2010, 6, 19, 12, 00) # on 6/19/2010 q1 = question(title=u"q1 audio", created=created_ds, save=True) q1.tags.add(u"desktop") ans = answer(question=q1, save=True) answervote(answer=ans, helpful=True, save=True) # on 6/21/2010 q2 = question(title=u"q2 audio", created=(created_ds + timedelta(days=2)), save=True) q2.tags.add(u"desktop") ans = answer(question=q2, save=True) answervote(answer=ans, helpful=True, save=True) self.refresh() qs = {"a": 1, "w": 2, "format": "json", "sortby": 2, "created_date": "06/20/2010"} qs["created"] = constants.INTERVAL_BEFORE response = self.client.get(reverse("search"), qs) results = json.loads(response.content)["results"] eq_([q1.get_absolute_url()], [r["url"] for r in results]) qs["created"] = constants.INTERVAL_AFTER response = self.client.get(reverse("search"), qs) results = json.loads(response.content)["results"] eq_([q2.get_absolute_url()], [r["url"] for r in results])
def delete_post(request, document_slug, thread_id, post_id): """Delete a post.""" doc = get_document(document_slug, request) thread = get_object_or_404(Thread, pk=thread_id, document=doc) post = get_object_or_404(Post, pk=post_id, thread=thread) if request.method == 'GET': # Render the confirmation page return render(request, 'kbforums/confirm_post_delete.html', { 'document': doc, 'thread': thread, 'post': post}) # Handle confirm delete form POST log.warning("User {0!s} is deleting KB post with id={1!s}".format(request.user, post.id)) post.delete() statsd.incr('kbforums.delete_post') try: Thread.objects.get(pk=thread_id) goto = reverse('wiki.discuss.posts', args=[document_slug, thread_id]) except Thread.DoesNotExist: # The thread was deleted, go to the threads list page goto = reverse('wiki.discuss.threads', args=[document_slug]) return HttpResponseRedirect(goto)
def test_top_contributors(self): # There should be no top contributors since there are no answers. response = self.client.get(reverse('questions.list', args=['all'])) eq_(200, response.status_code) doc = pq(response.content) eq_(0, len(doc('#top-contributors ol li'))) # Add an answer, we now have a top conributor. a = answer(save=True) profile(user=a.creator) self.refresh() response = self.client.get(reverse('questions.list', args=['all'])) eq_(200, response.status_code) doc = pq(response.content) lis = doc('#top-contributors ol li') eq_(1, len(lis)) eq_(Profile.objects.get(user=a.creator).display_name, lis[0].text) # Make answer 91 days old. There should no be top contributors. a.created = datetime.now() - timedelta(days=91) a.save() self.refresh() response = self.client.get(reverse('questions.list', args=['all'])) eq_(200, response.status_code) doc = pq(response.content) eq_(0, len(doc('#top-contributors ol li')))
def test_sortby_documents_helpful(self): """Tests advanced search with a sortby_documents by helpful""" r1 = RevisionFactory(is_approved=True) r2 = RevisionFactory(is_approved=True) HelpfulVoteFactory(revision=r2, helpful=True) # Note: We have to wipe and rebuild the index because new # helpful_votes don't update the index data. self.setup_indexes() self.reindex_and_refresh() # r2.document should come first with 1 vote. response = self.client.get( reverse("search.advanced"), {"w": "1", "a": "1", "sortby_documents": "helpful", "format": "json"} ) eq_(200, response.status_code) content = json.loads(response.content) eq_(r2.document.title, content["results"][0]["title"]) # Vote twice on r1, now it should come first. HelpfulVoteFactory(revision=r1, helpful=True) HelpfulVoteFactory(revision=r1, helpful=True) self.setup_indexes() self.reindex_and_refresh() response = self.client.get( reverse("search.advanced"), {"w": "1", "a": "1", "sortby_documents": "helpful", "format": "json"} ) eq_(200, response.status_code) content = json.loads(response.content) eq_(r1.document.title, content["results"][0]["title"])
def new_message(request, template): """Send a new private message.""" to = request.GET.get("to") if to: try: User.objects.get(username=to) except User.DoesNotExist: contrib_messages.add_message( request, contrib_messages.ERROR, _("Invalid username provided. Enter a new username below.") ) return HttpResponseRedirect(reverse("messages.new")) form = MessageForm(request.POST or None, initial={"to": to}) if ( request.method == "POST" and form.is_valid() and not is_ratelimited(request, increment=True, rate="50/d", ip=False, keys=user_or_ip("private-message-day")) ): send_message(form.cleaned_data["to"], form.cleaned_data["message"], request.user) if form.cleaned_data["in_reply_to"]: irt = form.cleaned_data["in_reply_to"] try: m = InboxMessage.objects.get(pk=irt, to=request.user) m.update(replied=True) except InboxMessage.DoesNotExist: pass contrib_messages.add_message(request, contrib_messages.SUCCESS, _("Your message was sent!")) return HttpResponseRedirect(reverse("messages.inbox")) return render(request, template, {"form": form})
def test_filter_by_doctype(self): desktop = ProductFactory(slug=u'desktop') ques = QuestionFactory(title=u'audio', product=desktop) ans = AnswerFactory(question=ques, content=u'volume') AnswerVoteFactory(answer=ans, helpful=True) doc = DocumentFactory(title=u'audio', locale=u'en-US', category=10, products=[desktop]) RevisionFactory(document=doc, is_approved=True) doc = DocumentFactory(title=u'audio too', locale=u'en-US', category=10, products=[desktop]) RevisionFactory(document=doc, is_approved=True) self.refresh() # There should be 2 results for kb (w=1) and 1 for questions (w=2). response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'w': '1'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 2) response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'w': '2'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 1)
def test_product_filter(self): """Test filtering results by product.""" today = date.today() # Create products and associated wiki metrics. p1 = ProductFactory() p2 = ProductFactory() # Create 3 for each product: for i in range(3): for p in [p1, p2]: WikiMetricFactory(date=today - timedelta(days=i), product=p) # Create one more for p2. WikiMetricFactory(date=today - timedelta(days=4), product=p2) # Call and verify the API for product=p1. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', product=p1.slug)) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(3, len(results)) # Call and verify the API for product=p1. response = self.client.get( urlparams(reverse('api.wikimetric_list'), format='json', product=p2.slug)) eq_(200, response.status_code) results = json.loads(response.content)['results'] eq_(4, len(results))
def test_filter_by_doctype(self): desktop = product(slug=u'desktop', save=True) ques = question(title=u'audio', product=desktop, save=True) ans = answer(question=ques, content=u'volume', save=True) answervote(answer=ans, helpful=True, save=True) doc = document(title=u'audio', locale=u'en-US', category=10, save=True) doc.products.add(desktop) revision(document=doc, is_approved=True, save=True) doc = document( title=u'audio too', locale=u'en-US', category=10, save=True) doc.products.add(desktop) revision(document=doc, is_approved=True, save=True) self.refresh() # There should be 2 results for kb (w=1) and 1 for questions (w=2). response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'w': '1'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 2) response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'w': '2'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 1)
def test_filter_by_product(self): desktop = ProductFactory(slug=u'desktop') mobile = ProductFactory(slug=u'mobile') ques = QuestionFactory(title=u'audio', product=desktop) ans = AnswerFactory(question=ques, content=u'volume') AnswerVoteFactory(answer=ans, helpful=True) doc = DocumentFactory(title=u'audio', locale=u'en-US', category=10) doc.products.add(desktop) doc.products.add(mobile) RevisionFactory(document=doc, is_approved=True) self.refresh() # There should be 2 results for desktop and 1 for mobile. response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'product': 'desktop'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 2) response = self.client.get(reverse('search'), { 'q': 'audio', 'format': 'json', 'product': 'mobile'}) eq_(200, response.status_code) content = json.loads(response.content) eq_(content['total'], 1)
def test_weekly_solutions(self): eight_days_ago = datetime.now() - timedelta(days=8) # First one is a solution, but it is too old. # second answer is not a solution. SolutionAnswerFactory(created=eight_days_ago) AnswerFactory() res = self.client.get(reverse('user-weekly-solutions')) eq_(res.status_code, 200) eq_(len(res.data), 0) # Check that the data about the contributors is showing currectly user_info_list = [] # Info list with username and their number of solutions top_answer_number = 15 for i in range(12): user = UserFactory() SolutionAnswerFactory.create_batch(top_answer_number, creator=user) user_info_list.append((user.username, top_answer_number)) top_answer_number -= 1 res = self.client.get(reverse('user-weekly-solutions')) eq_(res.status_code, 200) # Check only 10 users information is present there eq_(len(res.data), 10) # Create a list of the data with only the ``username`` and ``weekly_solutions`` data_list = [(data['username'], data['weekly_solutions']) for data in res.data] # Check only top 10 contributor information is in the API top_ten = user_info_list[:10] eq_(sorted(top_ten), sorted(data_list))
def get_absolute_url(self): # Note: If this function changes, we need to change it in # extract_document, too. return reverse('questions.answers', kwargs={'question_id': self.id})
def get_absolute_url(self): return reverse('wiki.document', locale=self.locale, args=[self.slug])
def get_absolute_url(self): return reverse('wiki.locale_details', args=[self.locale])
def get_absolute_url(self): return reverse('wiki.revision', locale=self.document.locale, args=[self.document.slug, self.id])
def setUp(self): url = reverse('forums.threads', args=[u'test-forum']) self.context = {'request': RequestFactory().get(url)}
def get_absolute_url(self): return reverse("users.profile", args=[self.pk])
def extract_document(cls, obj_id, obj=None): """Extracts indexable attributes from a Question and its answers.""" fields = [ 'id', 'title', 'content', 'num_answers', 'solution_id', 'is_locked', 'created', 'updated', 'num_votes_past_week', 'locale' ] composed_fields = ['creator__username'] all_fields = fields + composed_fields if obj is None: # Note: Need to keep this in sync with # tasks.update_question_vote_chunk. model = cls.get_model() obj = model.uncached.values(*all_fields).get(pk=obj_id) else: fixed_obj = dict([(field, getattr(obj, field)) for field in fields]) fixed_obj['creator__username'] = obj.creator.username obj = fixed_obj d = {} d['id'] = obj['id'] d['model'] = cls.get_mapping_type_name() # We do this because get_absolute_url is an instance method # and we don't want to create an instance because it's a DB # hit and expensive. So we do it by hand. get_absolute_url # doesn't change much, so this is probably ok. d['url'] = reverse('questions.answers', kwargs={'question_id': obj['id']}) d['indexed_on'] = int(time.time()) d['created'] = int(time.mktime(obj['created'].timetuple())) d['updated'] = int(time.mktime(obj['updated'].timetuple())) topics = Topic.uncached.filter(question__id=obj['id']) products = Product.uncached.filter(question__id=obj['id']) d['topic'] = [t.slug for t in topics] d['product'] = [p.slug for p in products] d['question_title'] = obj['title'] d['question_content'] = obj['content'] d['question_num_answers'] = obj['num_answers'] d['question_is_solved'] = bool(obj['solution_id']) d['question_is_locked'] = obj['is_locked'] d['question_has_answers'] = bool(obj['num_answers']) d['question_creator'] = obj['creator__username'] d['question_num_votes'] = (QuestionVote.objects.filter( question=obj['id']).count()) d['question_num_votes_past_week'] = obj['num_votes_past_week'] d['question_tag'] = list( TaggedItem.tags_for(Question, Question(pk=obj_id)).values_list('name', flat=True)) d['question_locale'] = obj['locale'] answer_values = list( Answer.objects.filter(question=obj_id).values_list( 'content', 'creator__username')) d['question_answer_content'] = [a[0] for a in answer_values] d['question_answer_creator'] = list(set(a[1] for a in answer_values)) if not answer_values: d['question_has_helpful'] = False else: d['question_has_helpful'] = Answer.objects.filter( question=obj_id).filter(votes__helpful=True).exists() return d
def test_xframe_options_deny_not_minimal(self): url = reverse('wiki.document', args=[self.doc.slug], locale='en-US') res = self.client.get(url) eq_(res['X-Frame-Options'], 'DENY')
def test_only_if_mobile(self): url = reverse('wiki.document', args=[self.doc.slug], locale='en-US') url += '?minimal=1' res = self.client.get(url) self.assertTemplateUsed(res, 'wiki/document.html')
def test_it_works(self): url = reverse('wiki.document', args=[self.doc.slug], locale='en-US') res = self.client.get(url) eq_(res.status_code, 200) self.assertTemplateUsed(res, 'wiki/mobile/document.html')
def test_doc_lock_workflow(self): """End to end test of locking on an english document.""" doc, rev = doc_rev() url = reverse('wiki.edit_document', args=[doc.slug], locale='en-US') self._lock_workflow(doc, url)
def test_xframe_options(self): url = reverse('wiki.document', args=[self.doc.slug], locale='en-US') url += '?minimal=1&mobile=1' res = self.client.get(url) # If it is not set to "DENY", then it is allowed. eq_(res.get('X-Frame-Options', 'ALLOW').lower(), 'allow')
def test_helpful_vote_no_id(self): """Throw helpful_vote a POST without an ID and see if it 400s.""" response = self.client.post(reverse('wiki.document_vote', args=['hi']), {}) eq_(400, response.status_code)
def test_it_works(self): url = reverse('wiki.document', args=[self.doc.slug], locale='en-US') url += '?minimal=1&mobile=1' res = self.client.get(url) self.assertTemplateUsed(res, 'wiki/mobile/document-minimal.html')
def test_while_there_is_no_parent_slug(self): doc = DocumentFactory(locale=settings.WIKI_DEFAULT_LANGUAGE) invalid_slug = doc.slug + 'invalid_slug' url = reverse('wiki.edit_document', args=[invalid_slug], locale='bn-BD') response = self.client.get(url) eq_(response.status_code, 404)
def test_fallback_with_query_params(self): """The query parameters should be passed along to the redirect.""" en_doc, de_doc = self._create_en_and_de_docs() url = reverse('wiki.document', args=[en_doc.slug], locale='de') response = self.client.get(url + '?x=y&x=z', follow=True) self.assertRedirects(response, de_doc.get_absolute_url() + '?x=y&x=z')
def test_GET(self): r = self.client.get(reverse('users.edit_watch_list')) eq_(200, r.status_code) assert u'question: ' + self.question.title in r.content.decode('utf8')
def test_helpful_vote_bad_id(self): """Throw helpful_vote a bad ID, and see if it crashes.""" response = self.client.post(reverse('wiki.document_vote', args=['hi']), {'revision_id': 'x'}) eq_(404, response.status_code)
def setUp(self): super(PasswordChangeTests, self).setUp() self.u = UserFactory() self.url = reverse('users.pw_change') self.new_pw = 'fjdka387fvstrongpassword!' self.client.login(username=self.u.username, password='******')
def test_json_view_404(self): """Searching for something that doesn't exist should 404.""" url = reverse('wiki.json', force_locale=True) resp = self.client.get(url, {'title': 'an article title ok.'}) eq_(404, resp.status_code)
def test_bad_email(self): r = self.client.post(reverse('users.pw_reset'), {'email': '*****@*****.**'}) eq_(302, r.status_code) eq_('http://testserver/en-US/users/pwresetsent', r['location']) eq_(0, len(mail.outbox))
def test_GET(self): r = self.client.get(reverse('users.forgot_username')) eq_(200, r.status_code)
def test_no_signature(self): response = self.client.get(reverse('postcrash.api')) eq_(400, response.status_code) eq_(b'', response.content) eq_('text/plain', response['content-type'])
def _get_reset_url(self): return reverse('users.pw_reset_confirm', args=[self.uidb36, self.token])
def test_search_type_param(self): """Ensure that invalid values for search type (a=) does not cause errors""" response = self.client.get(reverse('search'), {'a': 'dontdie'}) eq_('text/html; charset=utf-8', response['Content-Type']) eq_(200, response.status_code)
def test_login_mobile_csrf(self): """The mobile registration view should have a CSRF token.""" response = self.client.get(reverse('users.register'), {'mobile': 1}) eq_(200, response.status_code) doc = pq(response.content) assert doc('#content form input[name="csrfmiddlewaretoken"]')
def test_content(self): """Ensure template is rendered with no errors for a common search""" response = self.client.get(reverse('search'), {'q': 'audio'}) eq_('text/html; charset=utf-8', response['Content-Type']) eq_(200, response.status_code)
def test_unknown_signature(self): url = urlparams(reverse('postcrash.api'), s='foo') response = self.client.get(url) eq_(404, response.status_code) eq_(b'', response.content) eq_('text/plain', response['content-type'])
def setUp(self): super(LoginTests, self).setUp() self.u = UserFactory() self.profile_url = reverse('users.profile', args=[self.u.username], locale=settings.LANGUAGE_CODE) + '?fpa=1'
def test_content_mobile(self): """Ensure mobile template is rendered.""" self.client.cookies[settings.MOBILE_COOKIE] = 'on' response = self.client.get(reverse('search'), {'q': 'audio'}) eq_('text/html; charset=utf-8', response['Content-Type']) eq_(200, response.status_code)