From ff0da6aa6a8b63929593b20120bb1e7dae49ebdb Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 25 Jan 2017 22:16:52 +0000 Subject: [PATCH 01/19] Pin braintree to latest version 3.34.0 --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 9343860..c5b8bb2 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -51,7 +51,7 @@ lxml==3.7.2 mock gocardless -braintree +braintree==3.34.0 # Your custom requirements go here -e git+https://github.com/olymk2/scaffold.git#egg=scaffold From a8e8ad80e92ff4d66059b5c0263d639852d31601 Mon Sep 17 00:00:00 2001 From: Oly Date: Thu, 26 Jan 2017 08:52:41 +0000 Subject: [PATCH 02/19] fix env file loading --- config/settings/common.py | 2 +- env.example | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config/settings/common.py b/config/settings/common.py index 5dd17db..1c06d2e 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -16,7 +16,7 @@ ROOT_DIR = environ.Path(__file__) - 3 # (mhackspace/config/settings/common.py - APPS_DIR = ROOT_DIR.path('mhackspace') env = environ.Env() -env.read_env() +env.read_env('%s/.env' % ROOT_DIR) # APP CONFIGURATION # ------------------------------------------------------------------------------ diff --git a/env.example b/env.example index 2324613..db57760 100644 --- a/env.example +++ b/env.example @@ -29,16 +29,16 @@ DJANGO_ACCOUNT_ALLOW_REGISTRATION=True COMPRESS_ENABLED= -PAYMENT_ENVIRONMENT = 'sandbox' +PAYMENT_ENVIRONMENT=sandbox -BRAINTREE_MERCHANT_ID = '' -BRAINTREE_PUBLIC_KEY = '' -BRAINTREE_PRIVATE_KEY = '' +BRAINTREE_MERCHANT_ID=demo +BRAINTREE_PUBLIC_KEY=demo +BRAINTREE_PRIVATE_KEY=demo -PAYPAL_CLIENT_ID = "" -PAYPAL_CLIENT_SECRET = "" +PAYPAL_CLIENT_ID=demo +PAYPAL_CLIENT_SECRET=demo -GOCARDLESS_APP_ID = '' -GOCARDLESS_APP_SECRET = '' -GOCARDLESS_ACCESS_TOKEN = '' -GOCARDLESS_MERCHANT_ID = '' +GOCARDLESS_APP_ID=demo +GOCARDLESS_APP_SECRET=demo +GOCARDLESS_ACCESS_TOKEN=demo +GOCARDLESS_MERCHANT_ID=demo From 37ab2f6532be8a316195d04f00b22a0fca3fcf54 Mon Sep 17 00:00:00 2001 From: Sam Collins Date: Thu, 26 Jan 2017 09:03:03 +0000 Subject: [PATCH 03/19] Added support for Circle CI tests (#16) * Inital Travis Tests * Fixed YML word wrap * Added Requirements * Cricle CI Config * Removed Drone from tests * Update base.txt --- .travis.yml | 11 +++++++++++ circle.yml | 4 ++++ requirements.txt | 4 ++++ requirements/base.txt | 2 +- 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .travis.yml create mode 100644 circle.yml create mode 100644 requirements.txt diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..216b870 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +sudo: true +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq build-essential gettext python-dev zlib1g-dev libpq-dev xvfb + - sudo apt-get install -qq libtiff4-dev libjpeg8-dev libfreetype6-dev liblcms1-dev libwebp-dev + - sudo apt-get install -qq graphviz-dev python-setuptools python3-dev python-virtualenv python-pip + - sudo apt-get install -qq firefox automake libtool libreadline6 libreadline6-dev libreadline-dev + - sudo apt-get install -qq libsqlite3-dev libxml2 libxml2-dev libssl-dev libbz2-dev wget curl llvm +language: python +python: + - "3.5" diff --git a/circle.yml b/circle.yml new file mode 100644 index 0000000..8e6cfe6 --- /dev/null +++ b/circle.yml @@ -0,0 +1,4 @@ +machine: + environment: + DJANGO_SETTINGS_MODULE: config.settings.test + DATABASE_URL: postgres://ubuntu:@127.0.0.1:5432/circle_test diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b5774c9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# This file is here because many Platforms as a Service look for +# requirements.txt in the root directory of a project. +-r requirements/production.txt + diff --git a/requirements/base.txt b/requirements/base.txt index 9343860..25779a5 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -54,4 +54,4 @@ gocardless braintree # Your custom requirements go here --e git+https://github.com/olymk2/scaffold.git#egg=scaffold +git+https://github.com/olymk2/scaffold.git From 097a637682360fe08efc9d05a4e71095e070055f Mon Sep 17 00:00:00 2001 From: Oly Date: Thu, 26 Jan 2017 09:07:38 +0000 Subject: [PATCH 04/19] env and settings now loading, need to work on mocking next --- config/settings/common.py | 4 ++-- mhackspace/subscriptions/payments.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/settings/common.py b/config/settings/common.py index 1c06d2e..2e505d0 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -262,7 +262,7 @@ ADMIN_URL = '^admin/' # ------------------------------------------------------------------------------ -payment_providers = { +PAYMENT_PROVIDERS = { 'braintree': { 'mode': 'sandbox', 'credentials': { @@ -275,7 +275,7 @@ payment_providers = { "mode": "sandbox", # sandbox or live 'credentials': { "mode": "sandbox", # sandbox or live - "client_id": end('PAYPAL_CLIENT_ID'), + "client_id": env('PAYPAL_CLIENT_ID'), "client_secret": env('PAYPAL_CLIENT_SECRET')} }, 'gocardless':{ diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index edc4bae..6b6fbd1 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -3,7 +3,9 @@ import pytz import gocardless import braintree -from django.conf.settings import payment_providers +from django.conf import settings +print(dir(settings)) +payment_providers = settings.PAYMENT_PROVIDERS # import gocardless_pro # import paypalrestsdk as paypal From 0622d842ba8223bc0b5bb7a236d7ee2c432af46f Mon Sep 17 00:00:00 2001 From: Oly Date: Thu, 26 Jan 2017 13:13:42 +0000 Subject: [PATCH 05/19] all tests now run --- .drone.yml | 3 ++- mhackspace/subscriptions/__init__.py | 0 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 mhackspace/subscriptions/__init__.py diff --git a/.drone.yml b/.drone.yml index 3075c22..be2af8f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -6,7 +6,8 @@ pipeline: - USE_DOCKER=yes - DJANGO_SETTINGS_MODULE=config.settings.test commands: - - python manage.py test mhackspace.subscriptions --verbosity 2 + - cp -n env.example .env + - python manage.py test mhackspace --verbosity 2 #volumes: # postgres_data_dev: {} diff --git a/mhackspace/subscriptions/__init__.py b/mhackspace/subscriptions/__init__.py new file mode 100644 index 0000000..e69de29 From e8733284042aa9742c1572d737c33aaf20b09989 Mon Sep 17 00:00:00 2001 From: Sam Collins Date: Thu, 26 Jan 2017 13:27:33 +0000 Subject: [PATCH 06/19] Added Init for feeds --- mhackspace/feeds/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mhackspace/feeds/__init__.py diff --git a/mhackspace/feeds/__init__.py b/mhackspace/feeds/__init__.py new file mode 100644 index 0000000..e69de29 From 7734b006532b57bdade4add8df56523f3877aa21 Mon Sep 17 00:00:00 2001 From: Sam Collins Date: Thu, 26 Jan 2017 13:30:14 +0000 Subject: [PATCH 07/19] Updated circle config to be Python 3 --- circle.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/circle.yml b/circle.yml index 8e6cfe6..2d2ce88 100644 --- a/circle.yml +++ b/circle.yml @@ -1,4 +1,6 @@ machine: - environment: - DJANGO_SETTINGS_MODULE: config.settings.test - DATABASE_URL: postgres://ubuntu:@127.0.0.1:5432/circle_test + python: + version: 3.5.0 + environment: + DJANGO_SETTINGS_MODULE: config.settings.test + DATABASE_URL: postgres://ubuntu:@127.0.0.1:5432/circle_test From 3f4150b176f6703712ecbbf28aca0ab7b1fd062b Mon Sep 17 00:00:00 2001 From: Oly Date: Thu, 26 Jan 2017 17:35:29 +0000 Subject: [PATCH 08/19] fix existing tests --- mhackspace/subscriptions/payments.py | 46 ++--------------- .../tests/test_payment_gateways.py | 49 ++++++++++++++----- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index 6b6fbd1..2db4533 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -4,7 +4,6 @@ import gocardless import braintree from django.conf import settings -print(dir(settings)) payment_providers = settings.PAYMENT_PROVIDERS # import gocardless_pro @@ -47,18 +46,15 @@ class gocardless_provider: return { 'amount': subscription.amount, 'start_date': subscription.created_at, - 'reference': subscription.id + 'reference': subscription.id, + 'success': response.success } def fetch_subscriptions(self): for paying_member in self.client.subscriptions(): user=paying_member.user() - # for bill in paying_member.bills(): - # print('test') - # print(dir(bill)) - # print(bill.created_at) - # print(dir(paying_member)) - # print(paying_member.reference_fields) + + #gocardless does not have a reference so we use the id instead yield { 'status': paying_member.status, 'email': user.email, @@ -201,40 +197,6 @@ class payment: 'reference': paying_member.id, 'amount': paying_member.amount} - if self.provider == 'paypal': - #~ I-S39170DK26AF - #~ start_date, end_date = "2014-07-01", "2014-07-20" - billing_agreement = paypal.BillingAgreement.find('') - print(billing_agreement) - print(dir(billing_agreement)) - #~ print billing_agreement.search_transactions(start_date, end_date) - #~ transactions = billing_agreement.search_transactions(start_date, end_date) - payment_history = paypal.Payment.all({"count": 2}) - - # List Payments - print("List Payment:") - print(payment_history) - for payment in payment_history.payments: - print(" -> Payment[%s]" % (payment.id)) - #~ print paypal.BillingAgreement.all() - history = paypal.BillingPlan.all( - {"status": "CREATED", "page_size": 5, "page": 1, "total_required": "yes"}) - print(history) - - print("List BillingPlan:") - for plan in history.plans: - print(dir(plan)) - print(plan.to_dict()) - print(" -> BillingPlan[%s]" % (plan.id)) - - #~ merchant = gocardless.client.merchant() - #~ for paying_member in merchant.subscriptions(): - #~ user=paying_member.user() - #~ yield { - #~ 'email': user.email, - #~ 'start_date': paying_member.created_at, - #~ 'reference': paying_member.id, - #~ 'amount': paying_member.amount} def subscribe_confirm(self, args): if self.provider == 'gocardless': diff --git a/mhackspace/subscriptions/tests/test_payment_gateways.py b/mhackspace/subscriptions/tests/test_payment_gateways.py index 81c686b..acb65e2 100644 --- a/mhackspace/subscriptions/tests/test_payment_gateways.py +++ b/mhackspace/subscriptions/tests/test_payment_gateways.py @@ -26,31 +26,56 @@ class TestPaymentGatewaysGocardless(TestCase): self.provider = gocardless_provider() return self.provider #self.provider - def test_confirm_subscription_callback(self): - with patch('gocardless.client.confirm_resources') as mock_subscription: - self.provider = gocardless_provider() - - def test_fetch_subscription_gocardless(self): - items = [Mock( + # @patch('mhackspace.subscriptions.payments.gocardless.request.requests.get', autospec=True) + @patch('mhackspace.subscriptions.payments.gocardless.client.subscription', autospec=True) + @patch('mhackspace.subscriptions.payments.gocardless.client.confirm_resource', autospec=True) + def test_confirm_subscription_callback(self, mock_confirm, mock_subscription): + mock_confirm.return_value = Mock(success='success') + mock_subscription.return_value = Mock( id='01', status='active', amount=20.00, - reference='ref01', created_at='date' - )] - items[-1].user.return_value = Mock(email='test@test.com') + ) + + request_params = { + 'resource_uri': 'http://gocardless/resource/url/01', + 'resource_id': '01', + 'resource_type': 'subscription', + 'signature': 'sig', + 'state': 'inactive' + } + + result = self.provider.subscribe_confirm(request_params) + + self.assertEqual(result.get('amount'), 20.00) + self.assertEqual(result.get('start_date'), 'date') + self.assertEqual(result.get('reference'), '01') + self.assertEqual(result.get('success'), 'success') + + + def test_fetch_subscription_gocardless(self): + item = Mock( + id='01', + status='active', + amount=20.00, + created_at='date' + ) + item.user.return_value = Mock(email='test@test.com') self.provider.client = Mock() - self.provider.client.subscriptions = Mock(return_value=items) + self.provider.client.subscriptions = Mock(return_value=[item]) + + # mock out gocardless subscriptions method, and return our own values for item in self.provider.fetch_subscriptions(): self.assertEqual(item.get('status'), 'active') self.assertEqual(item.get('email'), 'test@test.com') - self.assertEqual(item.get('reference'), 'ref01') + self.assertEqual(item.get('reference'), '01') self.assertEqual(item.get('start_date'), 'date') self.assertEqual(item.get('amount'), 20.00) -class TestPaymentGatewaysBraintree(TestCase): +class DisabledestPaymentGatewaysBraintree(TestCase): @patch('mhackspace.subscriptions.payments.braintree.Configuration.configure') def auth_braintree(self, mock_request): # mock braintree initalisation request From 6042d68b66356a44da12856af99c2f6050efe6f5 Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Thu, 26 Jan 2017 22:35:59 +0000 Subject: [PATCH 09/19] start of test for unsubscribe button --- mhackspace/subscriptions/payments.py | 10 ++++++++++ .../tests/test_payment_gateways.py | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index 2db4533..6a188d4 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -68,6 +68,16 @@ class gocardless_provider: def get_token(self): return 'N/A' + def cancel_subscribe(self, reference): + subscription = gocardless.client.subscription(reference) + response = subscription.cancel() + return { + 'amount': subscription.amount, + 'start_date': subscription.created_at, + 'reference': subscription.id, + 'success': response.success + } + def create_subscription(self, amount, name, redirect_success, redirect_failure, interval_unit='month', interval_length='1'): return gocardless.client.new_subscription_url( amount=float(amount), diff --git a/mhackspace/subscriptions/tests/test_payment_gateways.py b/mhackspace/subscriptions/tests/test_payment_gateways.py index acb65e2..5b19544 100644 --- a/mhackspace/subscriptions/tests/test_payment_gateways.py +++ b/mhackspace/subscriptions/tests/test_payment_gateways.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from test_plus.test import TestCase -# import unittest +from unittest import skip from mock import patch, Mock from mhackspace.subscriptions.payments import payment, gocardless_provider, braintree_provider @@ -26,6 +26,23 @@ class TestPaymentGatewaysGocardless(TestCase): self.provider = gocardless_provider() return self.provider #self.provider + @skip("Need to implement") + @patch('mhackspace.subscriptions.payments.gocardless.client.subscription', autospec=True) + def test_unsubscribe(self, mock_subscription): + mock_subscription.return_value = Mock(success='success') + mock_subscription.cancel.return_value = Mock( + id='01', + status='active', + amount=20.00, + created_at='date' + ) + result = self.provider.cancel_subscription(reference='M01') + + self.assertEqual(result.get('amount'), 20.00) + self.assertEqual(result.get('start_date'), 'date') + self.assertEqual(result.get('reference'), '01') + self.assertEqual(result.get('success'), 'success') + # @patch('mhackspace.subscriptions.payments.gocardless.request.requests.get', autospec=True) @patch('mhackspace.subscriptions.payments.gocardless.client.subscription', autospec=True) @patch('mhackspace.subscriptions.payments.gocardless.client.confirm_resource', autospec=True) From fb271941bb1892bbf9b646bf4d901dcbb514dca8 Mon Sep 17 00:00:00 2001 From: Oly Date: Sat, 28 Jan 2017 22:34:47 +0000 Subject: [PATCH 10/19] Cleaned up migrations, added refresh subscriptions command to update members status --- .drone.yml | 4 ++ docker-compose.yml | 54 +++++++-------- mhackspace/feeds/migrations/0001_initial.py | 33 +++++++-- .../migrations/0002_auto_20170104_2033.py | 30 -------- .../migrations/0003_auto_20170104_2035.py | 20 ------ .../feeds/migrations/0004_feed_enabled.py | 20 ------ .../feeds/migrations/0005_storing_articles.py | 69 ------------------- mhackspace/members/views.py | 2 +- .../management/commands/list_subscriptions.py | 2 +- .../commands/refresh_subscriptions.py | 51 ++++++++++++++ mhackspace/subscriptions/models.py | 0 mhackspace/templates/pages/members.html | 7 +- mhackspace/templates/users/user_detail.html | 19 ++++- mhackspace/users/forms.py | 6 +- mhackspace/users/migrations/0001_initial.py | 29 +++++++- .../migrations/0002_membership_userblurb.py | 36 ---------- .../users/migrations/0003_user_image.py | 20 ------ .../migrations/0004_auto_20170106_2030.py | 24 ------- .../migrations/0005_auto_20170108_0050.py | 28 -------- mhackspace/users/models.py | 40 +++++++++-- mhackspace/users/views.py | 18 ++--- 21 files changed, 208 insertions(+), 304 deletions(-) delete mode 100644 mhackspace/feeds/migrations/0002_auto_20170104_2033.py delete mode 100644 mhackspace/feeds/migrations/0003_auto_20170104_2035.py delete mode 100644 mhackspace/feeds/migrations/0004_feed_enabled.py delete mode 100644 mhackspace/feeds/migrations/0005_storing_articles.py create mode 100644 mhackspace/subscriptions/management/commands/refresh_subscriptions.py delete mode 100644 mhackspace/subscriptions/models.py delete mode 100644 mhackspace/users/migrations/0002_membership_userblurb.py delete mode 100644 mhackspace/users/migrations/0003_user_image.py delete mode 100644 mhackspace/users/migrations/0004_auto_20170106_2030.py delete mode 100644 mhackspace/users/migrations/0005_auto_20170108_0050.py diff --git a/.drone.yml b/.drone.yml index be2af8f..fb192f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,6 +9,10 @@ pipeline: - cp -n env.example .env - python manage.py test mhackspace --verbosity 2 + deploy: + + + #volumes: # postgres_data_dev: {} # postgres_backup_dev: {} diff --git a/docker-compose.yml b/docker-compose.yml index 8f0abc6..3646dd9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,36 +23,36 @@ services: command: /gunicorn.sh env_file: .env - nginx: - build: ./compose/nginx - depends_on: - - django - - certbot +# nginx: +# build: ./compose/nginx +# depends_on: +# - django +# - certbot - ports: - - "0.0.0.0:80:80" +# ports: +# - "0.0.0.0:80:80" - environment: - - MY_DOMAIN_NAME=maidstone-hackspace.org.uk - ports: - - "0.0.0.0:80:80" - - "0.0.0.0:443:443" - volumes: - - /etc/letsencrypt:/etc/letsencrypt - - /var/lib/letsencrypt:/var/lib/letsencrypt +# environment: +# - MY_DOMAIN_NAME=maidstone-hackspace.org.uk +# ports: +# - "0.0.0.0:80:80" +# - "0.0.0.0:443:443" +# volumes: +# - /etc/letsencrypt:/etc/letsencrypt +# - /var/lib/letsencrypt:/var/lib/letsencrypt - certbot: - image: quay.io/letsencrypt/letsencrypt - command: bash -c "sleep 6 && certbot certonly -n --standalone -d maidstone-hackspace.org.uk --text --agree-tos --email support@maidstone-hackspace.org.uk --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01" - entrypoint: "" - volumes: - - /etc/letsencrypt:/etc/letsencrypt - - /var/lib/letsencrypt:/var/lib/letsencrypt - ports: - - "80" - - "443" - environment: - - TERM=xterm +# certbot: +# image: quay.io/letsencrypt/letsencrypt +# command: bash -c "sleep 6 && certbot certonly -n --standalone -d maidstone-hackspace.org.uk --text --agree-tos --email support@maidstone-hackspace.org.uk --server https://acme-v01.api.letsencrypt.org/directory --rsa-key-size 4096 --verbose --keep-until-expiring --standalone-supported-challenges http-01" +# entrypoint: "" +# volumes: +# - /etc/letsencrypt:/etc/letsencrypt +# - /var/lib/letsencrypt:/var/lib/letsencrypt +# ports: +# - "80" +# - "443" +# environment: +# - TERM=xterm redis: diff --git a/mhackspace/feeds/migrations/0001_initial.py b/mhackspace/feeds/migrations/0001_initial.py index 53bcf3c..4a5c9b9 100644 --- a/mhackspace/feeds/migrations/0001_initial.py +++ b/mhackspace/feeds/migrations/0001_initial.py @@ -1,8 +1,12 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-04 14:04 +# Generated by Django 1.10.5 on 2017-01-28 18:38 from __future__ import unicode_literals from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import stdimage.models +import stdimage.utils class Migration(migrations.Migration): @@ -13,14 +17,35 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('url', models.URLField()), + ('title', models.CharField(max_length=255)), + ('original_image', models.URLField(blank=True, max_length=255, null=True)), + ('image', stdimage.models.StdImageField(blank=True, null=True, upload_to=stdimage.utils.UploadToAutoSlugClassNameDir('title'))), + ('description', models.TextField()), + ('displayed', models.BooleanField(default=True)), + ('date', models.DateTimeField(default=django.utils.timezone.now)), + ], + ), migrations.CreateModel( name='Feed', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('url', models.CharField(max_length=255)), + ('home_url', models.URLField(verbose_name='Site Home Page')), + ('feed_url', models.URLField(verbose_name='RSS Feed URL')), + ('title', models.CharField(max_length=255)), ('author', models.CharField(max_length=255)), - ('tags', models.CharField(max_length=255)), - ('image', models.ImageField(upload_to='')), + ('tags', models.CharField(blank=True, max_length=255)), + ('image', stdimage.models.StdImageField(blank=True, null=True, upload_to=stdimage.utils.UploadToAutoSlugClassNameDir('title'))), + ('enabled', models.BooleanField(default=True)), ], ), + migrations.AddField( + model_name='article', + name='feed', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='feeds.Feed'), + ), ] diff --git a/mhackspace/feeds/migrations/0002_auto_20170104_2033.py b/mhackspace/feeds/migrations/0002_auto_20170104_2033.py deleted file mode 100644 index 4f8bd15..0000000 --- a/mhackspace/feeds/migrations/0002_auto_20170104_2033.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-04 20:33 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('feeds', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='feed', - name='id', - field=models.IntegerField(primary_key=True, serialize=False), - ), - migrations.AlterField( - model_name='feed', - name='image', - field=models.ImageField(blank=True, upload_to=''), - ), - migrations.AlterField( - model_name='feed', - name='tags', - field=models.CharField(blank=True, max_length=255), - ), - ] diff --git a/mhackspace/feeds/migrations/0003_auto_20170104_2035.py b/mhackspace/feeds/migrations/0003_auto_20170104_2035.py deleted file mode 100644 index 55a38dc..0000000 --- a/mhackspace/feeds/migrations/0003_auto_20170104_2035.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-04 20:35 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('feeds', '0002_auto_20170104_2033'), - ] - - operations = [ - migrations.AlterField( - model_name='feed', - name='id', - field=models.AutoField(primary_key=True, serialize=False), - ), - ] diff --git a/mhackspace/feeds/migrations/0004_feed_enabled.py b/mhackspace/feeds/migrations/0004_feed_enabled.py deleted file mode 100644 index 9579887..0000000 --- a/mhackspace/feeds/migrations/0004_feed_enabled.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-04 21:39 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('feeds', '0003_auto_20170104_2035'), - ] - - operations = [ - migrations.AddField( - model_name='feed', - name='enabled', - field=models.BooleanField(default=True), - ), - ] diff --git a/mhackspace/feeds/migrations/0005_storing_articles.py b/mhackspace/feeds/migrations/0005_storing_articles.py deleted file mode 100644 index 0734fba..0000000 --- a/mhackspace/feeds/migrations/0005_storing_articles.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-08 03:42 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone -import stdimage.models -import stdimage.utils - - -class Migration(migrations.Migration): - - dependencies = [ - ('feeds', '0004_feed_enabled'), - ] - - operations = [ - migrations.CreateModel( - name='Article', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('url', models.URLField()), - ('title', models.CharField(max_length=255)), - ('original_image', models.URLField(blank=True, max_length=255, null=True)), - ('image', stdimage.models.StdImageField(blank=True, null=True, upload_to=stdimage.utils.UploadToAutoSlugClassNameDir('title'))), - ('description', models.TextField()), - ('displayed', models.BooleanField(default=True)), - ('date', models.DateTimeField(default=django.utils.timezone.now)), - ], - ), - migrations.RemoveField( - model_name='feed', - name='url', - ), - migrations.AddField( - model_name='feed', - name='feed_url', - field=models.URLField(default='http://thearduinoguy.org/?feed=rss2', verbose_name='RSS Feed URL'), - preserve_default=False, - ), - migrations.AddField( - model_name='feed', - name='home_url', - field=models.URLField(default='http://thearduinoguy.org/', verbose_name='Site Home Page'), - preserve_default=False, - ), - migrations.AddField( - model_name='feed', - name='title', - field=models.CharField(default='The Arduino Guy', max_length=255), - preserve_default=False, - ), - migrations.AlterField( - model_name='feed', - name='id', - field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='feed', - name='image', - field=stdimage.models.StdImageField(blank=True, null=True, upload_to=stdimage.utils.UploadToAutoSlugClassNameDir('title')), - ), - migrations.AddField( - model_name='article', - name='feed', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='feeds.Feed'), - ), - ] diff --git a/mhackspace/members/views.py b/mhackspace/members/views.py index dbc597c..34972b2 100644 --- a/mhackspace/members/views.py +++ b/mhackspace/members/views.py @@ -10,7 +10,7 @@ from mhackspace.users.models import User class MemberListView(LoginRequiredMixin, ListView): template_name = 'pages/members.html' - queryset = User.objects.prefetch_related('users', 'groups') + queryset = User.objects.prefetch_related('user', 'groups') paginate_by = 10 def get_context_data(self, **kwargs): diff --git a/mhackspace/subscriptions/management/commands/list_subscriptions.py b/mhackspace/subscriptions/management/commands/list_subscriptions.py index a4e1d39..dc8f84c 100644 --- a/mhackspace/subscriptions/management/commands/list_subscriptions.py +++ b/mhackspace/subscriptions/management/commands/list_subscriptions.py @@ -24,4 +24,4 @@ class Command(BaseCommand): for sub in provider.fetch_subscriptions(): self.stdout.write( self.style.SUCCESS( - '\t{reference} - {amount} - {status} - {email}'.format(**sub))) + '\t{start_date} {reference} - {amount} - {status} - {email}'.format(**sub))) diff --git a/mhackspace/subscriptions/management/commands/refresh_subscriptions.py b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py new file mode 100644 index 0000000..9406808 --- /dev/null +++ b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py @@ -0,0 +1,51 @@ +from datetime import datetime +from django.utils import timezone +from django.contrib.auth.models import Group +from django.forms.models import model_to_dict +from django.core.management.base import BaseCommand +from mhackspace.subscriptions.payments import select_provider +from mhackspace.users.models import Membership, User + + +class Command(BaseCommand): + help = 'Update user subscriptions' + + def handle(self, *args, **options): + provider = select_provider('gocardless') + + self.stdout.write( + self.style.NOTICE( + '== Gocardless subscriptions ==')) + + Membership.objects.all().delete() + subscriptions = [] + + group = Group.objects.get(name='member') + + for sub in provider.fetch_subscriptions(): + try: + user_model = User.objects.get(email=sub.get('email')) + if sub.get('status') == 'active': + user_model.groups.add(group) + except User.DoesNotExist: + user_model = None + + self.stdout.write(sub.get('status')) + subscriptions.append( + Membership( + user= user_model, + 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')) + ) + ) + + self.stdout.write( + self.style.SUCCESS( + '\t{reference} - {payment} - {status} - {email}'.format(**model_to_dict(subscriptions[-1])))) + + Membership.objects.bulk_create(subscriptions) + diff --git a/mhackspace/subscriptions/models.py b/mhackspace/subscriptions/models.py deleted file mode 100644 index e69de29..0000000 diff --git a/mhackspace/templates/pages/members.html b/mhackspace/templates/pages/members.html index e009e7c..265c63a 100644 --- a/mhackspace/templates/pages/members.html +++ b/mhackspace/templates/pages/members.html @@ -4,8 +4,8 @@ Members feed
-
Users {{ paginator.count }}
-
Members {{ total }}
+
Users {{ paginator.count }}
+
Members {{ total }}
@@ -17,13 +17,14 @@ Members feed

{{ member.name }}

{{ member.users.description }}

{{ member.users.skills }}

+

{{ member.status }}

{% for group in member.groups.all %} {{ group.name }} {% endfor %}
-

{{ member.userblurb }}

+

{{ member.blurb }}

View Original diff --git a/mhackspace/templates/users/user_detail.html b/mhackspace/templates/users/user_detail.html index 13f5a1b..054fb0e 100644 --- a/mhackspace/templates/users/user_detail.html +++ b/mhackspace/templates/users/user_detail.html @@ -5,7 +5,21 @@ {% block content %}
- +

Profile

@@ -18,13 +32,14 @@

Member since

Description: {{ blurb.description }}

Skills: {{ blurb.description }}

+

Membership Status: {{ membership.get_status }}

Joined
-

MHS{{ user.id|stringformat:"05d" }}

Change me

+

MHS{{ user.id|stringformat:"05d" }}

{{user.name}}{{user.last_name}}

Cancel Membership
diff --git a/mhackspace/users/forms.py b/mhackspace/users/forms.py index 73b16ff..4c2b43e 100644 --- a/mhackspace/users/forms.py +++ b/mhackspace/users/forms.py @@ -2,9 +2,9 @@ from django.db import models from django.forms import ModelForm -from .models import UserBlurb +from .models import Blurb -class UserBlurbForm(ModelForm): +class BlurbForm(ModelForm): class Meta: - model = UserBlurb + model = Blurb exclude = ['user'] diff --git a/mhackspace/users/migrations/0001_initial.py b/mhackspace/users/migrations/0001_initial.py index e76c333..def69a6 100644 --- a/mhackspace/users/migrations/0001_initial.py +++ b/mhackspace/users/migrations/0001_initial.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-09-23 04:36 +# Generated by Django 1.10.5 on 2017-01-28 19:46 from __future__ import unicode_literals +from django.conf import settings import django.contrib.auth.models import django.contrib.auth.validators from django.db import migrations, models +import django.db.models.deletion import django.utils.timezone +import stdimage.models class Migration(migrations.Migration): @@ -32,16 +35,38 @@ class Migration(migrations.Migration): ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('name', models.CharField(blank=True, max_length=255, verbose_name='Name of User')), + ('image', stdimage.models.StdImageField(blank=True, null=True, upload_to='avatars/')), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ], options={ - 'verbose_name_plural': 'users', 'verbose_name': 'user', 'abstract': False, + 'verbose_name_plural': 'users', }, managers=[ ('objects', django.contrib.auth.models.UserManager()), ], ), + migrations.CreateModel( + name='Blurb', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('skills', models.CharField(max_length=255)), + ('description', models.TextField()), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Membership', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('payment', models.DecimalField(decimal_places=2, default=0.0, max_digits=6)), + ('date', models.DateTimeField()), + ('reference', models.CharField(max_length=255)), + ('status', models.PositiveSmallIntegerField(default=0)), + ('email', models.CharField(max_length=255)), + ('user', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL)), + ], + ), ] diff --git a/mhackspace/users/migrations/0002_membership_userblurb.py b/mhackspace/users/migrations/0002_membership_userblurb.py deleted file mode 100644 index 4e0c458..0000000 --- a/mhackspace/users/migrations/0002_membership_userblurb.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-06 08:53 -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', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Membership', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment', models.DecimalField(decimal_places=2, max_digits=6)), - ('date', models.DateTimeField()), - ('reference', models.CharField(max_length=255)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='UserBlurb', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('skills', models.CharField(max_length=255)), - ('description', models.TextField()), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/mhackspace/users/migrations/0003_user_image.py b/mhackspace/users/migrations/0003_user_image.py deleted file mode 100644 index f55e304..0000000 --- a/mhackspace/users/migrations/0003_user_image.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-06 19:03 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_membership_userblurb'), - ] - - operations = [ - migrations.AddField( - model_name='user', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='/upload/avatars'), - ), - ] diff --git a/mhackspace/users/migrations/0004_auto_20170106_2030.py b/mhackspace/users/migrations/0004_auto_20170106_2030.py deleted file mode 100644 index c98e20c..0000000 --- a/mhackspace/users/migrations/0004_auto_20170106_2030.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-06 20:30 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0003_user_image'), - ] - - operations = [ - migrations.RenameModel( - old_name='Membership', - new_name='UserMembership', - ), - migrations.AlterField( - model_name='user', - name='image', - field=models.ImageField(blank=True, null=True, upload_to='avatars/'), - ), - ] diff --git a/mhackspace/users/migrations/0005_auto_20170108_0050.py b/mhackspace/users/migrations/0005_auto_20170108_0050.py deleted file mode 100644 index 2d05065..0000000 --- a/mhackspace/users/migrations/0005_auto_20170108_0050.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.4 on 2017-01-08 00:50 -from __future__ import unicode_literals - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import stdimage.models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_auto_20170106_2030'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='image', - field=stdimage.models.StdImageField(blank=True, null=True, upload_to='avatars/'), - ), - migrations.AlterField( - model_name='userblurb', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='users', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/mhackspace/users/models.py b/mhackspace/users/models.py index 9c2b3e8..b056cac 100644 --- a/mhackspace/users/models.py +++ b/mhackspace/users/models.py @@ -29,14 +29,44 @@ class User(AbstractUser): return reverse('users:detail', kwargs={'username': self.username}) -class UserBlurb(models.Model): - user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='users') +class Blurb(models.Model): + user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='+') skills = models.CharField(max_length=255) description = models.TextField() -class UserMembership(models.Model): - user = models.ForeignKey(settings.AUTH_USER_MODEL) - payment = models.DecimalField(max_digits=6, decimal_places=2) +MEMBERSHIP_STRING = { + 0: 'Non Member', + 1: 'Member', + 3: 'Membership Expired' +} + +MEMBERSHIP_STATUS = { + 'active': 1, + 'cancelled': 2 +} + +class Membership(models.Model): + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + null=True, blank=True, + default=None, + related_name='user' + ) + payment = models.DecimalField(max_digits=6, decimal_places=2, default=0.0) date = models.DateTimeField() reference = models.CharField(max_length=255) + status = models.PositiveSmallIntegerField(default=0) + email = models.CharField(max_length=255) + + @property + def get_status(self): + return MEMBERSHIP_STRING[self.status] + + def lookup_status(name): + if not name: + return 0 + return MEMBERSHIP_STATUS.get(name.lower(), 0) + + def __str__(self): + return self.reference diff --git a/mhackspace/users/views.py b/mhackspace/users/views.py index bbdfb07..e511bcd 100644 --- a/mhackspace/users/views.py +++ b/mhackspace/users/views.py @@ -7,10 +7,10 @@ from django.views.generic import DetailView, ListView, RedirectView, UpdateView from django.contrib.auth.mixins import LoginRequiredMixin from .models import User -from .models import UserBlurb -from .models import UserMembership +from .models import Blurb +from .models import Membership -from .forms import UserBlurbForm +from .forms import BlurbForm class UserDetailView(LoginRequiredMixin, DetailView): model = User @@ -21,8 +21,8 @@ class UserDetailView(LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): # xxx will be available in the template as the related objects context = super(UserDetailView, self).get_context_data(**kwargs) - context['blurb'] = UserBlurb.objects.filter(user=self.get_object()).first() - context['membership'] = UserMembership.objects.filter(user=self.get_object()).first() + context['blurb'] = Blurb.objects.filter(user=self.get_object()).first() + context['membership'] = Membership.objects.filter(user=self.get_object()).first() return context class UserRedirectView(LoginRequiredMixin, RedirectView): @@ -45,8 +45,8 @@ class UserUpdateView(LoginRequiredMixin, UpdateView): def get_context_data(self, **kwargs): context = super(UserUpdateView, self).get_context_data(**kwargs) - profile = UserBlurb.objects.filter(user=self.get_object()).first() - context['form_blurb'] = UserBlurbForm(instance=profile) + profile = Blurb.objects.filter(user=self.get_object()).first() + context['form_blurb'] = BlurbForm(instance=profile) return context def get_object(self): @@ -54,8 +54,8 @@ class UserUpdateView(LoginRequiredMixin, UpdateView): return User.objects.get(username=self.request.user.username) def form_valid(self, form): - profile = UserBlurb.objects.filter(user=self.get_object()).first() - form_blurb = UserBlurbForm(self.request.POST, instance=profile) + profile = Blurb.objects.filter(user=self.get_object()).first() + form_blurb = BlurbForm(self.request.POST, instance=profile) if form_blurb.is_valid(): blurb_model = form_blurb.save(commit=False) blurb_model.user = self.request.user From e5c1e15010e7c4e8f0f073ffba136c769bce61ab Mon Sep 17 00:00:00 2001 From: Oly Date: Mon, 30 Jan 2017 17:08:37 +0000 Subject: [PATCH 11/19] more work on payment gateway --- mhackspace/members/views.py | 2 +- .../commands/list_subscription_payments.py | 41 ++++++++++++++++++ .../commands/refresh_subscriptions.py | 2 +- .../subscriptions/migrations/0001_initial.py | 32 ++++++++++++++ .../subscriptions/migrations/__init__.py | 0 mhackspace/subscriptions/models.py | 42 +++++++++++++++++++ mhackspace/subscriptions/payments.py | 33 +++++++++++++++ mhackspace/templates/pages/home.html | 2 + mhackspace/templates/users/user_detail.html | 2 +- mhackspace/users/fixtures/groups.json | 2 + 10 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 mhackspace/subscriptions/management/commands/list_subscription_payments.py create mode 100644 mhackspace/subscriptions/migrations/0001_initial.py create mode 100644 mhackspace/subscriptions/migrations/__init__.py create mode 100644 mhackspace/subscriptions/models.py create mode 100644 mhackspace/users/fixtures/groups.json diff --git a/mhackspace/members/views.py b/mhackspace/members/views.py index 34972b2..4518a32 100644 --- a/mhackspace/members/views.py +++ b/mhackspace/members/views.py @@ -16,5 +16,5 @@ class MemberListView(LoginRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super(MemberListView, self).get_context_data(**kwargs) context['members'] = self.get_queryset() - context['total'] = self.get_queryset().filter(groups__name='member').count() + context['total'] = self.get_queryset().filter(groups__name='members').count() return context diff --git a/mhackspace/subscriptions/management/commands/list_subscription_payments.py b/mhackspace/subscriptions/management/commands/list_subscription_payments.py new file mode 100644 index 0000000..930cea4 --- /dev/null +++ b/mhackspace/subscriptions/management/commands/list_subscription_payments.py @@ -0,0 +1,41 @@ +from datetime import datetime +from django.utils import timezone +from django.contrib.auth.models import Group +from django.forms.models import model_to_dict +from django.core.management.base import BaseCommand +from mhackspace.subscriptions.payments import select_provider +from mhackspace.users.models import Membership, User +from mhackspace.subscriptions.models import Payments + + +class Command(BaseCommand): + help = 'Update user subscriptions' + + def handle(self, *args, **options): + provider = select_provider('gocardless') + + self.stdout.write( + self.style.NOTICE( + '== Gocardless customers ==')) + + Payments.objects.all().delete() + for customer in provider.fetch_customers(): + self.stdout.write(str(dir(customer))) + self.stdout.write(str(customer)) + + Payments.objects.create( + user=None, + user_reference=customer.get('user_id'), + user_email=customer.get('email'), + reference=customer.get('payment_id'), + amount=customer.get('amount'), + type=Payments.lookup_payment_type(customer.get('payment_type')), + date=customer.get('payment_date') + ) + # self.stdout.write(str(customer.email)) + # self.stdout.write(str(dir(customer['email']()))) + # self.stdout.write( + # self.style.SUCCESS( + # '\t{reference} - {payment} - {status} - {email}'.format(**model_to_dict(subscriptions[-1])))) + + diff --git a/mhackspace/subscriptions/management/commands/refresh_subscriptions.py b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py index 9406808..ebcfddc 100644 --- a/mhackspace/subscriptions/management/commands/refresh_subscriptions.py +++ b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py @@ -20,7 +20,7 @@ class Command(BaseCommand): Membership.objects.all().delete() subscriptions = [] - group = Group.objects.get(name='member') + group = Group.objects.get(name='members') for sub in provider.fetch_subscriptions(): try: diff --git a/mhackspace/subscriptions/migrations/0001_initial.py b/mhackspace/subscriptions/migrations/0001_initial.py new file mode 100644 index 0000000..4ce244f --- /dev/null +++ b/mhackspace/subscriptions/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-01-29 21:55 +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): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Payments', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user_reference', models.CharField(max_length=255)), + ('user_email', models.CharField(max_length=255)), + ('reference', models.CharField(max_length=255, unique=True)), + ('amount', models.DecimalField(decimal_places=2, default=0.0, max_digits=6)), + ('type', models.PositiveSmallIntegerField(default=0)), + ('date', models.DateTimeField()), + ('user', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='from_user', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/mhackspace/subscriptions/migrations/__init__.py b/mhackspace/subscriptions/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mhackspace/subscriptions/models.py b/mhackspace/subscriptions/models.py new file mode 100644 index 0000000..a2b7770 --- /dev/null +++ b/mhackspace/subscriptions/models.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, absolute_import + +from django.conf import settings +from django.contrib.auth.models import AbstractUser +from django.core.urlresolvers import reverse +from django.db import models +from django.utils.encoding import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ +from stdimage.models import StdImageField + + +PAYMENT_TYPES = { + 'unknown': 0, + 'subscription': 1, + 'payment': 2 +} + +@python_2_unicode_compatible +class Payments(models.Model): + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + null=True, blank=True, + default=None, + related_name='from_user' + ) + user_reference = models.CharField(max_length=255) + user_email = models.CharField(max_length=255) + + reference = models.CharField(max_length=255, unique=True) + amount = models.DecimalField(max_digits=6, decimal_places=2, default=0.0) + type = models.PositiveSmallIntegerField(default=0) + date = models.DateTimeField() + + def lookup_payment_type(name): + return PAYMENT_TYPES.get(name, 0) + + def get_payment_type(self): + return self.type + + def __str__(self): + return self.reference diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index 6a188d4..d765a42 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -50,6 +50,39 @@ class gocardless_provider: 'success': response.success } + + + def fetch_customers(self): + merchant = gocardless.client.merchant() + for customer in merchant.bills(): + user = customer.user() + print(dir(customer)) + print(dir(customer.reference_fields)) + print(customer.reference_fields) + print(customer.payout_id) + print(customer.reference_fields.payout_id) + result = { + 'user_id': user.id, + 'email': user.email, + 'status': customer.status, + 'payment_id': customer.source_id, + 'payment_type': customer.source_type, + 'payment_date': customer.created_at, + 'amount': customer.amount + } + yield result #customer + + + + # for customer in self.client.users(): + # result = { + # 'email': customer.email, + # 'created_date': customer.created_at, + # 'first_name': customer.first_name, + # 'last_name': customer.last_name + # } + # yield customer + def fetch_subscriptions(self): for paying_member in self.client.subscriptions(): user=paying_member.user() diff --git a/mhackspace/templates/pages/home.html b/mhackspace/templates/pages/home.html index 3220ea9..61c4caf 100644 --- a/mhackspace/templates/pages/home.html +++ b/mhackspace/templates/pages/home.html @@ -4,5 +4,7 @@ {% block content %}

Introduction

Hackspaces are a shared space where artists, designers, makers, hackers, programmers, tinkerers, professionals and hobbyists can work on their projects, share knowledge and collaborate.We are in the process of developing Maidstone Hackspace. We're previous members of (ICMP) and looking to form a new space in the future. At the moment, communication is via google groups, email, and the website. If you're at all intrested please join our mailing list and make yourself known! + + Click here to chat with us https://hangouts.google.com/group/oDcAL0nDfQYfO3qq1 {% show_feeds %} {% endblock content %} diff --git a/mhackspace/templates/users/user_detail.html b/mhackspace/templates/users/user_detail.html index 054fb0e..f5954f2 100644 --- a/mhackspace/templates/users/user_detail.html +++ b/mhackspace/templates/users/user_detail.html @@ -36,7 +36,7 @@
-
Joined
+
Joined {{membership.start_date}}

MHS{{ user.id|stringformat:"05d" }}

{{user.name}}{{user.last_name}}

diff --git a/mhackspace/users/fixtures/groups.json b/mhackspace/users/fixtures/groups.json new file mode 100644 index 0000000..ab3af61 --- /dev/null +++ b/mhackspace/users/fixtures/groups.json @@ -0,0 +1,2 @@ +Postgres is up - continuing... +[{"model": "auth.group", "pk": 1, "fields": {"name": "members", "permissions": []}}] \ No newline at end of file From 5b223d23cd7ff437f34773a2213e6a36df7b1eac Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Mon, 30 Jan 2017 22:39:15 +0000 Subject: [PATCH 12/19] new command works needs improvement, fix fixtures file thanks for pointing that out @mightyscollins --- .../commands/list_subscription_payments.py | 22 +++++++++++-------- mhackspace/subscriptions/payments.py | 12 +++++----- mhackspace/users/fixtures/groups.json | 3 +-- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/mhackspace/subscriptions/management/commands/list_subscription_payments.py b/mhackspace/subscriptions/management/commands/list_subscription_payments.py index 930cea4..fc575d6 100644 --- a/mhackspace/subscriptions/management/commands/list_subscription_payments.py +++ b/mhackspace/subscriptions/management/commands/list_subscription_payments.py @@ -16,14 +16,16 @@ class Command(BaseCommand): self.stdout.write( self.style.NOTICE( - '== Gocardless customers ==')) + '== Gocardless customer payments ==')) Payments.objects.all().delete() - for customer in provider.fetch_customers(): - self.stdout.write(str(dir(customer))) - self.stdout.write(str(customer)) - Payments.objects.create( + payment_objects = [] + for customer in provider.fetch_customers(): + # self.stdout.write(str(dir(customer))) + # self.stdout.write(str(customer)) + + payment_objects.append(Payments( user=None, user_reference=customer.get('user_id'), user_email=customer.get('email'), @@ -31,11 +33,13 @@ class Command(BaseCommand): amount=customer.get('amount'), type=Payments.lookup_payment_type(customer.get('payment_type')), date=customer.get('payment_date') - ) + )) # self.stdout.write(str(customer.email)) # self.stdout.write(str(dir(customer['email']()))) - # self.stdout.write( - # self.style.SUCCESS( - # '\t{reference} - {payment} - {status} - {email}'.format(**model_to_dict(subscriptions[-1])))) + self.stdout.write( + self.style.SUCCESS( + '\t{reference} - {amount} - {type} - {user_email}'.format(**model_to_dict(payment_objects[-1])))) + + Payments.objects.bulk_create(payment_objects) diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index d765a42..26ff92e 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -56,16 +56,16 @@ class gocardless_provider: merchant = gocardless.client.merchant() for customer in merchant.bills(): user = customer.user() - print(dir(customer)) - print(dir(customer.reference_fields)) - print(customer.reference_fields) - print(customer.payout_id) - print(customer.reference_fields.payout_id) + # print(dir(customer)) + # print(dir(customer.reference_fields)) + # print(customer.reference_fields) + # print(customer.payout_id) + # print(customer.reference_fields.payout_id) result = { 'user_id': user.id, 'email': user.email, 'status': customer.status, - 'payment_id': customer.source_id, + 'payment_id': customer.id, 'payment_type': customer.source_type, 'payment_date': customer.created_at, 'amount': customer.amount diff --git a/mhackspace/users/fixtures/groups.json b/mhackspace/users/fixtures/groups.json index ab3af61..7a946f2 100644 --- a/mhackspace/users/fixtures/groups.json +++ b/mhackspace/users/fixtures/groups.json @@ -1,2 +1 @@ -Postgres is up - continuing... -[{"model": "auth.group", "pk": 1, "fields": {"name": "members", "permissions": []}}] \ No newline at end of file +[{"model": "auth.group", "pk": 1, "fields": {"name": "members", "permissions": []}}] From e94dfbac9c998dd80f3094a12485e8afb0f1ca31 Mon Sep 17 00:00:00 2001 From: Sam Collins Date: Mon, 30 Jan 2017 23:02:31 +0000 Subject: [PATCH 13/19] Remove Postgres status message Removed the echo in hope it will stop interfering with fixtures --- compose/django/entrypoint.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/compose/django/entrypoint.sh b/compose/django/entrypoint.sh index eb70a65..158fe37 100644 --- a/compose/django/entrypoint.sh +++ b/compose/django/entrypoint.sh @@ -33,5 +33,4 @@ until postgres_ready; do sleep 1 done ->&2 echo "Postgres is up - continuing..." exec $cmd From 411dedf00d4ba269c95b987564aba83a8ff70600 Mon Sep 17 00:00:00 2001 From: Oly Date: Wed, 1 Feb 2017 14:01:50 +0000 Subject: [PATCH 14/19] clean up refresg commands and start on docker-compose files for stage --- compose/django/gunicorn.sh | 2 +- compose/nginx/Dockerfile | 2 +- docker-compose.yml | 33 ++++++++++--------- .../commands/refresh_subscriptions.py | 12 +++---- mhackspace/templates/users/user_detail.html | 7 ++-- mhackspace/users/models.py | 4 +-- 6 files changed, 32 insertions(+), 28 deletions(-) diff --git a/compose/django/gunicorn.sh b/compose/django/gunicorn.sh index 014f173..21f8633 100644 --- a/compose/django/gunicorn.sh +++ b/compose/django/gunicorn.sh @@ -1,3 +1,3 @@ #!/bin/sh python /app/manage.py collectstatic --noinput -/usr/local/bin/gunicorn config.wsgi -w 4 -b 0.0.0.0:5000 --chdir=/app \ No newline at end of file +/usr/local/bin/gunicorn config.wsgi -w 4 -b unix:/data/sockets/gunicorn.sock --chdir=/app diff --git a/compose/nginx/Dockerfile b/compose/nginx/Dockerfile index 5984825..136fd5d 100644 --- a/compose/nginx/Dockerfile +++ b/compose/nginx/Dockerfile @@ -4,6 +4,6 @@ ADD nginx.conf /etc/nginx/nginx.conf ADD start.sh /start.sh ADD nginx-secure.conf /etc/nginx/nginx-secure.conf -ADD dhparams.pem /etc/ssl/private/dhparams.pem +#ADD dhparams.pem /etc/ssl/private/dhparams.pem CMD /start.sh diff --git a/docker-compose.yml b/docker-compose.yml index 3646dd9..3e77fa4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,7 @@ version: '2' volumes: + gunicorn_socket: {} postgres_data: {} postgres_backup: {} @@ -22,24 +23,24 @@ services: - redis command: /gunicorn.sh env_file: .env + volumes: + - .:/app + - gunicorn_socket:/data/sockets/ -# nginx: -# build: ./compose/nginx -# depends_on: -# - django -# - certbot + nginx: + build: ./compose/nginx + depends_on: + - django +# - certbot -# ports: -# - "0.0.0.0:80:80" - -# environment: -# - MY_DOMAIN_NAME=maidstone-hackspace.org.uk -# ports: -# - "0.0.0.0:80:80" -# - "0.0.0.0:443:443" -# volumes: -# - /etc/letsencrypt:/etc/letsencrypt -# - /var/lib/letsencrypt:/var/lib/letsencrypt + environment: + - MY_DOMAIN_NAME=maidstone-hackspace.org.uk + ports: + - "0.0.0.0:80:80" +# - "0.0.0.0:443:443" +# volumes: +# - /etc/letsencrypt:/etc/letsencrypt +# - /var/lib/letsencrypt:/var/lib/letsencrypt # certbot: # image: quay.io/letsencrypt/letsencrypt diff --git a/mhackspace/subscriptions/management/commands/refresh_subscriptions.py b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py index ebcfddc..aeecff9 100644 --- a/mhackspace/subscriptions/management/commands/refresh_subscriptions.py +++ b/mhackspace/subscriptions/management/commands/refresh_subscriptions.py @@ -33,12 +33,12 @@ class Command(BaseCommand): self.stdout.write(sub.get('status')) subscriptions.append( Membership( - user= user_model, - email= sub.get('email'), - reference= sub.get('reference'), - payment= 10.00, - # 'date'= sub.get('start_date'), - date=timezone.now(), + user=user_model, + 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')) ) ) diff --git a/mhackspace/templates/users/user_detail.html b/mhackspace/templates/users/user_detail.html index f5954f2..e731a00 100644 --- a/mhackspace/templates/users/user_detail.html +++ b/mhackspace/templates/users/user_detail.html @@ -24,7 +24,6 @@
Profile image -

{{ user.username }}

{{ user.name }}

{{ user.email }}

@@ -32,11 +31,15 @@

Member since

Description: {{ blurb.description }}

Skills: {{ blurb.description }}

+ +

Membership status

Membership Status: {{ membership.get_status }}

+

Last Payment: {{membership.date}}

+

Amount: £{{membership.payment}}

-
Joined {{membership.start_date}}
+
Joined {{membership.date}}

MHS{{ user.id|stringformat:"05d" }}

{{user.name}}{{user.last_name}}

diff --git a/mhackspace/users/models.py b/mhackspace/users/models.py index b056cac..a021f33 100644 --- a/mhackspace/users/models.py +++ b/mhackspace/users/models.py @@ -36,8 +36,8 @@ class Blurb(models.Model): MEMBERSHIP_STRING = { - 0: 'Non Member', - 1: 'Member', + 0: 'Guest user', + 1: 'Active membership', 3: 'Membership Expired' } From 9faf03f1e7e5720ec8ec892d0c39d62d6593f07b Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Wed, 1 Feb 2017 22:26:13 +0000 Subject: [PATCH 15/19] initial docker setup for staging now works --- compose/django/Dockerfile | 4 +- compose/django/gunicorn.sh | 3 ++ compose/nginx/nginx.conf | 15 ++++---- config/settings/common.py | 3 +- config/settings/production.py | 3 ++ docker-compose.yml | 23 ++++++++++-- live.yml | 55 ++++++++++++++++++++++++++++ mhackspace/subscriptions/payments.py | 2 - mhackspace/templates/base.html | 15 +++++++- requirements/base.txt | 5 +-- staticfiles/staticfiles | 0 11 files changed, 109 insertions(+), 19 deletions(-) create mode 100644 live.yml create mode 100644 staticfiles/staticfiles diff --git a/compose/django/Dockerfile b/compose/django/Dockerfile index a198604..b26d2fd 100644 --- a/compose/django/Dockerfile +++ b/compose/django/Dockerfile @@ -11,6 +11,7 @@ RUN pip install -r /requirements/production.txt \ COPY . /app RUN chown -R django /app +RUN mkdir -p /data/sockets COPY ./compose/django/gunicorn.sh /gunicorn.sh COPY ./compose/django/entrypoint.sh /entrypoint.sh @@ -19,7 +20,8 @@ RUN sed -i 's/\r//' /entrypoint.sh \ && chmod +x /entrypoint.sh \ && chown django /entrypoint.sh \ && chmod +x /gunicorn.sh \ - && chown django /gunicorn.sh + && chown django /gunicorn.sh \ + && chown django /data/sockets WORKDIR /app diff --git a/compose/django/gunicorn.sh b/compose/django/gunicorn.sh index 21f8633..52c50ca 100644 --- a/compose/django/gunicorn.sh +++ b/compose/django/gunicorn.sh @@ -1,3 +1,6 @@ #!/bin/sh python /app/manage.py collectstatic --noinput +chmod 777 -R /data/sockets/ +touch /data/sockets/gunicron.sock +ls -la /data/sockets/ /usr/local/bin/gunicorn config.wsgi -w 4 -b unix:/data/sockets/gunicorn.sock --chdir=/app diff --git a/compose/nginx/nginx.conf b/compose/nginx/nginx.conf index 3b9d2a3..a200939 100644 --- a/compose/nginx/nginx.conf +++ b/compose/nginx/nginx.conf @@ -26,7 +26,8 @@ http { #gzip on; upstream app { - server django:5000; + #server django:5000; + server unix:/data/sockets/gunicorn.sock; } server { @@ -36,12 +37,12 @@ http { server_name ___my.example.com___ ; - location /.well-known/acme-challenge { - proxy_pass http://certbot:80; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto https; - } +# location /.well-known/acme-challenge { +# proxy_pass http://certbot:80; +# proxy_set_header Host $host; +# proxy_set_header X-Forwarded-For $remote_addr; +# proxy_set_header X-Forwarded-Proto https; +# } location / { diff --git a/config/settings/common.py b/config/settings/common.py index 2e505d0..d60d0f3 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -189,6 +189,7 @@ STATICFILES_DIRS = ( STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + 'sass_processor.finders.CssFinder', ) # MEDIA CONFIGURATION @@ -252,7 +253,7 @@ LOGIN_URL = 'account_login' AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify' # django-compressor # ------------------------------------------------------------------------------ -INSTALLED_APPS += ("compressor", ) +INSTALLED_APPS += ("compressor", 'sass_processor',) STATICFILES_FINDERS += ("compressor.finders.CompressorFinder", ) # Location of root django.contrib.admin URL, use {% url 'admin:index' %} diff --git a/config/settings/production.py b/config/settings/production.py index e8d8d20..5ab3a21 100644 --- a/config/settings/production.py +++ b/config/settings/production.py @@ -56,6 +56,9 @@ X_FRAME_OPTIONS = 'DENY' # Hosts/domain names that are valid for this site # See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['maidstone-hackspace.org.uk']) +ALLOWED_HOSTS.append('172.*') +ALLOWED_HOSTS.append('172.18.0.5') + # END SITE CONFIGURATION INSTALLED_APPS += ('gunicorn', ) diff --git a/docker-compose.yml b/docker-compose.yml index 3e77fa4..99d65fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,20 @@ version: '2' volumes: - gunicorn_socket: {} - postgres_data: {} - postgres_backup: {} + gunicorn_socket: + driver: local + postgres_data: + driver: local + postgres_backup: + driver: local + + +# volumes: +# sockets: +# driver: local +# data: +# driver: local + services: postgres: @@ -25,10 +36,11 @@ services: env_file: .env volumes: - .:/app - - gunicorn_socket:/data/sockets/ + - gunicorn_socket:/data/sockets nginx: build: ./compose/nginx + env_file: .env depends_on: - django # - certbot @@ -37,6 +49,9 @@ services: - MY_DOMAIN_NAME=maidstone-hackspace.org.uk ports: - "0.0.0.0:80:80" + volumes: + - .:/app + - gunicorn_socket:/data/sockets # - "0.0.0.0:443:443" # volumes: # - /etc/letsencrypt:/etc/letsencrypt diff --git a/live.yml b/live.yml new file mode 100644 index 0000000..09566d7 --- /dev/null +++ b/live.yml @@ -0,0 +1,55 @@ +version: '2' + +volumes: + gunicorn_socket: {} + postgres_data_dev: {} + postgres_backup_dev: {} + +services: + postgres: + build: ./compose/postgres + volumes: + - postgres_data_dev:/var/lib/postgresql/data + - postgres_backup_dev:/backups + # environment: + # - POSTGRES_USER=${POSTGRES_USER} + env_file: .env + + django: + build: + context: . + dockerfile: ./compose/django/Dockerfile + command: /start-dev.sh + depends_on: + - postgres + environment: + - POSTGRES_USER=${POSTGRES_USER} + - USE_DOCKER=yes + volumes: + - .:/app + - gunicorn_socket:/var/run/gunicorn/ + ports: + - "8180:8000" + links: + - postgres + - mailhog + + nginx: + build: ./compose/nginx + depends_on: + - django + environment: + - MY_DOMAIN_NAME=maidstone-hackspace.org.uk + ports: + - "0.0.0.0:80:80" + # - "0.0.0.0:443:443" + volumes: + - gunicorn_socket:/var/run/gunicorn/ + + mailhog: + image: mailhog/mailhog + ports: + - "8125:8025" + + redis: + image: redis:latest diff --git a/mhackspace/subscriptions/payments.py b/mhackspace/subscriptions/payments.py index 26ff92e..a92bc78 100644 --- a/mhackspace/subscriptions/payments.py +++ b/mhackspace/subscriptions/payments.py @@ -369,9 +369,7 @@ class payment: confirm_details['successfull'] = False print('---------------------') print(args) - - from pprint import pprint if self.provider == 'paypal': print(args.get('paymentId')) diff --git a/mhackspace/templates/base.html b/mhackspace/templates/base.html index 2751ea0..1aa9239 100644 --- a/mhackspace/templates/base.html +++ b/mhackspace/templates/base.html @@ -91,8 +91,21 @@
+
- {% if messages %} {% for message in messages %}
{{ message }}
diff --git a/requirements/base.txt b/requirements/base.txt index 25779a5..078f3aa 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -42,10 +42,9 @@ django-redis==4.7.0 redis>=2.10.5 - - -rcssmin==1.0.6 +rcssmin==1.0.6 django-compressor==2.1 +django-sass-processor lxml==3.7.2 mock diff --git a/staticfiles/staticfiles b/staticfiles/staticfiles new file mode 100644 index 0000000..e69de29 From 911e55021cd79fd3b039f079b30bd3f1a3dbb6f3 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 2 Feb 2017 14:05:42 +0000 Subject: [PATCH 16/19] Pin django-sass-processor to latest version 0.5.3 --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 078f3aa..f9a72cc 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -44,7 +44,7 @@ redis>=2.10.5 rcssmin==1.0.6 django-compressor==2.1 -django-sass-processor +django-sass-processor==0.5.3 lxml==3.7.2 mock From 9829e87ca9476840306cabfd3278503a920b2e41 Mon Sep 17 00:00:00 2001 From: Oly Date: Thu, 2 Feb 2017 17:05:38 +0000 Subject: [PATCH 17/19] add auto fixtures --- requirements/base.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 078f3aa..b9b3e8d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -47,10 +47,13 @@ django-compressor==2.1 django-sass-processor lxml==3.7.2 + +# Your custom requirements go here mock gocardless braintree -# Your custom requirements go here +django-autofixture + git+https://github.com/olymk2/scaffold.git From 9ab45cf07819f52b4558efe1b389a11ec4829e3a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 2 Feb 2017 17:06:00 +0000 Subject: [PATCH 18/19] Pin django-autofixture to latest version 0.12.1 --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index b9b3e8d..aef3872 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -54,6 +54,6 @@ mock gocardless braintree -django-autofixture +django-autofixture==0.12.1 git+https://github.com/olymk2/scaffold.git From ad301febf65999ef4823b9f1b30051807256f529 Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Thu, 2 Feb 2017 18:51:54 +0000 Subject: [PATCH 19/19] Demo autofixture integration --- config/settings/common.py | 1 + .../management/commands/generate_test_data.py | 19 +++++++++++++++++++ mhackspace/templates/base.html | 14 +++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 mhackspace/base/management/commands/generate_test_data.py diff --git a/config/settings/common.py b/config/settings/common.py index d60d0f3..fc4941c 100644 --- a/config/settings/common.py +++ b/config/settings/common.py @@ -48,6 +48,7 @@ LOCAL_APPS = ( # custom users app # Your stuff: custom apps go here 'mhackspace.users.apps.UsersConfig', + 'mhackspace.base', 'mhackspace.subscriptions', 'mhackspace.feeds', 'mhackspace.contact', diff --git a/mhackspace/base/management/commands/generate_test_data.py b/mhackspace/base/management/commands/generate_test_data.py new file mode 100644 index 0000000..9bb4471 --- /dev/null +++ b/mhackspace/base/management/commands/generate_test_data.py @@ -0,0 +1,19 @@ +from autofixture import AutoFixture +from django.core.management.base import BaseCommand +from mhackspace.feeds.models import Article +from mhackspace.users.models import User + + +class Command(BaseCommand): + help = 'Imports the RSS feeds from active blogs' + + def handle(self, *args, **options): + users = AutoFixture(User) + users.create(10) + + feeds = AutoFixture(User) + feeds.create(10) + + self.stdout.write( + self.style.SUCCESS( + 'Finished creating test data')) diff --git a/mhackspace/templates/base.html b/mhackspace/templates/base.html index 1aa9239..aa5764b 100644 --- a/mhackspace/templates/base.html +++ b/mhackspace/templates/base.html @@ -91,18 +91,22 @@
-