add referral app

remotes/origin/HEAD
Max Yakovenko 8 years ago
parent 34808371a1
commit f435090822
  1. 1
      referral/__init__.py
  2. 108
      referral/admin.py
  3. 10
      referral/apps.py
  4. 46
      referral/forms.py
  5. 42
      referral/middleware.py
  6. 9
      referral/mixins.py
  7. 116
      referral/models.py
  8. 2
      referral/signals.py
  9. 0
      referral/templatetags/__init__.py
  10. 7
      referral/templatetags/referral_tags.py
  11. 3
      referral/tests.py
  12. 6
      referral/urls.py
  13. 15
      referral/utils.py
  14. 0
      referral/views.py

@ -0,0 +1 @@
default_app_config = 'referral.apps.ReferralConfig'

@ -0,0 +1,108 @@
from django.contrib import admin
from django.contrib.admin import register
from django.urls import reverse_lazy
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _
# Register your models here.
from rangefilter.filter import DateRangeFilter, DateTimeRangeFilter
from core.admin import SafeModelAdmin
from .models import Referral, ReferralStats, PartnerStats
from .forms import ReferralAdminForm, ReferralStatsAdminForm, PartnerStatsAdminForm
class RefarralAdminInline(admin.TabularInline):
model = Referral
readonly_fields = ('code',)
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
@register(Referral)
class ReferralAdmin(SafeModelAdmin):
def has_add_permission(self, request):
return False
def referral_stats(self, referral):
try:
link = reverse_lazy(
'admin:{}_{}_changelist'.format(referral.referralstats._meta.app_label,
referral.referralstats._meta.object_name.lower())
)
link += '?q={}'.format(referral.code)
except Exception as e:
link = '#'
name = _('Details')
return format_html('<a href="{}">{}</a>', link, name)
referral_stats.short_description = _('Stats')
form = ReferralAdminForm
list_display = ('code', 'create_at', 'updated_at', 'status', 'referral_stats')
search_fields = ('code',)
list_filter = ('status', ('create_at', DateRangeFilter), ('updated_at', DateTimeRangeFilter))
ordering = ('-create_at',)
@register(ReferralStats)
class ReferralStatsAdmin(SafeModelAdmin):
def has_add_permission(self, request):
return False
def referral_code(self, stats):
return stats.referral.code
referral_code.short_description = _('Code')
def converted_earnings(self, stats):
return stats.earnings if stats.earnings > 0 else 0
converted_earnings.short_description = _('Earnings')
form = ReferralStatsAdminForm
list_display = ('referral_code', 'visits', 'registrations')
list_select_related = ('referral',)
search_fields = ('referral__name', 'referral__code',)
ordering = ('-create_at',)
@register(PartnerStats)
class PartnerStatsAdmin(SafeModelAdmin):
def has_add_permission(self, request):
return False
def stats_owner(self, stats):
try:
link = reverse_lazy(
'admin:{}_{}_change'.format(stats.user._meta.app_label, stats.user._meta.object_name.lower()),
args=(stats.user.id,)
)
name = stats.user.email
except Exception as e:
link = '#'
name = "None"
return format_html('<a href="{}">{}</a>', link, name)
stats_owner.short_description = _('User')
def formatted_total_conversion(self, stats):
return str(stats.formatted_total_conversion) + "%"
formatted_total_conversion.short_description = _('Total conversion')
def converted_total_earnings(self, stats):
return stats.total_earnings if stats.total_earnings > 0 else 0
converted_total_earnings.short_description = _('Total earnings')
form = PartnerStatsAdminForm
list_display = ('stats_owner', 'total_visits', 'total_regs')
search_fields = ('user__email',)

@ -0,0 +1,10 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ReferralConfig(AppConfig):
name = 'referral'
verbose_name = _("Referrals")
def ready(self):
import referral.signals

@ -0,0 +1,46 @@
from django import forms
from django.forms import URLInput, ALL_FIELDS
from .models import Referral, ReferralStats, PartnerStats
class ReferralAdminForm(forms.ModelForm):
class Meta:
model = Referral
fields = ('code',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.disable_fields(self.fields)
def disable_fields(self, fields):
for field_name, field in fields.items():
field.disabled = True
class ReferralStatsAdminForm(forms.ModelForm):
class Meta:
model = ReferralStats
fields = ALL_FIELDS
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.disable_fields(self.fields)
def disable_fields(self, fields):
for field_name, field in fields.items():
field.disabled = True
class PartnerStatsAdminForm(forms.ModelForm):
class Meta:
model = PartnerStats
fields = ALL_FIELDS
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.disable_fields(self.fields)
def disable_fields(self, fields):
for field_name, field in fields.items():
field.disabled = True

@ -0,0 +1,42 @@
from django.http import HttpResponseRedirect
from django.urls import reverse
from core.models import STATUS_ACTIVE
from .models import Referral
from .utils import set_cookie, pop_cookie, get_cookie
class ReferralMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = None
if hasattr(self,'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self,'process_response'):
response = self.process_response(request,response)
return response
def process_request(self,request):
pass
def process_response(self,request,response):
if not request.user.is_authenticated:
code = request.GET.get('ref')
cookie_code = get_cookie(request.COOKIES, 'referral')
if code != cookie_code:
referral_code = request.GET.get('ref')
referral = Referral.active.filter(code__exact=referral_code).first()
if referral and referral.is_active:
referral.referralstats.visits += 1
referral.referralstats.save()
referral.user.partnerstats.total_visits += 1
referral.user.partnerstats.save()
set_cookie(response, 'referral', referral_code)
elif request.user.is_authenticated:
pop_cookie(response, 'referral')
return response

@ -0,0 +1,9 @@
from decimal import Decimal
class StatsFormatterMixin(object):
def format_conversion(self, conversion, place=0):
return round(conversion * 100, place)
def normalize_conversion(self, conversion):
return Decimal(conversion) / Decimal(100)

@ -0,0 +1,116 @@
import logging
import string
import random
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
# Create your models here.
from registration.signals import user_activated
from core.models import AbstractStatusModel, STATUS_ACTIVE
from referral.mixins import StatsFormatterMixin
from referral.utils import get_cookie
logger = logging.getLogger(__name__)
# --------------------------------- Referral status list ----------------------------#
REFERRAL_DEFAULT_STATUS = STATUS_ACTIVE
# @TODO: translate into english and use translation
class Referral(AbstractStatusModel):
CODE_LENGTH = 8
user = models.OneToOneField(get_user_model(),verbose_name=_('пользователь'), on_delete=models.CASCADE, primary_key=True
)
code = models.CharField(_('код'), max_length=255)
@classmethod
def create(cls, user, code):
referral = cls(user=user, code=code)
return referral
@staticmethod
def generate_code():
def _generate_code():
return ''.join([random.choice(string.ascii_uppercase + string.digits) for n in range(Referral.CODE_LENGTH)])
code = _generate_code()
while Referral.active.filter(code=code).exists():
code = _generate_code()
return code
@property
def url(self):
path = reverse_lazy('index:index')
site_url = settings.DEFAULT_SITE_URL
return "{}{}".format(site_url, path)
def __str__(self):
return self.code
class Meta:
verbose_name = _('Реферал')
verbose_name_plural = _('Рефералы')
class ReferralStats(StatsFormatterMixin, AbstractStatusModel):
referral = models.OneToOneField(Referral, verbose_name=_('Реферал'), on_delete=models.CASCADE, primary_key=True)
visits = models.IntegerField(_('Посищения'), default=0)
registrations = models.IntegerField(_('Регистрации'), default=0)
class Meta:
verbose_name = _('Реферальная статистика')
verbose_name_plural = _('Реферальная статистика')
class PartnerStats(StatsFormatterMixin, AbstractStatusModel):
user = models.OneToOneField(get_user_model(), verbose_name=_('username'), on_delete=models.CASCADE,
primary_key=True)
total_visits = models.BigIntegerField(_('Всего посещений'), default=0)
total_regs = models.BigIntegerField(_('Всего регистраций'), default=0)
class Meta:
verbose_name = _('Партнеская статистика')
verbose_name_plural = _('Партнерская статистика')
@receiver(post_save, sender=get_user_model())
def create_user_referral(sender, instance, created, **kwargs):
if created and Referral.objects.filter(user=instance).first() is None:
Referral.create(user=instance, code=Referral.generate_code()).save()
@receiver(post_save, sender=Referral)
def init_referral_stuff(sender, instance, created, *args, **kwargs):
if created:
if PartnerStats.objects.filter(user_id=instance.user_id).count() == 0:
PartnerStats.objects.create(user=instance.user).save()
if ReferralStats.active.filter(referral=instance).count() == 0:
ReferralStats.active.create(referral=instance).save()
@receiver(user_activated)
def update_ref_stats(sender, user, request, **kwargs):
referral_code = get_cookie(request.COOKIES, 'referral')
if referral_code:
referral = Referral.objects.filter(code__exact=referral_code).first()
if referral:
referral.referralstats.registrations += 1
referral.referralstats.save()
referral.user.partnerstats.total_regs += 1
referral.user.partnerstats.save()
user.referral = referral
user.referral_user = referral.user
user.save()
else:
logger.warning("Missing referral code in database: " + referral_code)

@ -0,0 +1,2 @@
import logging
logger = logging.getLogger(__name__)

@ -0,0 +1,7 @@
from django import template
register = template.Library()
@register.filter
def normalize_conversion(conversion, place = 0):
return round(conversion*100, place)

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,6 @@
from django.conf.urls import url
from django.urls import re_path
urlpatterns = [
# re_path()
]

@ -0,0 +1,15 @@
import datetime
def set_cookie(response, key, value, day_expire = 1):
max_age = day_expire * 24 * 60 * 60
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age), "%a, %d-%b-%Y %H:%M:%S GMT")
response.set_cookie(key=key,value=value,max_age=max_age,expires=expires) # @TODO: Connect cookie to domain
def get_cookie(cookies, key):
return cookies.get(key) if cookies.get(key) else None
def pop_cookie(response, key):
cookie = get_cookie(response.cookies, key)
if cookie:
response.delete_cookie(key)
return cookie
Loading…
Cancel
Save