diff --git a/README.md b/README.md index fe7a95670eac3b96b5669c61f19e0ae556ef800c..7cb00bf7f2a18340c0f18b25427f431cc28b19cb 100755 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Prerequisites * Debian 8 * Python 3.4 or 3.5 +* Django 1.11 (included in Python packages below) * Nginx * Additional dependency packages: * `libsasl2-dev` @@ -23,7 +24,10 @@ Prerequisites * `uwsgi-emperor` * `uwsgi-plugin-python3` * Python/Django packages: see `requires/requirements.txt` - * Includes Django 1.11 +* External resources: + * LDAP database + * WooCommerce instance (REST API) + * RabbitMQ server Other versions and alternatives may work but are untested. diff --git a/conf/etc/config.ini b/conf/etc/config.ini index fd5fc4d46088c58f90e0363bf3df005f02b0eba9..4e067ecd30717262fbcffe51fdfa7cf060e50ba5 100755 --- a/conf/etc/config.ini +++ b/conf/etc/config.ini @@ -18,3 +18,6 @@ AUTH_LDAP_BIND_DN=cn=admin,dc=example,dc=com AUTH_LDAP_USER_SEARCH_BASE_DN=ou=people,dc=example,dc=com SQLITE_DB_PATH = /var/opt/purist/account/db.sqlite3 STATICFILES_DIRS = /var/opt/purist/brand +WOO_URL = https://example.com +WOO_WP_API = True +WOO_VERSION = wc/v1 diff --git a/conf/etc/secret.ini b/conf/etc/secret.ini index 090e45131bd91c57b2f2d0274ca23a03c09f6c95..2506b43ecafa59cedaa55162284326d81df4a2ed 100755 --- a/conf/etc/secret.ini +++ b/conf/etc/secret.ini @@ -4,3 +4,5 @@ [settings] DJANGO_SECRET_KEY=random_key AUTH_LDAP_BIND_PASSWORD=ldap_password +WOO_CONSUMER_KEY = woo_key +WOO_CONSUMER_SECRET = woo_secret diff --git a/conf/uwsgi_emperor_vassals/purist_account.ini b/conf/uwsgi_emperor_vassals/purist_account.ini index 8c2d435045c61f10bf35d8fc53f767078e651767..5d9329efc08da9750aee8ea563782b43f24a332f 100755 --- a/conf/uwsgi_emperor_vassals/purist_account.ini +++ b/conf/uwsgi_emperor_vassals/purist_account.ini @@ -15,4 +15,3 @@ threads = 1 plugins = python3,logfile logger = file:/var/log/uwsgi/app/purist_account.log vacuum = true - diff --git a/ldapregister/jinja2/ldapregister/home.html b/ldapregister/jinja2/ldapregister/home.html index 84b14841f69a623c0c54c6150ae3b229a1d5898c..0ca3ed4aa32de2133da0d74cf902f6578e558885 100755 --- a/ldapregister/jinja2/ldapregister/home.html +++ b/ldapregister/jinja2/ldapregister/home.html @@ -5,13 +5,14 @@ {{ site_title }} - {{ site_byline }} +

{% if request.user.is_authenticated %} - {% trans "Your are logged in as" %} {{ username }}
+ {% trans "Logged in as" %} {{ username }}
{% trans "Change password" %} | {% if request.user.is_superuser %} @@ -22,7 +23,7 @@ {% else %} {% trans "You are not logged in." %}
{% trans "Log in" %} {% trans "or" %} - {% trans "register" %} + {% trans "register." %} {% endif %}

diff --git a/ldapregister/templates/base.html b/ldapregister/templates/base.html index b4aea83fd8c32aa493c5ad8b08b641740c712005..3cf64d8a78b275af5527eb34ab71f018377583f3 100755 --- a/ldapregister/templates/base.html +++ b/ldapregister/templates/base.html @@ -20,7 +20,7 @@
- +

{% block header %}Base{% endblock %}

{% block byline %}Byline{% endblock %}

diff --git a/ldapregister/views.py b/ldapregister/views.py index 5f17b3fc2af05bf4327b48a435285747631f246f..5e8306a1d2b9eb7a8bbdfba1d3394cc5cd406f1d 100755 --- a/ldapregister/views.py +++ b/ldapregister/views.py @@ -1,9 +1,8 @@ +from django.conf import settings from django.shortcuts import render -from purist_account import settings - -def home_page(request): +def home(request): render_data = { "username": request.user.get_username(), diff --git a/limitmonitor/__init__.py b/limitmonitor/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/limitmonitor/admin.py b/limitmonitor/admin.py new file mode 100644 index 0000000000000000000000000000000000000000..846f6b4061a68eda58bc9c76c36603d1e7721ee8 --- /dev/null +++ b/limitmonitor/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/limitmonitor/apps.py b/limitmonitor/apps.py new file mode 100644 index 0000000000000000000000000000000000000000..4288e2c822cadd99238fac0f891e6ed21c4a82a6 --- /dev/null +++ b/limitmonitor/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class LimitMonitorConfig(AppConfig): + name = 'limitmonitor' + verbose_name = 'Limit monitor' diff --git a/limitmonitor/jinja2/limitmonitor/userlimit.html b/limitmonitor/jinja2/limitmonitor/userlimit.html new file mode 100644 index 0000000000000000000000000000000000000000..2c20c44158b59c34ba0ab178a64e45eb86c4c550 --- /dev/null +++ b/limitmonitor/jinja2/limitmonitor/userlimit.html @@ -0,0 +1,40 @@ + + + + + User limits + + + + + + + + + + + + + + + + + + + + {% for limit in limits %} + + + + + + + + + {% endfor %} + + +
ServiceActiveExpiresCredit
{{ limit.service }}{{ limit.is_active }}{{ limit.expiry_date }}{{ limit.time_total }}
+ + + diff --git a/limitmonitor/migrations/0001_initial.py b/limitmonitor/migrations/0001_initial.py new file mode 100644 index 0000000000000000000000000000000000000000..31d85c752442c8c0b61230384e3129e11f8f311e --- /dev/null +++ b/limitmonitor/migrations/0001_initial.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2017-07-19 14:16 +from __future__ import unicode_literals + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Credit', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('time_credit', models.DecimalField(decimal_places=2, default=0, max_digits=6)), + ('volume_credit', models.DecimalField(decimal_places=2, default=0, max_digits=6)), + ('old_expiry_date', models.DateTimeField(default=None, null=True)), + ('old_time_total', models.DecimalField(decimal_places=2, default=None, max_digits=6, null=True)), + ('old_volume_total', models.DecimalField(decimal_places=2, default=None, max_digits=6, null=True)), + ('new_expiry_date', models.DateTimeField(default=None, null=True)), + ('new_time_total', models.DecimalField(decimal_places=2, default=None, max_digits=6, null=True)), + ('new_volume_total', models.DecimalField(decimal_places=2, default=None, max_digits=6, null=True)), + ('created_date', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_date', models.DateTimeField(default=django.utils.timezone.now)), + ], + ), + migrations.CreateModel( + name='ExternalBundle', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('parser', models.CharField(choices=[('WOO1', 'WooCommerce v1')], max_length=30)), + ('external_key', models.CharField(max_length=30)), + ('service', + models.CharField(choices=[('TUNNEL', 'Tunnel'), ('COMMUNICATION', 'Communication')], max_length=30)), + ('time_credit', models.DecimalField(decimal_places=2, default=0, max_digits=6)), + ('volume_credit', models.DecimalField(decimal_places=2, default=0, max_digits=6)), + ('created_date', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_date', models.DateTimeField(default=django.utils.timezone.now)), + ], + ), + migrations.CreateModel( + name='ExternalCredit', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('parser', models.CharField(choices=[('WOO1', 'WooCommerce v1')], max_length=30)), + ('external_key', models.CharField(max_length=30)), + ('label', models.CharField(max_length=30)), + ('bundle_key', models.CharField(max_length=30)), + ('bundle_label', models.CharField(max_length=30)), + ('quantity', models.DecimalField(decimal_places=2, default=1, max_digits=6)), + ('account_name', models.CharField(default='', max_length=30)), + ('additional_data', models.TextField(default='')), + ('is_converted', models.BooleanField(default=False)), + ('created_date', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_date', models.DateTimeField(default=django.utils.timezone.now)), + ], + ), + migrations.CreateModel( + name='Limit', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('service', + models.CharField(choices=[('TUNNEL', 'Tunnel'), ('COMMUNICATION', 'Communication')], max_length=30)), + ('expiry_date', models.DateTimeField(blank=True, default=None)), + ('volume_total', models.DecimalField(decimal_places=2, max_digits=6)), + ('time_total', models.DecimalField(decimal_places=2, max_digits=6)), + ('is_active', models.BooleanField()), + ('created_date', models.DateTimeField(default=django.utils.timezone.now)), + ('updated_date', models.DateTimeField(default=django.utils.timezone.now)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddField( + model_name='credit', + name='external', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.CASCADE, + to='limitmonitor.ExternalCredit'), + ), + migrations.AddField( + model_name='credit', + name='limit', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='limitmonitor.Limit'), + ), + ] diff --git a/limitmonitor/migrations/__init__.py b/limitmonitor/migrations/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/limitmonitor/models.py b/limitmonitor/models.py new file mode 100644 index 0000000000000000000000000000000000000000..dfa51cf071c8aabd13aa9417cb644b79636e4da3 --- /dev/null +++ b/limitmonitor/models.py @@ -0,0 +1,73 @@ +import woocommerce +from django.conf import settings +from django.db import models +from django.utils import timezone + +EXTERNAL_PARSER_CHOICES = ( + ("WOO1", "WooCommerce v1"), +) + +SERVICE_CHOICES = ( + ("TUNNEL", "Tunnel"), + ("COMMUNICATION", "Communication"), +) + + +def get_wcapi(): + return woocommerce.API( + url=settings.WOO_URL, + consumer_key=settings.WOO_CONSUMER_KEY, + consumer_secret=settings.WOO_CONSUMER_SECRET, + wp_api=settings.WOO_WP_API, + version=settings.WOO_VERSION + ) + + +class Limit(models.Model): + user = models.ForeignKey(settings.AUTH_USER_MODEL) + service = models.CharField(max_length=30, choices=SERVICE_CHOICES) + expiry_date = models.DateTimeField(default=None, blank=True) + volume_total = models.DecimalField(decimal_places=2, max_digits=6) + time_total = models.DecimalField(decimal_places=2, max_digits=6) + is_active = models.BooleanField() + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) + + +class ExternalBundle(models.Model): + parser = models.CharField(max_length=30, choices=EXTERNAL_PARSER_CHOICES) + external_key = models.CharField(max_length=30) + service = models.CharField(max_length=30, choices=SERVICE_CHOICES) + time_credit = models.DecimalField(default=0, decimal_places=2, max_digits=6) + volume_credit = models.DecimalField(default=0, decimal_places=2, max_digits=6) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) + + +class ExternalCredit(models.Model): + parser = models.CharField(max_length=30, choices=EXTERNAL_PARSER_CHOICES) + external_key = models.CharField(max_length=30) + label = models.CharField(max_length=30) + bundle_key = models.CharField(max_length=30) + bundle_label = models.CharField(max_length=30) + quantity = models.DecimalField(default=1, decimal_places=2, max_digits=6) + account_name = models.CharField(max_length=30, default="") + additional_data = models.TextField(default="") + is_converted = models.BooleanField(default=False) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) + + +class Credit(models.Model): + limit = models.ForeignKey(Limit) + external = models.ForeignKey(ExternalCredit, null=True, default=None) + time_credit = models.DecimalField(default=0, decimal_places=2, max_digits=6) + volume_credit = models.DecimalField(default=0, decimal_places=2, max_digits=6) + old_expiry_date = models.DateTimeField(null=True, default=None) + old_time_total = models.DecimalField(null=True, default=None, decimal_places=2, max_digits=6) + old_volume_total = models.DecimalField(null=True, default=None, decimal_places=2, max_digits=6) + new_expiry_date = models.DateTimeField(null=True, default=None) + new_time_total = models.DecimalField(null=True, default=None, decimal_places=2, max_digits=6) + new_volume_total = models.DecimalField(null=True, default=None, decimal_places=2, max_digits=6) + created_date = models.DateTimeField(default=timezone.now) + updated_date = models.DateTimeField(default=timezone.now) diff --git a/limitmonitor/tests.py b/limitmonitor/tests.py new file mode 100644 index 0000000000000000000000000000000000000000..a39b155ac3ee946fb97efafe6ecbb42f571cd7ad --- /dev/null +++ b/limitmonitor/tests.py @@ -0,0 +1 @@ +# Create your tests here. diff --git a/limitmonitor/views.py b/limitmonitor/views.py new file mode 100644 index 0000000000000000000000000000000000000000..dcbcd3f5ac82ee97dba503ab2ac60f365eb4e228 --- /dev/null +++ b/limitmonitor/views.py @@ -0,0 +1,18 @@ +from django.conf import settings +from django.shortcuts import render + +from .models import Limit + + +def userlimit(request): + username = request.user.get_username() + limits = Limit.objects.filter(user__username=username) + + render_data = { + "username": username, + "site_title": settings.SITE_TITLE, + "site_byline": settings.SITE_BYLINE, + "limits": limits, + } + + return render(request, 'limitmonitor/userlimit.html', render_data) diff --git a/purist_account/settings.py b/purist_account/settings.py index 0b0820f24833e24dd0adc595df98230b9587191f..36895d7d4efd157e032b767938df66ccafaf3485 100755 --- a/purist_account/settings.py +++ b/purist_account/settings.py @@ -33,7 +33,7 @@ ALLOWED_HOSTS = config("ALLOWED_HOSTS", cast=Csv()) # # INSTALLED_APPS = ["registration_defaults", ] + INSTALLED_APPS + ["ldapregister", ] -INSTALLED_APPS += ["crispy_forms", "ldapregister", ] +INSTALLED_APPS += ["crispy_forms", "ldapregister", "limitmonitor", ] REGISTRATION_OPEN = config("REGISTRATION_OPEN", cast=bool) @@ -85,6 +85,10 @@ AUTH_USER_MODEL = 'ldapregister.User' SQLITE_DB_PATH = config("SQLITE_DB_PATH") DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': SQLITE_DB_PATH, + }, 'ldap': { 'ENGINE': 'ldapdb.backends.ldap', 'NAME': AUTH_LDAP_SERVER_URI, @@ -92,10 +96,6 @@ DATABASES = { 'PASSWORD': AUTH_LDAP_BIND_PASSWORD, 'TLS': AUTH_LDAP_START_TLS, }, - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': SQLITE_DB_PATH, - }, } DATABASE_ROUTERS = ['ldapdb.router.Router'] @@ -107,3 +107,14 @@ STATICFILES_DIRS = config("STATICFILES_DIRS", cast=Csv()) SITE_TITLE = config("SITE_TITLE") SITE_BYLINE = config("SITE_BYLINE") + +# +# WOOCOMMERCE +# + +WOO_URL = config("WOO_URL") +WOO_WP_API = config("WOO_WP_API", cast=bool) +WOO_VERSION = config("WOO_VERSION") + +WOO_CONSUMER_KEY = secret_config("WOO_CONSUMER_KEY") +WOO_CONSUMER_SECRET = secret_config("WOO_CONSUMER_SECRET") diff --git a/purist_account/urls.py b/purist_account/urls.py index d2d6bb6f46367bd47acbb7accf315f3d37205520..fb3254e8d5b36c5bfeab5bc4573f37dd2eb50e10 100755 --- a/purist_account/urls.py +++ b/purist_account/urls.py @@ -19,13 +19,14 @@ from django.views.generic import RedirectView from registration.backends.simple.views import RegistrationView import ldapregister.views +import limitmonitor.views from ldapregister.forms import RegistrationForm urlpatterns = [ - url(r'^$', ldapregister.views.home_page, name='home_page'), + url(r'^$', ldapregister.views.home, name='home'), url(r'^admin/', admin.site.urls), url(r'^accounts/$', RedirectView.as_view(url='/')), - url(r'^accounts/profile/$', RedirectView.as_view(url='/')), + url(r'^accounts/profile/$', limitmonitor.views.userlimit, name='limitmonitor_userlimit'), url(r'^accounts/register/$', RegistrationView.as_view(form_class=RegistrationForm), name='registration_register'), url(r'^accounts/', include('registration.backends.simple.urls')), ] diff --git a/requires/requirements.txt b/requires/requirements.txt index c7843a4bfeec451ebe5f83fc617ed80e8577774c..9ff2ac85b530bcbaca37353f583f1dcfb88eeb3e 100755 --- a/requires/requirements.txt +++ b/requires/requirements.txt @@ -1,5 +1,7 @@ Django==1.11.3 Jinja2==2.9.6 +WooCommerce==1.2.1 +celery==4.0.2 dj-database-url==0.4.2 django-auth-ldap==1.2.13 django-crispy-forms==1.6.1