Some ad changes around opting out. (#2951)
* Allow users to opt out of ads * Small update to verbage * Properly filter opted out users * Add boolean instead for community ads. * Add opted out projects as community only as well * Small wording change * Make user opt out follow same defaults/verbage as projectscom-py3-compat
parent
7d586be5e7
commit
053b54d64d
|
@ -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)
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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.'),
|
||||
|
|
|
@ -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'),
|
||||
),
|
||||
]
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
|
|
@ -4,13 +4,14 @@ import json
|
|||
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)
|
||||
|
@ -184,6 +185,28 @@ class FooterTests(TestCase):
|
|||
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):
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue