Fix duplicate records in membership table.

This commit is contained in:
Oliver Marks 2017-09-17 10:50:09 +01:00
parent 22a700bc5e
commit 574286e8e3
11 changed files with 91 additions and 69 deletions

View File

@ -375,7 +375,12 @@ CELERY_BROKER_URL = env('CELERY_BROKER_URL', default='redis://redis:6379/0')
#if CELERY_BROKER_URL == 'django://': #if CELERY_BROKER_URL == 'django://':
# CELERY_RESULT_BACKEND = 'redis://' # CELERY_RESULT_BACKEND = 'redis://'
#else: #else:
CELERY_RESULT_BACKEND = 'django-cache' CELERY_RESULT_BACKEND = 'redis://redis:6379/0'
CELERY_IGNORE_RESULT = False
CELERY_REDIS_HOST = "redis"
CELERY_REDIS_PORT = 6379
CELERY_REDIS_DB = 0
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
INSTALLED_APPS += ('django_celery_results','django_celery_beat',) INSTALLED_APPS += ('django_celery_results','django_celery_beat',)
CELERY_TIMEZONE = 'UTC' CELERY_TIMEZONE = 'UTC'

View File

@ -86,7 +86,7 @@ TEST_RUNNER = 'django.test.runner.DiscoverRunner'
########## CELERY ########## CELERY
# In development, all tasks will be executed locally by blocking until the task returns # In development, all tasks will be executed locally by blocking until the task returns
CELERY_ALWAYS_EAGER = True # CELERY_ALWAYS_EAGER = True
########## END CELERY ########## END CELERY
# Your local stuff: Below this line define 3rd party library settings # Your local stuff: Below this line define 3rd party library settings

View File

@ -6,8 +6,8 @@ from mhackspace.feeds.helper import import_feeds
@shared_task @shared_task
def update_homepage_feeds(): def update_homepage_feeds():
return import_feeds() import_feeds()
return {'result': 'Homepage feeds imported'}
matrix_url = "https://matrix.org/_matrix/client/r0" matrix_url = "https://matrix.org/_matrix/client/r0"
matrix_login_url = matrix_url + "/login" matrix_login_url = matrix_url + "/login"
@ -31,9 +31,10 @@ def send_email(email_to,
to=[email_to], to=[email_to],
headers={'Reply-To': 'no-reply@maidstone-hackspace.org.uk'}) headers={'Reply-To': 'no-reply@maidstone-hackspace.org.uk'})
email.send() email.send()
return {'result', 'Email sent to %s' % email_to}
@shared_task @shared_task
def matrix_message(message): def matrix_message(message, prefix=''):
# we dont rely on theses, so ignore if it goes wrong # we dont rely on theses, so ignore if it goes wrong
# TODO at least log that something has gone wrong # TODO at least log that something has gone wrong
try: try:
@ -59,8 +60,8 @@ def matrix_message(message):
url = matrix_send_msg_url.format(**url_params) url = matrix_send_msg_url.format(**url_params)
details = { details = {
"msgtype": "m.text", "msgtype": "m.text",
"body": "[%s] %s" % (settings.MSG_PREFIX, message)} "body": "[%s%s] %s" % (settings.MSG_PREFIX, prefix, message)}
r2 = requests.post(url, json=details) r2 = requests.post(url, json=details)
except: except:
pass pass
return True return {'result', 'Matrix message sent successfully'}

View File

@ -45,7 +45,7 @@ class UserRequests(models.Model):
def send_topic_update_email(sender, instance, **kwargs): def send_topic_update_email(sender, instance, **kwargs):
matrix_message.delay('New Request - %s' % instance.title) matrix_message.delay(prefix=' - REQUEST', message=instance.title)
post_save.connect(send_topic_update_email, sender=UserRequests) post_save.connect(send_topic_update_email, sender=UserRequests)

View File

@ -1,13 +1,18 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
from django.contrib import messages
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.utils.dateparse import parse_datetime
from mhackspace.users.models import Membership from mhackspace.users.models import Membership
def create_or_update_membership(user, signup_details, complete=False): def create_or_update_membership(user, signup_details, complete=False):
try: try:
member = Membership.objects.get(user=user) member = Membership.objects.get(email=signup_details.get('email'))
# Only update if newer than last record, this way we only get the latest status
# cancellation and changed payment will not be counted against current status
start_date = parse_datetime(signup_details.get('start_date'))
if start_date < member.date:
return True
except Membership.DoesNotExist: except Membership.DoesNotExist:
member = Membership() member = Membership()
member.user = user member.user = user
@ -25,6 +30,7 @@ def create_or_update_membership(user, signup_details, complete=False):
return False # sign up not completed return False # sign up not completed
# add user to group on success # add user to group on success
group = Group.objects.get(name='members') if user:
user.groups.add(group) group = Group.objects.get(name='members')
user.groups.add(group)
return True # Sign up finished return True # Sign up finished

View File

@ -1,5 +1,3 @@
from datetime import datetime
from django.utils import timezone
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
@ -8,6 +6,10 @@ from mhackspace.users.models import Membership, User
from mhackspace.subscriptions.helper import create_or_update_membership from mhackspace.subscriptions.helper import create_or_update_membership
# this should be done in bulk, create the objects and save all at once
# for now its not an issue, because of small membership size
def update_subscriptions(provider_name): def update_subscriptions(provider_name):
provider = select_provider('gocardless') provider = select_provider('gocardless')
@ -24,17 +26,9 @@ def update_subscriptions(provider_name):
except User.DoesNotExist: except User.DoesNotExist:
user_model = None user_model = None
subscriptions.append( create_or_update_membership(user=user_model,
Membership( signup_details=sub,
user=user_model, complete=True)
email=sub.get('email'),
reference=sub.get('reference'),
payment=10.00,
date= sub.get('start_date'),
# date=timezone.now(),
status=Membership.lookup_status(name=sub.get('status'))
)
)
yield model_to_dict(subscriptions[-1]) yield model_to_dict(subscriptions[-1])
@ -49,11 +43,11 @@ class Command(BaseCommand):
provider = select_provider('gocardless') provider = select_provider('gocardless')
Membership.objects.all().delete() Membership.objects.all().delete()
subscriptions = []
group = Group.objects.get(name='members') group = Group.objects.get(name='members')
for sub in provider.fetch_subscriptions(): for sub in provider.fetch_subscriptions():
prefix = ''
sub['amount'] = sub['amount'] * 0.01 sub['amount'] = sub['amount'] * 0.01
try: try:
user_model = User.objects.get(email=sub.get('email')) user_model = User.objects.get(email=sub.get('email'))
@ -61,37 +55,23 @@ class Command(BaseCommand):
user_model.groups.add(group) user_model.groups.add(group)
except User.DoesNotExist: except User.DoesNotExist:
user_model = None user_model = None
self.style.NOTICE( prefix = 'NO USER - '
'\tMissing User {reference} - {payment} - {status} - {email}'.format(**{
'reference': sub.get('reference'),
'payment': sub.get('amount'),
'status': sub.get('status'),
'email': sub.get('email')
}))
continue
create_or_update_membership(user=user_model, create_or_update_membership(user=user_model,
signup_details=sub, signup_details=sub,
complete=True) complete=True)
subscriptions.append(
Membership(
user=user_model,
email=sub.get('email'),
reference=sub.get('reference'),
payment=sub.get('amount'),
date=sub.get('start_date'),
status=Membership.lookup_status(name=sub.get('status'))
)
)
self.stdout.write( message = '\t{prefix}{date} - {reference} - {payment} - {status} - {email}'.format(**{
self.style.SUCCESS( 'prefix': prefix,
'\t{reference} - {payment} - {status} - {email}'.format(**{ 'date': sub.get('start_date'),
'reference': sub.get('reference'), 'reference': sub.get('reference'),
'payment': sub.get('amount'), 'payment': sub.get('amount'),
'status': sub.get('status'), 'status': sub.get('status'),
'email': sub.get('email') 'email': sub.get('email')
}))) })
Membership.objects.bulk_create(subscriptions) if user_model:
self.stdout.write(self.style.SUCCESS(message))
else:
self.stdout.write(self.style.NOTICE(message))

View File

@ -168,6 +168,7 @@
<div class="container"> <div class="container">
{% block footer-left %}{% endblock footer-left %} {% block footer-left %}{% endblock footer-left %}
<span class="text-muted">&copy; {% now "Y" %} Maidstone Hackspace</span> <span class="text-muted">&copy; {% now "Y" %} Maidstone Hackspace</span>
<span><a href="https://maidstone-hackspace.org.uk/wiki/maidstone-hackspace-constitution/">Constitution</a></span>
<div class="float-right"> <div class="float-right">
<a href="https://github.com/maidstone-hackspace/" target="_blank"><i class="fa fa-github"></i></a> <a href="https://github.com/maidstone-hackspace/" target="_blank"><i class="fa fa-github"></i></a>
<a href="https://github.com/maidstone-hackspace/" target="_blank"><i class="fa fa-twitter"></i></a> <a href="https://github.com/maidstone-hackspace/" target="_blank"><i class="fa fa-twitter"></i></a>

View File

@ -11,7 +11,8 @@ from django.urls import reverse
from django.conf.urls import url from django.conf.urls import url
from .models import User, Rfid, Membership, MEMBERSHIP_STATUS_CHOICES from .models import User, Rfid, Membership, MEMBERSHIP_STATUS_CHOICES
from mhackspace.subscriptions.management.commands.update_membership_status import update_subscriptions # from mhackspace.subscriptions.management.commands.update_membership_status import update_subscriptions
from mhackspace.users.tasks import update_users_memebership_status
class MyUserChangeForm(UserChangeForm): class MyUserChangeForm(UserChangeForm):
@ -46,27 +47,27 @@ class MyUserAdmin(AuthUserAdmin):
list_display = ('username', 'name', 'is_superuser') list_display = ('username', 'name', 'is_superuser')
search_fields = ['name'] search_fields = ['name']
@admin.register(Membership)
class MembershipAdmin(ModelAdmin):
list_display = ('user_id', 'email', 'payment', 'date', 'status')
list_filter = ('status',)
def get_urls(self): def get_urls(self):
urls = super(MyUserAdmin, self).get_urls() urls = super(MembershipAdmin, self).get_urls()
my_urls = [ my_urls = [
url(r'^refresh/payments/$', self.admin_site.admin_view(self.refresh_payments)) url(r'^refresh/payments/$', self.admin_site.admin_view(self.refresh_payments))
] ]
return my_urls + urls return my_urls + urls
def refresh_payments(self, request): def refresh_payments(self, request):
for user in update_subscriptions(provider_name='gocardless'): update_users_memebership_status()
continue # for user in update_subscriptions(provider_name='gocardless'):
self.message_user(request, 'Successfully imported refresh users payment status') # continue
return HttpResponseRedirect(reverse('admin:feeds_article_changelist')) self.message_user(request, 'Successfully triggered user payment refresh')
return HttpResponseRedirect(reverse('admin:index'))
@admin.register(Membership)
class MembershipAdmin(ModelAdmin):
list_display = ('user_id', 'user', 'payment', 'date', 'status')
list_filter = ('status',)
@admin.register(Rfid) @admin.register(Rfid)
class RfidAdmin(ModelAdmin): class RfidAdmin(ModelAdmin):
list_display = ('code', 'description') list_display = ('code', 'description')

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-17 09:48
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0007_auto_20170914_2021'),
]
operations = [
migrations.AlterField(
model_name='membership',
name='email',
field=models.CharField(max_length=255, unique=True),
),
migrations.AlterField(
model_name='membership',
name='user',
field=models.OneToOneField(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -70,17 +70,18 @@ MEMBERSHIP_STATUS = {
class Membership(models.Model): class Membership(models.Model):
user = models.ForeignKey( user = models.OneToOneField(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
null=True, blank=True, null=True, blank=True,
default=None, default=None,
related_name='user' related_name='user',
unique=True
) )
payment = models.DecimalField(max_digits=6, decimal_places=2, default=0.0) payment = models.DecimalField(max_digits=6, decimal_places=2, default=0.0)
date = models.DateTimeField() date = models.DateTimeField()
reference = models.CharField(max_length=255) reference = models.CharField(max_length=255)
status = models.PositiveSmallIntegerField(default=0, choices=MEMBERSHIP_STATUS_CHOICES) status = models.PositiveSmallIntegerField(default=0, choices=MEMBERSHIP_STATUS_CHOICES)
email = models.CharField(max_length=255) email = models.CharField(max_length=255, unique=True)
@property @property
def get_status(self): def get_status(self):