Skip to content

Some ad changes around opting out. #2951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion readthedocs/core/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class UserProfileForm(forms.ModelForm):
class Meta(object):
model = UserProfile
# Don't allow users edit someone else's user page,
fields = ['first_name', 'last_name', 'homepage']
fields = ['first_name', 'last_name', 'homepage', 'allow_ads']

def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
Expand Down
28 changes: 28 additions & 0 deletions readthedocs/core/migrations/0004_ad-opt-out.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-06-14 18:06
from __future__ import unicode_literals

import annoying.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0003_add_banned_status'),
]

operations = [
migrations.AddField(
model_name='userprofile',
name='allow_ads',
field=models.BooleanField(default=True, help_text='If unchecked, you will still see community ads.', verbose_name='See paid advertising'),
),
migrations.AlterField(
model_name='userprofile',
name='user',
field=annoying.fields.AutoOneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL, verbose_name='User'),
),
]
4 changes: 4 additions & 0 deletions readthedocs/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class UserProfile (models.Model):
whitelisted = models.BooleanField(_('Whitelisted'), default=False)
banned = models.BooleanField(_('Banned'), default=False)
homepage = models.CharField(_('Homepage'), max_length=100, blank=True)
allow_ads = models.BooleanField(_('See paid advertising'),
help_text=_('If unchecked, you will still see community ads.'),
default=True,
)
allow_email = models.BooleanField(_('Allow email'),
help_text=_('Show your email on VCS '
'contributions.'),
Expand Down
20 changes: 20 additions & 0 deletions readthedocs/donate/migrations/0012_add-community-ads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-06-14 17:48
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('donate', '0011_add-theme-filter'),
]

operations = [
migrations.AddField(
model_name='supporterpromo',
name='community',
field=models.BooleanField(default=False, verbose_name='Community Ad'),
),
]
1 change: 1 addition & 0 deletions readthedocs/donate/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class SupporterPromo(models.Model):
theme = models.CharField(_('Theme'), max_length=40,
choices=THEMES, default=READTHEDOCS_THEME,
blank=True, null=True)
community = models.BooleanField(_('Community Ad'), default=False)
live = models.BooleanField(_('Live'), default=False)

class Meta(object):
Expand Down
20 changes: 16 additions & 4 deletions readthedocs/donate/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ def choose_promo(promo_list):
return None


def get_promo(country_code, programming_language, theme, gold_project=False, gold_user=False):
def get_promo(country_code, programming_language, theme,
gold_project=False, gold_user=False, community_only=False):
"""
Get a proper promo.

Expand All @@ -104,6 +105,9 @@ def get_promo(country_code, programming_language, theme, gold_project=False, gol
"""
promo_queryset = SupporterPromo.objects.filter(live=True, display_type='doc')

if community_only:
promo_queryset = promo_queryset.filter(community=True)

filtered_promos = []
for promo in promo_queryset:
# Break out if we aren't meant to show to this language
Expand Down Expand Up @@ -157,6 +161,15 @@ def is_gold_project(project):
return project.gold_owners.count()


def is_community_only(user, project):
"""Return True is this project or user should only be shown community ads"""
if user.is_authenticated() and user.profile.as_opt_out:
return True
if not project.allow_promos:
return True
return False


def get_user_country(request):
"""Return the ISO country code from geo-IP data, or None if not found."""
if not PROMO_GEO_PATH:
Expand Down Expand Up @@ -200,11 +213,9 @@ def lookup_promo(request, project, theme):
if no promo should be shown.

"""
if not project.allow_promos:
return None

gold_user = is_gold_user(request.user)
gold_project = is_gold_project(project)
community_only = is_community_only(request.user, project)

# Don't show promos to gold users or on gold projects for now
# (Some day we may show them something customised for them)
Expand All @@ -217,6 +228,7 @@ def lookup_promo(request, project, theme):
theme=theme,
gold_project=gold_project,
gold_user=gold_user,
community_only=community_only,
)

# If we don't have anything to show, don't show it.
Expand Down
25 changes: 24 additions & 1 deletion readthedocs/donate/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import mock

from builtins import range
from django.contrib.auth.models import User
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.core.cache import cache
from django.test.client import RequestFactory
from django_dynamic_fixture import get

from readthedocs.core.middleware import FooterNoSessionMiddleware
from .core.middleware import FooterNoSessionMiddleware
from .models import SupporterPromo, GeoFilter, Country
from .constants import (CLICKS, VIEWS, OFFERS,
INCLUDE, EXCLUDE)
Expand Down Expand Up @@ -184,6 +185,28 @@ def test_project_disabling(self):
resp = json.loads(r.content)
self.assertEqual(resp['promo'], False)

def test_user_disabling(self):
"""Test that the promo doesn't show when the project has it disabled"""
user = User.objects.get(username='test')
user.profile.allow_ads = False
user.profile.save()

# No ads for logged in user
self.login('test', 'test')
r = self.client.get(
'/api/v2/footer_html/?project=pip&version=latest&page=index'
)
resp = json.loads(r.content)
self.assertEqual(resp['promo'], False)

# Ads for logged out user
self.logout()
r = self.client.get(
'/api/v2/footer_html/?project=pip&version=latest&page=index'
)
resp = json.loads(r.content)
self.assertTrue(resp['promo'] is not False)


class FilterTests(TestCase):

Expand Down
4 changes: 2 additions & 2 deletions readthedocs/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ class Project(models.Model):
build_queue = models.CharField(
_('Alternate build queue id'), max_length=32, null=True, blank=True)
allow_promos = models.BooleanField(
_('Sponsor advertisements'), default=True, help_text=_(
"Allow sponsor advertisements on my project documentation"))
_('Allow paid advertising'), default=True, help_text=_(
"If unchecked, users will still see community ads."))

# Sphinx specific build options.
enable_epub_build = models.BooleanField(
Expand Down