Replace some static settings by dynamic settings

master
Alice 7 years ago
parent 6574ba2640
commit 7d7742bdd0

@ -1,4 +1,6 @@
from django.conf import settings
from constance import config
from datetime import timedelta
def get_client_ip(request):
@ -11,3 +13,24 @@ def get_client_ip(request):
return value.split(',', 1)[0]
return request.META.get('REMOTE_ADDR')
def get_price():
return config.MONTHLY_PRICE_EUR
def get_price_float():
return get_price() / 100
def get_trial_period_duration():
return config.TRIAL_PERIOD_HOURS * timedelta(hours=1)
def parse_integer_list(ls):
l = ls.split(',')
l = [p.strip() for p in l]
l = [p for p in l if p]
l = [int(p) for p in l]
return l

@ -13,7 +13,8 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from datetime import timedelta
from django.core.validators import RegexValidator
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -43,6 +44,8 @@ INSTALLED_APPS = (
'lambdainst',
'payments',
'tickets',
'constance',
'constance.backends.database',
)
MIDDLEWARE_CLASSES = (
@ -229,10 +232,24 @@ PAYMENTS_BACKENDS = {
}
PAYMENTS_CURRENCY = ('eur', '')
PAYMENTS_MONTHLY_PRICE = 300 # in currency*100
TRIAL_PERIOD = timedelta(hours=2) # Time added on each trial awarded
TRIAL_PERIOD_LIMIT = 2 # 2 * 2h = 4h, still has to push the button twice
NOTIFY_DAYS_BEFORE = (3, 1) # notify twice: 3 and 1 days before expiration
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
CONSTANCE_CONFIG = {
'MOTD': ('', "Public site message, displayed on homepage"),
'MOTD_USER': ('', "Message for users, displayed on account home"),
'MONTHLY_PRICE_EUR': (300, "Base subscription price per month (x0.01€)"),
'BTC_EUR_VALUE': (300000, "Current value of a bitcoin (x0.01€/btc)"),
'TRIAL_PERIOD_HOURS': (2, "Hours given for each trial period"),
'TRIAL_PERIOD_MAX': (84, "Maximum number of trial periods to give (84*2h=1w)"),
'NOTIFY_DAYS_BEFORE': ("3, 1", "When to send account expiration notifications. In number of days before, separated y commas",
'integer_list'),
}
CONSTANCE_ADDITIONAL_FIELDS = {
'integer_list': ['django.forms.fields.CharField', {
'validators': [RegexValidator(r'^([0-9]+[ ,]+)*([0-9]+)?$')],
}],
}
# Local settings

@ -10,14 +10,17 @@ from django.utils.http import is_safe_url
from django.utils.translation import (
LANGUAGE_SESSION_KEY, check_for_language,
)
from constance import config
from .common import get_price_float
md = markdown.Markdown(extensions=['toc', 'meta', 'codehilite(noclasses=True)'])
def index(request):
eur = '%.2f' % (settings.PAYMENTS_MONTHLY_PRICE / 100)
return render(request, 'ccvpn/index.html', dict(eur_price=eur))
eur = '%.2f' % get_price_float()
return render(request, 'ccvpn/index.html', dict(eur_price=eur, motd=config.MOTD))
def chat(request):

@ -7,15 +7,14 @@ from django.conf import settings
from django.utils import timezone
from django.template.loader import get_template
from django.core.mail import send_mass_mail
from constance import config as site_config
from ccvpn.common import parse_integer_list
from lambdainst.models import VPNUser
ROOT_URL = settings.ROOT_URL
SITE_NAME = settings.TICKETS_SITE_NAME
NOTIFY_DAYS_BEFORE = settings.NOTIFY_DAYS_BEFORE
assert isinstance(NOTIFY_DAYS_BEFORE, (list, tuple, set))
def get_next_expirations(days=3):
""" Gets users whose subscription will expire in some days """
@ -40,7 +39,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
from_email = settings.DEFAULT_FROM_EMAIL
for v in NOTIFY_DAYS_BEFORE:
for v in parse_integer_list(site_config.NOTIFY_DAYS_BEFORE):
emails = []
qs = get_next_expirations(v)
users = list(qs)

@ -4,16 +4,14 @@ from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from django.utils import timezone
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from . import core
from constance import config as site_config
from . import core
from ccvpn.common import get_trial_period_duration
from payments.models import Subscription
assert isinstance(settings.TRIAL_PERIOD, timedelta)
assert isinstance(settings.TRIAL_PERIOD_LIMIT, int)
prng = random.SystemRandom()
@ -66,12 +64,12 @@ class VPNUser(models.Model):
core.update_user_expiration(self.user)
def give_trial_period(self):
self.add_paid_time(settings.TRIAL_PERIOD)
self.add_paid_time(get_trial_period_duration())
self.trial_periods_given += 1
@property
def can_have_trial(self):
if self.trial_periods_given >= settings.TRIAL_PERIOD_LIMIT:
if self.trial_periods_given >= site_config.TRIAL_PERIOD_MAX:
return False
if self.user.payment_set.filter(status='confirmed').count() > 0:
return False
@ -79,7 +77,7 @@ class VPNUser(models.Model):
@property
def remaining_trial_periods(self):
return settings.TRIAL_PERIOD_LIMIT - self.trial_periods_given
return site_config.TRIAL_PERIOD_MAX - self.trial_periods_given
def on_payment_confirmed(self, payment):
if self.referrer and not self.referrer_used:

@ -4,6 +4,8 @@ from django.utils import timezone
from django.core.management import call_command
from django.core import mail
from django.utils.six import StringIO
from constance import config as site_config
from constance.test import override_config
from .forms import SignupForm
from .models import VPNUser, User, random_gift_code, GiftCode, GiftCodeUser
@ -80,7 +82,7 @@ class UserModelTest(TestCase, UserTestMixin):
u = User.objects.get(username='aaa')
vu = u.vpnuser
with self.settings(TRIAL_PERIOD=p, TRIAL_PERIOD_LIMIT=2):
with override_config(TRIAL_PERIOD_HOURS=24, TRIAL_PERIOD_MAX=2):
self.assertEqual(vu.remaining_trial_periods, 2)
self.assertTrue(vu.can_have_trial)
vu.give_trial_period()
@ -103,7 +105,7 @@ class UserModelTest(TestCase, UserTestMixin):
vu = u.vpnuser
with self.settings(TRIAL_PERIOD=p, TRIAL_PERIOD_LIMIT=2):
with override_config(TRIAL_PERIOD_HOURS=24, TRIAL_PERIOD_MAX=2):
self.assertEqual(vu.remaining_trial_periods, 2)
self.assertFalse(vu.can_have_trial)
@ -186,25 +188,27 @@ class AccountViewsTest(TestCase, UserTestMixin):
def test_trial(self):
p = timedelta(days=1)
with self.settings(RECAPTCHA_API='TEST', TRIAL_PERIOD=p):
good_data = {'g-recaptcha-response': 'TEST-TOKEN'}
with self.settings(RECAPTCHA_API='TEST'):
with override_config(TRIAL_PERIOD_HOURS=24, TRIAL_PERIOD_MAX=2):
good_data = {'g-recaptcha-response': 'TEST-TOKEN'}
response = self.client.post('/account/trial', good_data)
self.assertRedirects(response, '/account/')
response = self.client.post('/account/trial', good_data)
self.assertRedirects(response, '/account/')
user = User.objects.get(username='test')
self.assertRemaining(user.vpnuser, p)
user = User.objects.get(username='test')
self.assertRemaining(user.vpnuser, p)
def test_trial_fail(self):
p = timedelta(days=1)
with self.settings(RECAPTCHA_API='TEST', TRIAL_PERIOD=p):
bad_data = {'g-recaptcha-response': 'TOTALLY-NOT-TEST-TOKEN'}
with self.settings(RECAPTCHA_API='TEST'):
with override_config(TRIAL_PERIOD_HOURS=24, TRIAL_PERIOD_MAX=2):
bad_data = {'g-recaptcha-response': 'TOTALLY-NOT-TEST-TOKEN'}
response = self.client.post('/account/trial', bad_data)
self.assertRedirects(response, '/account/')
response = self.client.post('/account/trial', bad_data)
self.assertRedirects(response, '/account/')
user = User.objects.get(username='test')
self.assertRemaining(user.vpnuser, timedelta())
user = User.objects.get(username='test')
self.assertRemaining(user.vpnuser, timedelta())
def test_settings_form(self):
response = self.client.get('/account/settings')

@ -25,9 +25,10 @@ from django.db.models import Count
from django.contrib import auth
from django.contrib.auth.models import User
from django_countries import countries
from constance import config as site_config
import lcoreapi
from ccvpn.common import get_client_ip
from ccvpn.common import get_client_ip, get_price_float
from payments.models import ACTIVE_BACKENDS
from .forms import SignupForm, ReqEmailForm
from .models import GiftCode, VPNUser
@ -164,7 +165,7 @@ def index(request):
3 an arbitrary number of months
"""
def __getitem__(self, months):
n = int(months) * project_settings.PAYMENTS_MONTHLY_PRICE / 100
n = int(months) * get_price_float()
c = project_settings.PAYMENTS_CURRENCY[1]
return '%.2f %s' % (n, c)
@ -180,6 +181,7 @@ def index(request):
default_backend='paypal',
recaptcha_site_key=project_settings.RECAPTCHA_SITE_KEY,
price=price_fn(),
user_motd=site_config.MOTD_USER,
)
return render(request, 'lambdainst/account.html', context)

@ -1,10 +1,10 @@
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings
from ccvpn.common import get_price
from payments.models import ACTIVE_BACKENDS, SUBSCR_PERIOD_CHOICES, period_months
CURRENCY_CODE, CURRENCY_NAME = settings.PAYMENTS_CURRENCY
MONTHLY_PRICE = settings.PAYMENTS_MONTHLY_PRICE
class Command(BaseCommand):
@ -26,11 +26,11 @@ class Command(BaseCommand):
for period_id, period_name in SUBSCR_PERIOD_CHOICES:
plan_id = backend.get_plan_id(period_id)
months = period_months(period_id)
amount = months * MONTHLY_PRICE
amount = months * get_price()
kwargs = dict(
id=plan_id,
amount=months * MONTHLY_PRICE,
amount=amount,
interval='month',
interval_count=months,
name=backend.name + " (%s)" % period_id,

@ -4,13 +4,13 @@ from django.utils.translation import ugettext_lazy as _
from jsonfield import JSONField
from datetime import timedelta
from ccvpn.common import get_price
from .backends import BackendBase
backend_settings = settings.PAYMENTS_BACKENDS
assert isinstance(backend_settings, dict)
backends_settings = settings.PAYMENTS_BACKENDS
assert isinstance(backends_settings, dict)
CURRENCY_CODE, CURRENCY_NAME = settings.PAYMENTS_CURRENCY
MONTHLY_PRICE = settings.PAYMENTS_MONTHLY_PRICE
STATUS_CHOICES = (
('new', _("Waiting for payment")),
@ -51,12 +51,17 @@ for cls in BackendBase.__subclasses__():
name = cls.backend_id
assert isinstance(name, str)
if name not in backend_settings:
if name not in backends_settings:
continue
obj = cls(backend_settings.get(name, {}))
backend_settings = backends_settings.get(name, {})
for k, v in backend_settings.items():
if hasattr(v, '__call__'):
backend_settings[k] = v()
obj = cls(backend_settings)
if not obj.backend_enabled:
if name in backend_settings:
if name in backends_settings:
raise Exception("Invalid settings for payment backend %r" % name)
BACKENDS[name] = obj
@ -131,7 +136,7 @@ class Payment(models.Model):
backend_id=backend_id,
status='new',
time=timedelta(days=30 * months),
amount=MONTHLY_PRICE * months
amount=get_price() * months
)
return payment
@ -161,7 +166,7 @@ class Subscription(models.Model):
@property
def period_amount(self):
return self.months * MONTHLY_PRICE
return self.months * get_price()
@property
def next_renew(self):
@ -172,7 +177,7 @@ class Subscription(models.Model):
@property
def monthly_amount(self):
return MONTHLY_PRICE
return get_price()
def create_payment(self):
payment = Payment(
@ -180,7 +185,7 @@ class Subscription(models.Model):
backend_id=self.backend_id,
status='new',
time=timedelta(days=30 * self.months),
amount=MONTHLY_PRICE * self.months,
amount=get_price() * self.months,
subscription=self,
)
return payment

@ -13,9 +13,6 @@ from .forms import NewPaymentForm
from .models import Payment, Subscription, BACKENDS, ACTIVE_BACKENDS
monthly_price = settings.PAYMENTS_MONTHLY_PRICE
@login_required
def new(request):
if request.method != 'POST':

@ -1,5 +1,6 @@
django
django-jsonfield
django-constance[database]
django_countries
markdown
requests

@ -235,6 +235,9 @@ footer p { margin-top: 0.6em; margin-bottom: 0.5em; }
margin: 0;
color: white;
}
.message.motd p {
color: black;
}
.message p.info, .message p.success {
background-color: #062D4D;
}
@ -492,6 +495,15 @@ a.home-signup-button {
padding: 0.6em 2em;
margin: 2em 0 0 0;
}
.account-motd {
background: #E6F5FF;
border-radius: 4px;
border: 1px solid #72B6ED;
box-shadow: 1px 1px 3px #aaa;
padding: 0.3em 2em;
text-align: center;
margin: 2em 0 0 0;
}
.account-payment-box form label, .account-giftcode-box form label {
width: 8em;

@ -7,6 +7,13 @@
{% block account_content %}
<div>
{% if user_motd %}
<div class="account-motd">
<p> {{ user_motd | safe }} </p>
</div>
{% endif %}
<h1>{% trans 'Account' %} : {{user.username}}</h1>
<div class="account-status">

@ -65,6 +65,11 @@
</header>
{% block wrap %}
{% if motd %}
<div class="message motd">
<p>{{ motd | safe }}</p>
</div>
{% endif %}
{% for message in messages %}
<div class="message">
<p class="{{message.tags}}">{{ message }}</p>

Loading…
Cancel
Save