Exemple #1
0
def overview(request):
    """Returns the overview for a daterange.

    GET paramaters:
    * daterange - 7d, 1m, 3m, 6m or 1y (default: 1y)

    Returns an overview dict with a count for all action types.
    """
    form = OverviewAPIForm(request.GET)
    if not form.is_valid():
        return {'success': False, 'errors': form.errors}

    daterange = form.cleaned_data.get('daterange') or '1y'

    mgr = KarmaManager()
    overview = {}
    for t in KarmaManager.action_types.keys():
        overview[t] = mgr.count(daterange=daterange, type=t)

    # TODO: Maybe have a karma action not assigned to a user for this?
    num_days = KarmaManager.date_ranges[daterange]
    start_day = date.today() - timedelta(days=num_days)
    overview['question'] = Question.objects.filter(
        created__gt=start_day).count()

    return {
        'success': True,
        'overview': overview}
Exemple #2
0
def _process_recalculate_chunk(data, **kwargs):
    """Recalculate karma points for a chunk of user ids."""
    mgr = KarmaManager()
    actions = [AnswerAction, AnswerMarkedHelpfulAction, AnswerMarkedNotHelpfulAction, FirstAnswerAction, SolutionAction]
    actions_dict = dict((a.action_type, a.points) for a in actions)

    for userid in data:
        mgr.recalculate_points(userid, actions_dict)
Exemple #3
0
def details(request):
    """Returns monthly or daily totals for an action type.

    Feeds the dashboard chart.
    """
    mgr = KarmaManager()
    form = DetailAPIForm(request.GET)

    if not form.is_valid():
        return {'success': False, 'errors': form.errors}
    userid = form.cleaned_data.get('userid') or 'overview'
    daterange = form.cleaned_data.get('daterange') or '1y'
    counts = {}
    count_func = mgr.monthly_counts
    form.cleaned_data.pop('daterange')
    if daterange == '1w':
        count_func = mgr.daily_counts
    for t in KarmaManager.action_types.keys():
        counts[t], time_units = count_func(daterange,
                                           type=t,
                                           **form.cleaned_data)

    return {
        'success': True,
        'time_units': time_units,
        'counts': counts,
        'userid': userid
    }
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaManagerTests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        today = date.today()

        # user1 actions (3 + 3 + 7):
        TestAction1(user=self.user1, day=today).save()
        TestAction1(user=self.user1, day=today).save()
        TestAction2(user=self.user1, day=today).save()

        # user2 actions (3 + 7 + 7):
        TestAction1(user=self.user2, day=today - timedelta(days=8)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=32)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=360)).save()

        # user3 actions (3 + 3 + 3 + 7):
        TestAction1(user=self.user3, day=today - timedelta(days=10)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=40)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=190)).save()
        TestAction2(user=self.user3, day=today - timedelta(days=3)).save()
Exemple #5
0
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaAPITests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        TestAction1(user=self.user1).save()
        TestAction2(user=self.user2).save()
        TestAction2(user=self.user2).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        self.mgr.update_top()

        self.client.login(username=self.user1.username, password='******')
        add_permission(self.user1, models.Title, 'view_dashboard')
Exemple #6
0
def karma(request):
    """Admin view that displays karma related data."""
    if not request.user.has_perm('users.view_karma_points'):
        raise PermissionDenied

    if request.POST.get('init'):
        init_karma.delay()
        messages.add_message(request, messages.SUCCESS,
                             'init_karma task queued!')
        return HttpResponseRedirect(request.path)

    if request.POST.get('recalculate'):
        recalculate_karma_points.delay()
        messages.add_message(request, messages.SUCCESS,
                             'recalculate_karma_points task queued!')
        return HttpResponseRedirect(request.path)

    if request.POST.get('update-top'):
        update_top_contributors.delay()
        messages.add_message(request, messages.SUCCESS,
                             'update_top_contributors task queued!')
        return HttpResponseRedirect(request.path)

    kmgr = KarmaManager()
    top_alltime = [_user_karma_alltime(u, kmgr) for
                   u in kmgr.top_users('all') or []]
    top_week = [_user_karma_week(u, kmgr) for
                u in kmgr.top_users(daterange='1w') or []]

    username = request.GET.get('username')
    user_karma = None
    if username:
        try:
            user = User.objects.get(username=username)
            d = kmgr.user_data(user)
            user_karma = [{'key': k, 'value': d[k]} for k in sorted(d.keys())]
        except User.DoesNotExist:
            pass

    return render(
        request,
        'admin/karma.html',
        {'title': 'Karma',
         'top_alltime': top_alltime,
         'top_week': top_week,
         'username': username,
         'user_karma': user_karma})
Exemple #7
0
 def setUp(self):
     super(KarmaActionTests, self).setUp()
     self.user = user(save=True)
     try:
         self.mgr = KarmaManager()
         redis_client('karma').flushdb()
     except RedisError:
         raise SkipTest
Exemple #8
0
 def creator_num_points(self):
     try:
         return KarmaManager().count('all',
                                     user=self.creator,
                                     type='points')
     except RedisError as e:
         statsd.incr('redis.errror')
         log.error('Redis connection error: %s' % e)
Exemple #9
0
def user_num_answers(user):
    """Count the number of answers a user has.

    If karma is enabled, and redis is working, this will query that (much
    faster), otherwise it will just count objects in the database.
    """
    if waffle.switch_is_active('karma'):
        try:
            km = KarmaManager()
            count = km.count(user=user, type=AnswerAction.action_type)
            if count is not None:
                return count
        except RedisError as e:
            statsd.incr('redis.errror')
            log.error('Redis connection error: %s' % e)

    return Answer.objects.filter(creator=user).count()
Exemple #10
0
def user_num_answers(user):
    """Count the number of answers a user has.

    If karma is enabled, and redis is working, this will query that (much
    faster), otherwise it will just count objects in the database.
    """
    if waffle.switch_is_active('karma'):
        try:
            km = KarmaManager()
            count = km.count(user=user, type=AnswerAction.action_type)
            if count is not None:
                return count
        except RedisError as e:
            statsd.incr('redis.errror')
            log.error('Redis connection error: %s' % e)

    return Answer.objects.filter(creator=user).count()
Exemple #11
0
def users(request):
    """Returns list of user karma information.

    GET paramaters:
    * daterange - 7d, 1m, 3m, 6m or 1y (default: 1y)
    * sort - field to sort on (default: points). Order is always descending.
    * page - starts at 1 (default: 1)
    * pagesize - (default: 100)

    Returns list of objects with the following fields:
        userid, username, points, <action_types>
    """
    form = UserAPIForm(request.GET)
    if not form.is_valid():
        return {'success': False, 'errors': form.errors}

    daterange = form.cleaned_data.get('daterange') or '1y'
    sort = form.cleaned_data.get('sort') or 'points'
    page = form.cleaned_data.get('page') or 1
    pagesize = form.cleaned_data.get('pagesize') or 100

    mgr = KarmaManager()
    users = mgr.top_users(daterange=daterange, type=sort, count=pagesize,
                          offset=(page - 1) * pagesize) or []

    now = datetime.now()
    action_types = KarmaManager.action_types.keys()
    schema = ['id', 'username', 'lastactivity', 'points'] + action_types
    user_list = []
    for u in users:
        user = [u.id, u.username]
        last_activity = Answer.last_activity_for(u)
        user.append((now - last_activity).days if last_activity else None)
        user.append(mgr.count(u, daterange=daterange, type='points'))
        for t in action_types:
            user.append(mgr.count(u, daterange=daterange, type=t))
        user_list.append(user)

    return {
        'success': True,
        'results': user_list,
        'schema': schema}
Exemple #12
0
def users(request):
    """Returns list of user karma information.

    GET paramaters:
    * daterange - 7d, 1m, 3m, 6m or 1y (default: 1y)
    * sort - field to sort on (default: points). Order is always descending.
    * page - starts at 1 (default: 1)
    * pagesize - (default: 100)

    Returns list of objects with the following fields:
        userid, username, points, <action_types>
    """
    form = UserAPIForm(request.GET)
    if not form.is_valid():
        return {'success': False, 'errors': form.errors}

    daterange = form.cleaned_data.get('daterange') or '1y'
    sort = form.cleaned_data.get('sort') or 'points'
    page = form.cleaned_data.get('page') or 1
    pagesize = form.cleaned_data.get('pagesize') or 100

    mgr = KarmaManager()
    users = mgr.top_users(daterange=daterange,
                          type=sort,
                          count=pagesize,
                          offset=(page - 1) * pagesize) or []

    now = datetime.now()
    action_types = KarmaManager.action_types.keys()
    schema = ['id', 'username', 'lastactivity', 'points'] + action_types
    user_list = []
    for u in users:
        user = [u.id, u.username]
        last_activity = Answer.last_activity_for(u)
        user.append((now - last_activity).days if last_activity else None)
        user.append(mgr.count(u, daterange=daterange, type='points'))
        for t in action_types:
            user.append(mgr.count(u, daterange=daterange, type=t))
        user_list.append(user)

    return {'success': True, 'results': user_list, 'schema': schema}
Exemple #13
0
def user_num_solutions(user):
    """Count the number of solutions a user has.

    This means the number of answers the user has submitted that are then
    marked as the solution to the question they belong to.

    If karma is enabled, and redis is working, this will query that (much
    faster), otherwise it will just count objects in the database.
    """
    if waffle.switch_is_active('karma'):
        try:
            km = KarmaManager()
            count = km.count(user=user, type=SolutionAction.action_type)
            if count is not None:
                return count
        except RedisError as e:
            statsd.incr('redis.errror')
            log.error('Redis connection error: %s' % e)

    return Question.objects.filter(solution__in=Answer.objects
            .filter(creator=user)).count()
Exemple #14
0
def user_num_solutions(user):
    """Count the number of solutions a user has.

    This means the number of answers the user has submitted that are then
    marked as the solution to the question they belong to.

    If karma is enabled, and redis is working, this will query that (much
    faster), otherwise it will just count objects in the database.
    """
    if waffle.switch_is_active('karma'):
        try:
            km = KarmaManager()
            count = km.count(user=user, type=SolutionAction.action_type)
            if count is not None:
                return count
        except RedisError as e:
            statsd.incr('redis.errror')
            log.error('Redis connection error: %s' % e)

    return Question.objects.filter(solution__in=Answer.objects
            .filter(creator=user)).count()
Exemple #15
0
def users(request):
    """Returns list of user karma information.

    GET paramaters:
    * daterange - 7d, 1m, 3m, 6m or 1y (default: 1y)
    * sort - field to sort on (default: points). Order is always descending.
    * page - starts at 1 (default: 1)
    * pagesize - (default: 100)

    Returns list of objects with the following fields:
        userid, username, points, <action_types>
    """
    form = UserAPIForm(request.GET)
    if not form.is_valid():
        return {"success": False, "errors": form.errors}

    daterange = form.cleaned_data.get("daterange") or "1y"
    sort = form.cleaned_data.get("sort") or "points"
    page = form.cleaned_data.get("page") or 1
    pagesize = form.cleaned_data.get("pagesize") or 100

    mgr = KarmaManager()
    users = mgr.top_users(daterange, type=sort, count=pagesize, offset=(page - 1) * pagesize) or []

    now = datetime.now()
    action_types = KarmaManager.action_types.keys()
    schema = ["id", "username", "lastactivity", "points"] + action_types
    user_list = []
    for u in users:
        user = [u.id, u.username]
        last_activity = Answer.last_activity_for(u)
        user.append((now - last_activity).days if last_activity else None)
        user.append(mgr.count(daterange, u, type="points"))
        for t in action_types:
            user.append(mgr.count(daterange, u, type=t))
        user_list.append(user)

    return {"success": True, "results": user_list, "schema": schema}
Exemple #16
0
    def creator_num_answers(self):
        # If karma is enabled, try to use the karma backend (redis) to get
        # the number of answers. Fallback to database.
        if waffle.switch_is_active('karma'):
            try:
                count = KarmaManager().count(
                    user=self.creator, type=AnswerAction.action_type)
                if count != None:
                    return count
            except RedisError as e:
                statsd.incr('redis.errror')
                log.error('Redis connection error: %s' % e)

        return Answer.objects.filter(creator=self.creator).count()
Exemple #17
0
class KarmaManagerTests(TestCase):
    def setUp(self):
        super(KarmaManagerTests, self).setUp()
        self.user = user(save=True)
        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

    @mock.patch.object(waffle, 'switch_is_active')
    def test_recalculate_points(self, switch_is_active):
        """Test the recalculate_points method."""
        switch_is_active.return_value = True
        TestAction1(user=self.user).save()  # 3pts
        TestAction1(user=self.user).save()  # 3pts
        TestAction2(user=self.user).save()  # 7pts
        eq_(13, self.mgr.total_points(self.user))
        new_pts = {
            'test-action-1': 15,
            'test-action-2': 12
        }
        self.mgr.recalculate_points(self.user, new_pts)
        eq_(42, self.mgr.total_points(self.user))
Exemple #18
0
    def test_creator_nums_redis(self, switch_is_active):
        """Test creator_num_* pulled from karma data."""
        try:
            KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        switch_is_active.return_value = True
        answer = Answer.objects.all()[0]

        AnswerAction(answer.creator).save()
        AnswerAction(answer.creator).save()
        SolutionAction(answer.creator).save()

        eq_(answer.creator_num_solutions, 1)
        eq_(answer.creator_num_answers, 2)
Exemple #19
0
def questions(request):
    """View the questions."""

    filter_ = request.GET.get('filter')
    tagged = request.GET.get('tagged')
    tags = None
    sort_ = request.GET.get('sort')
    cache_count = True  # Some counts are too esoteric to cache right now.

    if sort_ == 'requested':
        order = '-num_votes_past_week'
    else:
        sort_ = None
        order = '-updated'

    question_qs = Question.objects.select_related(
        'creator', 'last_answer', 'last_answer__creator')
    question_qs = question_qs.extra(
        {'_num_votes': 'SELECT COUNT(*) FROM questions_questionvote WHERE '
                       'questions_questionvote.question_id = '
                       'questions_question.id'})
    question_qs = question_qs.filter(creator__is_active=1, is_locked=False)

    if filter_ == 'no-replies':
        question_qs = question_qs.filter(num_answers=0)
    elif filter_ == 'replies':
        question_qs = question_qs.filter(num_answers__gt=0)
    elif filter_ == 'solved':
        question_qs = question_qs.exclude(solution=None)
    elif filter_ == 'unsolved':
        question_qs = question_qs.filter(solution=None)
    elif filter_ == 'my-contributions' and request.user.is_authenticated():
        criteria = Q(answers__creator=request.user) | Q(creator=request.user)
        question_qs = question_qs.filter(criteria).distinct()
        cache_count = False
    else:
        filter_ = None

    feed_urls = ((reverse('questions.feed'),
                  QuestionsFeed().title()),)

    if tagged:
        cache_count = False
        tag_slugs = tagged.split(',')
        tags = Tag.objects.filter(slug__in=tag_slugs)
        if tags:
            for t in tags:
                question_qs = question_qs.filter(tags__name__in=[t.name])
            if len(tags) == 1:
                feed_urls += ((reverse('questions.tagged_feed',
                                       args=[tags[0].slug]),
                               TaggedQuestionsFeed().title(tags[0])),)
        else:
            question_qs = Question.objects.get_empty_query_set()

    question_qs = question_qs.order_by(order)

    if cache_count:
        cache_key = u'questions:count:%s' % filter_
        count = cache.get(cache_key)
        if not count:
            count = question_qs.count()
            cache.add(cache_key, count, settings.QUESTIONS_COUNT_TTL)
    else:
        count = question_qs.count()

    questions_ = paginate(request, question_qs, count=count,
                          per_page=constants.QUESTIONS_PER_PAGE)

    data = {'questions': questions_, 'feeds': feed_urls, 'filter': filter_,
            'sort': sort_, 'tags': tags, 'tagged': tagged}

    if (waffle.flag_is_active(request, 'karma') and
        waffle.switch_is_active('karma')):
        kmgr = KarmaManager()
        data.update(karma_top=kmgr.top_users())
        if request.user.is_authenticated():
            ranking = kmgr.ranking(request.user)
            if ranking <= constants.HIGHEST_RANKING:
                data.update(karma_ranking=ranking)
    else:
        data.update(top_contributors=_get_top_contributors())

    return jingo.render(request, 'questions/questions.html', data)
Exemple #20
0
def questions(request, template):
    """View the questions."""

    filter_ = request.GET.get("filter")
    tagged = request.GET.get("tagged")
    tags = None
    sort_ = request.GET.get("sort", None)
    product_slug = request.GET.get("product")

    if sort_ == "requested":
        order = ["-num_votes_past_week", "-_num_votes"]
    elif sort_ == "created":
        order = ["-created"]
    else:
        order = ["-updated"]

    if product_slug:
        product = get_object_or_404(Product, slug=product_slug)
    else:
        product = None

    question_qs = Question.objects.select_related("creator", "last_answer", "last_answer__creator")

    if not waffle.switch_is_active("hide-total-question-votes") or sort_ == "requested":
        question_qs = question_qs.extra(
            {
                "_num_votes": "SELECT COUNT(*) FROM questions_questionvote WHERE "
                "questions_questionvote.question_id = "
                "questions_question.id"
            }
        )

    question_qs = question_qs.filter(creator__is_active=1)

    if filter_ == "no-replies":
        question_qs = question_qs.filter(num_answers=0, is_locked=False)
    elif filter_ == "replies":
        question_qs = question_qs.filter(num_answers__gt=0)
    elif filter_ == "solved":
        question_qs = question_qs.exclude(solution=None)
    elif filter_ == "unsolved":
        question_qs = question_qs.filter(solution=None)
    elif filter_ == "my-contributions" and request.user.is_authenticated():
        criteria = Q(answers__creator=request.user) | Q(creator=request.user)
        question_qs = question_qs.filter(criteria).distinct()
    elif filter_ == "recent-unanswered":
        # Only unanswered questions from the last 72 hours.
        start = datetime.now() - timedelta(hours=72)
        question_qs = question_qs.filter(num_answers=0, created__gt=start, is_locked=False)
    else:
        filter_ = None

    feed_urls = ((reverse("questions.feed"), QuestionsFeed().title()),)

    if tagged:
        tag_slugs = tagged.split(",")
        tags = Tag.objects.filter(slug__in=tag_slugs)
        if tags:
            for t in tags:
                question_qs = question_qs.filter(tags__name__in=[t.name])
            if len(tags) == 1:
                feed_urls += (
                    (reverse("questions.tagged_feed", args=[tags[0].slug]), TaggedQuestionsFeed().title(tags[0])),
                )
        else:
            question_qs = Question.objects.get_empty_query_set()

    # Exclude questions over 90 days old without an answer.
    oldest_date = date.today() - timedelta(days=90)
    question_qs = question_qs.exclude(created__lt=oldest_date, num_answers=0)

    # Filter by product.
    if product:
        # This filter will match if any of the products on a question have the
        # correct id.
        question_qs = question_qs.filter(products__id__exact=product.id)

    # Set the order.
    question_qs = question_qs.order_by(*order)

    try:
        with statsd.timer("questions.view.paginate.%s" % filter_):
            questions_page = simple_paginate(request, question_qs, per_page=constants.QUESTIONS_PER_PAGE)
    except (PageNotAnInteger, EmptyPage):
        # If we aren't on page 1, redirect there.
        # TODO: Is 404 more appropriate?
        if request.GET.get("page", "1") != "1":
            url = build_paged_url(request)
            return HttpResponseRedirect(urlparams(url, page=1))

    # Recent answered stats
    recent_asked_count = Question.recent_asked_count()
    recent_unanswered_count = Question.recent_unanswered_count()
    if recent_asked_count:
        recent_answered_percent = int((float(recent_asked_count - recent_unanswered_count) / recent_asked_count) * 100)
    else:
        recent_answered_percent = 0

    # List of products to fill the selector.
    product_list = Product.objects.filter(visible=True)

    data = {
        "questions": questions_page,
        "feeds": feed_urls,
        "filter": filter_,
        "sort": sort_,
        "tags": tags,
        "tagged": tagged,
        "recent_asked_count": recent_asked_count,
        "recent_unanswered_count": recent_unanswered_count,
        "recent_answered_percent": recent_answered_percent,
        "product_list": product_list,
        "product": product,
    }

    if waffle.flag_is_active(request, "karma") and waffle.switch_is_active("karma"):
        kmgr = KarmaManager()
        data.update(karma_top=kmgr.top_users("3m"))
        if request.user.is_authenticated():
            ranking = kmgr.ranking("3m", request.user)
            if ranking <= constants.HIGHEST_RANKING:
                data.update(karma_ranking=ranking)
    else:
        data.update(top_contributors=_get_top_contributors())

    with statsd.timer("questions.view.render"):
        return jingo.render(request, template, data)
class KarmaManagerTests(TestCase):
    @mock.patch.object(waffle, 'switch_is_active')
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaManagerTests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        today = date.today()

        # user1 actions (3 + 3 + 7):
        TestAction1(user=self.user1, day=today).save()
        TestAction1(user=self.user1, day=today).save()
        TestAction2(user=self.user1, day=today).save()

        # user2 actions (3 + 7 + 7):
        TestAction1(user=self.user2, day=today - timedelta(days=8)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=32)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=360)).save()

        # user3 actions (3 + 3 + 3 + 7):
        TestAction1(user=self.user3, day=today - timedelta(days=10)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=40)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=190)).save()
        TestAction2(user=self.user3, day=today - timedelta(days=3)).save()

    @mock.patch.object(waffle, 'switch_is_active')
    def test_count(self, switch_is_active):
        """Test count method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(13, self.mgr.count(self.user1, type='points'))
        eq_(2, self.mgr.count(self.user1, type=TestAction1.action_type))
        eq_(1, self.mgr.count(self.user1, type=TestAction2.action_type))
        eq_(0, self.mgr.count(self.user2, type='points', daterange='1w'))
        eq_(3, self.mgr.count(self.user2, type='points', daterange='1m'))
        eq_(2, self.mgr.count(self.user2, type=TestAction2.action_type,
                              daterange='1y'))
        eq_(2, self.mgr.count(self.user3, type=TestAction1.action_type,
                              daterange='6m'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_top_users(self, switch_is_active):
        """Test top_users method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        u1, u2, u3 = self.user1, self.user2, self.user3
        eq_([u2, u3, u1], self.mgr.top_users())
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u1], self.mgr.top_users(type=TestAction1.action_type,
                                     daterange='1w'))
        eq_([u1, u3], self.mgr.top_users(daterange='1w'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_ranking(self, switch_is_active):
        """Test ranking method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(1, self.mgr.ranking(self.user2))
        eq_(3, self.mgr.ranking(self.user1))
        eq_(1, self.mgr.ranking(self.user1, daterange='1w'))
        eq_(1, self.mgr.ranking(self.user3, type=TestAction1.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_recalculate_points(self, switch_is_active):
        """Test the recalculate_points method."""
        switch_is_active.return_value = True

        # Create Points with new point values.
        p1 = Points.objects.create(action='test-action-1', points=15)
        Points.objects.create(action='test-action-2', points=12)

        self.mgr.recalculate_points(self.user1)
        eq_(42, self.mgr.count(self.user1, type='points'))

        # Update one of the Point values.
        p1.points = 30
        p1.save()

        self.mgr.recalculate_points(self.user1)
        eq_(72, self.mgr.count(self.user1, type='points'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_overview_counts(self, switch_is_active):
        """Verify the overview counts are correct."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(46, self.mgr.count(type='points'))
        eq_(6, self.mgr.count(type=TestAction1.action_type))
        eq_(4, self.mgr.count(type=TestAction2.action_type))
        eq_(2, self.mgr.count(type=TestAction1.action_type, daterange='1w'))
        eq_(2, self.mgr.count(type=TestAction2.action_type, daterange='1m'))
        eq_(3, self.mgr.count(type=TestAction2.action_type, daterange='6m'))
        eq_(2, self.mgr.day_count(type=TestAction1.action_type))
        eq_(1, self.mgr.day_count(type=TestAction2.action_type))
Exemple #22
0
class KarmaManagerTests(TestCase):
    @mock.patch.object(waffle, 'switch_is_active')
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaManagerTests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        today = date.today()

        # user1 actions (3 + 3 + 7):
        TestAction1(user=self.user1, day=today).save()
        TestAction1(user=self.user1, day=today).save()
        TestAction2(user=self.user1, day=today).save()

        # user2 actions (3 + 7 + 7):
        TestAction1(user=self.user2, day=today - timedelta(days=8)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=32)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=360)).save()

        # user3 actions (3 + 3 + 3 + 7):
        TestAction1(user=self.user3, day=today - timedelta(days=10)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=40)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=190)).save()
        TestAction2(user=self.user3, day=today - timedelta(days=3)).save()

    @mock.patch.object(waffle, 'switch_is_active')
    def test_count(self, switch_is_active):
        """Test count method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(13, self.mgr.count(self.user1, type='points'))
        eq_(2, self.mgr.count(self.user1, type=TestAction1.action_type))
        eq_(1, self.mgr.count(self.user1, type=TestAction2.action_type))
        eq_(0, self.mgr.count(self.user2, type='points', daterange='1w'))
        eq_(3, self.mgr.count(self.user2, type='points', daterange='1m'))
        eq_(2, self.mgr.count(self.user2, type=TestAction2.action_type,
                              daterange='1y'))
        eq_(2, self.mgr.count(self.user3, type=TestAction1.action_type,
                              daterange='6m'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_top_users(self, switch_is_active):
        """Test top_users method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        u1, u2, u3 = self.user1, self.user2, self.user3
        eq_([u2, u3, u1], self.mgr.top_users())
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u1], self.mgr.top_users(type=TestAction1.action_type,
                                     daterange='1w'))
        eq_([u1, u3], self.mgr.top_users(daterange='1w'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_ranking(self, switch_is_active):
        """Test ranking method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(1, self.mgr.ranking(self.user2))
        eq_(3, self.mgr.ranking(self.user1))
        eq_(1, self.mgr.ranking(self.user1, daterange='1w'))
        eq_(1, self.mgr.ranking(self.user3, type=TestAction1.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_recalculate_points(self, switch_is_active):
        """Test the recalculate_points method."""
        switch_is_active.return_value = True
        KarmaManager.action_types = {
            'test-action-1': 15,
            'test-action-2': 12
        }
        self.mgr.recalculate_points(self.user1)
        eq_(42, self.mgr.count(self.user1, type='points'))
Exemple #23
0
from karma.actions import KarmaAction
from karma.manager import KarmaManager


class TestAction1(KarmaAction):
    """A test action for testing!"""
    action_type = 'test-action-1'
    points = 3


class TestAction2(KarmaAction):
    """Another test action for testing!"""
    action_type = 'test-action-2'
    points = 7


KarmaManager.action_types = {}  # Clear them out for tests.
KarmaManager.register(TestAction1)
KarmaManager.register(TestAction2)
Exemple #24
0
class KarmaAPITests(TestCase):
    client_class = LocalizingClient

    @mock.patch.object(waffle, "switch_is_active")
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaAPITests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client("karma").flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        TestAction1(user=self.user1).save()
        TestAction2(user=self.user2).save()
        TestAction2(user=self.user2).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        self.mgr.update_top()

        self.client.login(username=self.user1.username, password="******")
        add_permission(self.user1, models.Title, "view_dashboard")

    @mock.patch.object(waffle, "switch_is_active")
    def test_user_api_no_permission(self, switch_is_active):
        """No view_dashboard permission? No API for you."""
        switch_is_active.return_value = True
        self.client.login(username=self.user2.username, password="******")
        url = reverse("karma.api.users")
        response = self.client.get(url)
        eq_(403, response.status_code)

    @mock.patch.object(waffle, "switch_is_active")
    def test_user_api_default(self, switch_is_active):
        """Test user API with all defaults."""
        switch_is_active.return_value = True
        url = reverse("karma.api.users")
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r["results"]]
        eq_([self.user2.id, self.user3.id, self.user1.id], user_ids)

    @mock.patch.object(waffle, "switch_is_active")
    def test_user_api_sort_testaction1(self, switch_is_active):
        """Test user API with sort = TestAction1."""
        switch_is_active.return_value = True
        url = reverse("karma.api.users")
        url = urlparams(url, sort=TestAction1.action_type)
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r["results"]]
        eq_([self.user3.id, self.user1.id], user_ids)

    @mock.patch.object(waffle, "switch_is_active")
    def test_user_api_sort_testaction2(self, switch_is_active):
        """Test user API with sort = TestAction2."""
        switch_is_active.return_value = True
        url = reverse("karma.api.users")
        url = urlparams(url, sort=TestAction2.action_type)
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r["results"]]
        eq_([self.user2.id], user_ids)
Exemple #25
0
def _process_recalculate_chunk(data):
    """Recalculate karma points for a chunk of user ids."""
    mgr = KarmaManager()
    for userid in data:
        mgr.recalculate_points(userid)
Exemple #26
0
class FirstAnswerAction(KarmaAction):
    """The user posted the first answer to a question."""
    action_type = 'first-answer'
    points = 5


class AnswerMarkedHelpfulAction(KarmaAction):
    """The user's answer was voted as helpful."""
    action_type = 'helpful-answer'
    points = 10


class AnswerMarkedNotHelpfulAction(KarmaAction):
    """The user's answer was voted as not helpful."""
    action_type = 'nothelpful-answer'
    points = -10


class SolutionAction(KarmaAction):
    """The user's answer was marked as the solution."""
    action_type = 'solution'
    points = 25


KarmaManager.register(AnswerAction)
KarmaManager.register(FirstAnswerAction)
KarmaManager.register(AnswerMarkedHelpfulAction)
KarmaManager.register(AnswerMarkedNotHelpfulAction)
KarmaManager.register(SolutionAction)
Exemple #27
0
 def _save(self, redis=None):
     statsd.incr('karma.{t}'.format(t=self.action_type))
     KarmaManager(redis).save_action(self)
Exemple #28
0
 def _delete(self):
     statsd.incr('karma.delete.{t}'.format(t=self.action_type))
     KarmaManager().delete_action(self)
Exemple #29
0
    action_type = "first-answer"
    points = 5


class AnswerMarkedHelpfulAction(KarmaAction):
    """The user's answer was voted as helpful."""

    action_type = "helpful-answer"
    points = 10


class AnswerMarkedNotHelpfulAction(KarmaAction):
    """The user's answer was voted as not helpful."""

    action_type = "nothelpful-answer"
    points = -10


class SolutionAction(KarmaAction):
    """The user's answer was marked as the solution."""

    action_type = "solution"
    points = 25


KarmaManager.register(AnswerAction)
KarmaManager.register(FirstAnswerAction)
KarmaManager.register(AnswerMarkedHelpfulAction)
KarmaManager.register(AnswerMarkedNotHelpfulAction)
KarmaManager.register(SolutionAction)
Exemple #30
0
def questions(request):
    """View the questions."""

    filter_ = request.GET.get('filter')
    tagged = request.GET.get('tagged')
    tags = None
    sort_ = request.GET.get('sort', None)

    if sort_ == 'requested':
        order = '-num_votes_past_week'
    elif sort_ == 'created':
        order = '-created'
    else:
        order = '-updated'

    question_qs = Question.objects.select_related('creator', 'last_answer',
                                                  'last_answer__creator')

    if not waffle.switch_is_active('hide-total-question-votes'):
        question_qs = question_qs.extra({
            '_num_votes':
            'SELECT COUNT(*) FROM questions_questionvote WHERE '
            'questions_questionvote.question_id = '
            'questions_question.id'
        })

    question_qs = question_qs.filter(creator__is_active=1)

    if filter_ == 'no-replies':
        question_qs = question_qs.filter(num_answers=0, is_locked=False)
    elif filter_ == 'replies':
        question_qs = question_qs.filter(num_answers__gt=0)
    elif filter_ == 'solved':
        question_qs = question_qs.exclude(solution=None)
    elif filter_ == 'unsolved':
        question_qs = question_qs.filter(solution=None)
    elif filter_ == 'my-contributions' and request.user.is_authenticated():
        criteria = Q(answers__creator=request.user) | Q(creator=request.user)
        question_qs = question_qs.filter(criteria).distinct()
    elif filter_ == 'recent-unanswered':
        # Only unanswered questions from the last 72 hours.
        start = datetime.now() - timedelta(hours=72)
        question_qs = question_qs.filter(num_answers=0,
                                         created__gt=start,
                                         is_locked=False)
    else:
        filter_ = None

    feed_urls = ((reverse('questions.feed'), QuestionsFeed().title()), )

    if tagged:
        tag_slugs = tagged.split(',')
        tags = Tag.objects.filter(slug__in=tag_slugs)
        if tags:
            for t in tags:
                question_qs = question_qs.filter(tags__name__in=[t.name])
            if len(tags) == 1:
                feed_urls += ((reverse('questions.tagged_feed',
                                       args=[tags[0].slug]),
                               TaggedQuestionsFeed().title(tags[0])), )
        else:
            question_qs = Question.objects.get_empty_query_set()

    # Exclude questions over 90 days old without an answer.
    oldest_date = date.today() - timedelta(days=90)
    question_qs = question_qs.exclude(created__lt=oldest_date, num_answers=0)

    # Set the order.
    question_qs = question_qs.order_by(order)

    try:
        with statsd.timer('questions.view.paginate.%s' % filter_):
            questions_page = simple_paginate(
                request, question_qs, per_page=constants.QUESTIONS_PER_PAGE)
    except (PageNotAnInteger, EmptyPage):
        # If we aren't on page 1, redirect there.
        # TODO: Is 404 more appropriate?
        if request.GET.get('page', '1') != '1':
            url = build_paged_url(request)
            return HttpResponseRedirect(urlparams(url, page=1))

    # Recent answered stats
    recent_asked_count = Question.recent_asked_count()
    recent_unanswered_count = Question.recent_unanswered_count()
    if recent_asked_count:
        recent_answered_percent = int(
            (float(recent_asked_count - recent_unanswered_count) /
             recent_asked_count) * 100)
    else:
        recent_answered_percent = 0

    data = {
        'questions': questions_page,
        'feeds': feed_urls,
        'filter': filter_,
        'sort': sort_,
        'tags': tags,
        'tagged': tagged,
        'recent_asked_count': recent_asked_count,
        'recent_unanswered_count': recent_unanswered_count,
        'recent_answered_percent': recent_answered_percent
    }

    if (waffle.flag_is_active(request, 'karma')
            and waffle.switch_is_active('karma')):
        kmgr = KarmaManager()
        data.update(karma_top=kmgr.top_users())
        if request.user.is_authenticated():
            ranking = kmgr.ranking(request.user)
            if ranking <= constants.HIGHEST_RANKING:
                data.update(karma_ranking=ranking)
    else:
        data.update(top_contributors=_get_top_contributors())

    with statsd.timer('questions.view.render'):
        return jingo.render(request, 'questions/questions.html', data)
Exemple #31
0
class KarmaAPITests(TestCase):
    client_class = LocalizingClient

    @mock.patch.object(waffle, 'switch_is_active')
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaAPITests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        TestAction1(user=self.user1).save()
        TestAction2(user=self.user2).save()
        TestAction2(user=self.user2).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        TestAction1(user=self.user3).save()
        self.mgr.update_top()

        self.client.login(username=self.user1.username, password='******')
        add_permission(self.user1, models.Title, 'view_dashboard')

    @mock.patch.object(waffle, 'switch_is_active')
    def test_user_api_no_permission(self, switch_is_active):
        """No view_dashboard permission? No API for you."""
        switch_is_active.return_value = True
        self.client.login(username=self.user2.username, password='******')
        url = reverse('karma.api.users')
        response = self.client.get(url)
        eq_(403, response.status_code)

    @mock.patch.object(waffle, 'switch_is_active')
    def test_user_api_default(self, switch_is_active):
        """Test user API with all defaults."""
        switch_is_active.return_value = True
        url = reverse('karma.api.users')
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r['results']]
        eq_([self.user2.id, self.user3.id, self.user1.id], user_ids)

    @mock.patch.object(waffle, 'switch_is_active')
    def test_user_api_sort_testaction1(self, switch_is_active):
        """Test user API with sort = TestAction1."""
        switch_is_active.return_value = True
        url = reverse('karma.api.users')
        url = urlparams(url, sort=TestAction1.action_type)
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r['results']]
        eq_([self.user3.id, self.user1.id], user_ids)

    @mock.patch.object(waffle, 'switch_is_active')
    def test_user_api_sort_testaction2(self, switch_is_active):
        """Test user API with sort = TestAction2."""
        switch_is_active.return_value = True
        url = reverse('karma.api.users')
        url = urlparams(url, sort=TestAction2.action_type)
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        user_ids = [u[0] for u in r['results']]
        eq_([self.user2.id], user_ids)

    @mock.patch.object(waffle, 'switch_is_active')
    def test_user_api_last_activity(self, switch_is_active):
        """Verify the last activity field."""
        switch_is_active.return_value = True

        now = datetime.now()
        one_day = now - timedelta(days=1)
        two_days = now - timedelta(days=2)

        answer(creator=self.user1, created=now, save=True)
        answer(creator=self.user2, created=one_day, save=True)
        answer(creator=self.user3, created=two_days, save=True)

        url = reverse('karma.api.users')
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        days_since_last_activity = [u[2] for u in r['results']]
        eq_([1, 2, 0], days_since_last_activity)

    @mock.patch.object(waffle, 'switch_is_active')
    def test_overview_api(self, switch_is_active):
        """Test overview API."""
        switch_is_active.return_value = True
        url = reverse('karma.api.overview')
        url = urlparams(url, daterange='6m')
        response = self.client.get(url)
        eq_(200, response.status_code)
        r = json.loads(response.content)
        overview = r['overview']
        eq_(4, overview['test-action-1'])
        eq_(2, overview['test-action-2'])
Exemple #32
0
class KarmaManagerTests(TestCase):
    @mock.patch.object(waffle, 'switch_is_active')
    def setUp(self, switch_is_active):
        switch_is_active.return_value = True

        super(KarmaManagerTests, self).setUp()

        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

        self.user1 = user(save=True)
        self.user2 = user(save=True)
        self.user3 = user(save=True)

        today = date.today()

        # user1 actions (3 + 3 + 7):
        TestAction1(user=self.user1, day=today).save()
        TestAction1(user=self.user1, day=today).save()
        TestAction2(user=self.user1, day=today).save()

        # user2 actions (3 + 7 + 7):
        TestAction1(user=self.user2, day=today - timedelta(days=8)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=32)).save()
        TestAction2(user=self.user2, day=today - timedelta(days=360)).save()

        # user3 actions (3 + 3 + 3 + 7):
        TestAction1(user=self.user3, day=today - timedelta(days=10)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=40)).save()
        TestAction1(user=self.user3, day=today - timedelta(days=190)).save()
        TestAction2(user=self.user3, day=today - timedelta(days=3)).save()

    @mock.patch.object(waffle, 'switch_is_active')
    def test_count(self, switch_is_active):
        """Test count method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(13, self.mgr.count(self.user1, type='points'))
        eq_(2, self.mgr.count(self.user1, type=TestAction1.action_type))
        eq_(1, self.mgr.count(self.user1, type=TestAction2.action_type))
        eq_(0, self.mgr.count(self.user2, type='points', daterange='1w'))
        eq_(3, self.mgr.count(self.user2, type='points', daterange='1m'))
        eq_(
            2,
            self.mgr.count(self.user2,
                           type=TestAction2.action_type,
                           daterange='1y'))
        eq_(
            2,
            self.mgr.count(self.user3,
                           type=TestAction1.action_type,
                           daterange='6m'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_top_users(self, switch_is_active):
        """Test top_users method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        u1, u2, u3 = self.user1, self.user2, self.user3
        eq_([u2, u3, u1], self.mgr.top_users())
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u3, u1, u2], self.mgr.top_users(type=TestAction1.action_type))
        eq_([u1],
            self.mgr.top_users(type=TestAction1.action_type, daterange='1w'))
        eq_([u1, u3], self.mgr.top_users(daterange='1w'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_ranking(self, switch_is_active):
        """Test ranking method."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(1, self.mgr.ranking(self.user2))
        eq_(3, self.mgr.ranking(self.user1))
        eq_(1, self.mgr.ranking(self.user1, daterange='1w'))
        eq_(1, self.mgr.ranking(self.user3, type=TestAction1.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_recalculate_points(self, switch_is_active):
        """Test the recalculate_points method."""
        switch_is_active.return_value = True
        KarmaManager.action_types = {'test-action-1': 15, 'test-action-2': 12}
        self.mgr.recalculate_points(self.user1)
        eq_(42, self.mgr.count(self.user1, type='points'))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_overview_counts(self, switch_is_active):
        """Verify the overview counts are correct."""
        switch_is_active.return_value = True
        self.mgr.update_top()
        eq_(46, self.mgr.count(type='points'))
        eq_(6, self.mgr.count(type=TestAction1.action_type))
        eq_(4, self.mgr.count(type=TestAction2.action_type))
        eq_(2, self.mgr.count(type=TestAction1.action_type, daterange='1w'))
        eq_(2, self.mgr.count(type=TestAction2.action_type, daterange='1m'))
        eq_(3, self.mgr.count(type=TestAction2.action_type, daterange='6m'))
        eq_(2, self.mgr.day_count(type=TestAction1.action_type))
        eq_(1, self.mgr.day_count(type=TestAction2.action_type))
Exemple #33
0
class KarmaActionTests(TestCase):
    def setUp(self):
        super(KarmaActionTests, self).setUp()
        self.user = user(save=True)
        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

    @mock.patch.object(waffle, 'switch_is_active')
    def test_action(self, switch_is_active):
        """Save an action and verify."""
        switch_is_active.return_value = True
        TestAction1(user=self.user).save()
        eq_(3, self.mgr.count('all', self.user, type='points'))
        eq_(1, self.mgr.count('all', self.user, type=TestAction1.action_type))
        today = date.today()
        eq_(1, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(1, self.mgr.month_count(self.user, today.year,
                                    today.month, TestAction1.action_type))
        eq_(1, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_two_actions(self, switch_is_active):
        """Save two actions, one twice, and verify."""
        switch_is_active.return_value = True
        TestAction1(user=self.user).save()
        TestAction2(user=self.user).save()
        TestAction2(user=self.user).save()
        eq_(17, self.mgr.count('all', self.user, type='points'))
        eq_(1, self.mgr.count('all', self.user, type=TestAction1.action_type))
        eq_(2, self.mgr.count('all', self.user, type=TestAction2.action_type))
        today = date.today()
        eq_(1, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(1, self.mgr.month_count(self.user, today.year, today.month,
                                    TestAction1.action_type))
        eq_(1, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))
        eq_(2, self.mgr.day_count(self.user, today, TestAction2.action_type))
        eq_(2, self.mgr.month_count(self.user, today.year, today.month,
                                    TestAction2.action_type))
        eq_(2, self.mgr.year_count(self.user, today.year,
                                   TestAction2.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_delete_action(self, switch_is_active):
        """Save two actions, one twice, and verify."""
        switch_is_active.return_value = True
        today = date.today()

        # Create two TestAction1s and verify counts.
        TestAction1(user=self.user).save()
        TestAction1(user=self.user).save()
        eq_(6, self.mgr.count('all', self.user, type='points'))
        eq_(2, self.mgr.count('all', self.user, type=TestAction1.action_type))
        today = date.today()
        eq_(2, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(2, self.mgr.month_count(self.user, today.year,
                                    today.month, TestAction1.action_type))
        eq_(2, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))

        # Delete one and verify new counts
        TestAction1(user=self.user).delete()
        eq_(3, self.mgr.count('all', self.user, type='points'))
        eq_(1, self.mgr.count('all', self.user, type=TestAction1.action_type))
        today = date.today()
        eq_(1, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(1, self.mgr.month_count(self.user, today.year,
                                    today.month, TestAction1.action_type))
        eq_(1, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))

        # Delete the other and verify all zeroes
        TestAction1(user=self.user).delete()
        eq_(0, self.mgr.count('all', self.user, type='points'))
        eq_(0, self.mgr.count('all', self.user, type=TestAction1.action_type))
        today = date.today()
        eq_(0, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(0, self.mgr.month_count(self.user, today.year,
                                    today.month, TestAction1.action_type))
        eq_(0, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))
Exemple #34
0
def questions(request):
    """View the questions."""

    filter_ = request.GET.get('filter')
    tagged = request.GET.get('tagged')
    tags = None
    sort_ = request.GET.get('sort')
    cache_count = True  # Some counts are too esoteric to cache right now.

    if sort_ == 'requested':
        order = '-num_votes_past_week'
    else:
        sort_ = None
        order = '-updated'

    question_qs = Question.objects.select_related(
        'creator', 'last_answer', 'last_answer__creator')
    question_qs = question_qs.extra(
        {'_num_votes': 'SELECT COUNT(*) FROM questions_questionvote WHERE '
                       'questions_questionvote.question_id = '
                       'questions_question.id'})
    question_qs = question_qs.filter(creator__is_active=1, is_locked=False)

    if filter_ == 'no-replies':
        question_qs = question_qs.filter(num_answers=0)
    elif filter_ == 'replies':
        question_qs = question_qs.filter(num_answers__gt=0)
    elif filter_ == 'solved':
        question_qs = question_qs.exclude(solution=None)
    elif filter_ == 'unsolved':
        question_qs = question_qs.filter(solution=None)
    elif filter_ == 'my-contributions' and request.user.is_authenticated():
        criteria = Q(answers__creator=request.user) | Q(creator=request.user)
        question_qs = question_qs.filter(criteria).distinct()
        cache_count = False
    else:
        filter_ = None

    feed_urls = ((reverse('questions.feed'),
                  QuestionsFeed().title()),)

    if tagged:
        cache_count = False
        tag_slugs = tagged.split(',')
        tags = Tag.objects.filter(slug__in=tag_slugs)
        if tags:
            for t in tags:
                question_qs = question_qs.filter(tags__name__in=[t.name])
            if len(tags) == 1:
                feed_urls += ((reverse('questions.tagged_feed',
                                       args=[tags[0].slug]),
                               TaggedQuestionsFeed().title(tags[0])),)
        else:
            question_qs = Question.objects.get_empty_query_set()

    question_qs = question_qs.order_by(order)

    if cache_count:
        cache_key = u'questions:count:%s' % filter_
        count = cache.get(cache_key)
        if not count:
            count = question_qs.count()
            cache.add(cache_key, count, settings.QUESTIONS_COUNT_TTL)
    else:
        count = question_qs.count()

    questions_ = paginate(request, question_qs, count=count,
                          per_page=constants.QUESTIONS_PER_PAGE)

    data = {'questions': questions_, 'feeds': feed_urls, 'filter': filter_,
            'sort': sort_, 'tags': tags, 'tagged': tagged}

    if (waffle.flag_is_active(request, 'karma') and
        waffle.switch_is_active('karma')):
        kmgr = KarmaManager()
        data.update(karma_top=kmgr.top_users())
        if request.user.is_authenticated():
            ranking = kmgr.ranking(request.user)
            if ranking <= constants.HIGHEST_RANKING:
                data.update(karma_ranking=ranking)
    else:
        data.update(top_contributors=_get_top_contributors())

    return jingo.render(request, 'questions/questions.html', data)
Exemple #35
0
def questions(request, template):
    """View the questions."""

    filter_ = request.GET.get('filter')
    tagged = request.GET.get('tagged')
    tags = None
    sort_ = request.GET.get('sort', None)

    if sort_ == 'requested':
        order = '-num_votes_past_week'
    elif sort_ == 'created':
        order = '-created'
    else:
        order = '-updated'

    question_qs = Question.objects.select_related(
        'creator', 'last_answer', 'last_answer__creator')

    if not waffle.switch_is_active('hide-total-question-votes'):
        question_qs = question_qs.extra(
            {'_num_votes': 'SELECT COUNT(*) FROM questions_questionvote WHERE '
                           'questions_questionvote.question_id = '
                           'questions_question.id'})

    question_qs = question_qs.filter(creator__is_active=1)

    if filter_ == 'no-replies':
        question_qs = question_qs.filter(num_answers=0, is_locked=False)
    elif filter_ == 'replies':
        question_qs = question_qs.filter(num_answers__gt=0)
    elif filter_ == 'solved':
        question_qs = question_qs.exclude(solution=None)
    elif filter_ == 'unsolved':
        question_qs = question_qs.filter(solution=None)
    elif filter_ == 'my-contributions' and request.user.is_authenticated():
        criteria = Q(answers__creator=request.user) | Q(creator=request.user)
        question_qs = question_qs.filter(criteria).distinct()
    elif filter_ == 'recent-unanswered':
        # Only unanswered questions from the last 72 hours.
        start = datetime.now() - timedelta(hours=72)
        question_qs = question_qs.filter(
            num_answers=0, created__gt=start, is_locked=False)
    else:
        filter_ = None

    feed_urls = ((reverse('questions.feed'),
                  QuestionsFeed().title()),)

    if tagged:
        tag_slugs = tagged.split(',')
        tags = Tag.objects.filter(slug__in=tag_slugs)
        if tags:
            for t in tags:
                question_qs = question_qs.filter(tags__name__in=[t.name])
            if len(tags) == 1:
                feed_urls += ((reverse('questions.tagged_feed',
                                       args=[tags[0].slug]),
                               TaggedQuestionsFeed().title(tags[0])),)
        else:
            question_qs = Question.objects.get_empty_query_set()

    # Exclude questions over 90 days old without an answer.
    oldest_date = date.today() - timedelta(days=90)
    question_qs = question_qs.exclude(created__lt=oldest_date, num_answers=0)

    # Set the order.
    question_qs = question_qs.order_by(order)

    try:
        with statsd.timer('questions.view.paginate.%s' % filter_):
            questions_page = simple_paginate(
                request, question_qs, per_page=constants.QUESTIONS_PER_PAGE)
    except (PageNotAnInteger, EmptyPage):
        # If we aren't on page 1, redirect there.
        # TODO: Is 404 more appropriate?
        if request.GET.get('page', '1') != '1':
            url = build_paged_url(request)
            return HttpResponseRedirect(urlparams(url, page=1))

    # Recent answered stats
    recent_asked_count = Question.recent_asked_count()
    recent_unanswered_count = Question.recent_unanswered_count()
    if recent_asked_count:
        recent_answered_percent = int(
            (float(recent_asked_count - recent_unanswered_count) /
            recent_asked_count) * 100)
    else:
        recent_answered_percent = 0

    data = {'questions': questions_page,
            'feeds': feed_urls,
            'filter': filter_,
            'sort': sort_,
            'tags': tags,
            'tagged': tagged,
            'recent_asked_count': recent_asked_count,
            'recent_unanswered_count': recent_unanswered_count,
            'recent_answered_percent': recent_answered_percent}

    if (waffle.flag_is_active(request, 'karma') and
        waffle.switch_is_active('karma')):
        kmgr = KarmaManager()
        data.update(karma_top=kmgr.top_users('3m'))
        if request.user.is_authenticated():
            ranking = kmgr.ranking('3m', request.user)
            if ranking <= constants.HIGHEST_RANKING:
                data.update(karma_ranking=ranking)
    else:
        data.update(top_contributors=_get_top_contributors())

    with statsd.timer('questions.view.render'):
        return jingo.render(request, template, data)
Exemple #36
0
class KarmaActionTests(TestCase):
    def setUp(self):
        super(KarmaActionTests, self).setUp()
        self.user = user(save=True)
        try:
            self.mgr = KarmaManager()
            redis_client('karma').flushdb()
        except RedisError:
            raise SkipTest

    @mock.patch.object(waffle, 'switch_is_active')
    def test_action(self, switch_is_active):
        """Save an action and verify."""
        switch_is_active.return_value = True
        TestAction1(user=self.user).save()
        eq_(3, self.mgr.count(self.user, type='points'))
        eq_(1, self.mgr.count(self.user, type=TestAction1.action_type))
        today = date.today()
        eq_(1, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(1, self.mgr.month_count(self.user, today.year,
                                    today.month, TestAction1.action_type))
        eq_(1, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))

    @mock.patch.object(waffle, 'switch_is_active')
    def test_two_actions(self, switch_is_active):
        """Save two actions, one twice, and verify."""
        switch_is_active.return_value = True
        TestAction1(user=self.user).save()
        TestAction2(user=self.user).save()
        TestAction2(user=self.user).save()
        eq_(17, self.mgr.count(self.user, type='points'))
        eq_(1, self.mgr.count(self.user, type=TestAction1.action_type))
        eq_(2, self.mgr.count(self.user, type=TestAction2.action_type))
        today = date.today()
        eq_(1, self.mgr.day_count(self.user, today, TestAction1.action_type))
        eq_(1, self.mgr.month_count(self.user, today.year, today.month,
                                    TestAction1.action_type))
        eq_(1, self.mgr.year_count(self.user, today.year,
                                   TestAction1.action_type))
        eq_(2, self.mgr.day_count(self.user, today, TestAction2.action_type))
        eq_(2, self.mgr.month_count(self.user, today.year, today.month,
                                    TestAction2.action_type))
        eq_(2, self.mgr.year_count(self.user, today.year,
                                   TestAction2.action_type))