diff --git a/.idea/PyRIGS.iml b/.idea/PyRIGS.iml index 28c5f8b9..eb7f7ac7 100644 --- a/.idea/PyRIGS.iml +++ b/.idea/PyRIGS.iml @@ -11,7 +11,7 @@ - + diff --git a/.idea/dataSources.ids b/.idea/dataSources.ids index b79da580..748b0aa7 100644 --- a/.idea/dataSources.ids +++ b/.idea/dataSources.ids @@ -1,6 +1,836 @@ + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + +
+
+ + + #@ + ` + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + +
+ + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + +
+ + + + + + + +
+ + + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + +
+
+
\ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 5cabf5c9..d0308fd0 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -1,10 +1,32 @@ - + sqlite.xerial org.sqlite.JDBC jdbc:sqlite:$PROJECT_DIR$/db.sqlite3 + .* + + + + mysql + true + com.mysql.jdbc.Driver + jdbc:mysql://alfie.codedinternet.com:3306/tec_rigs + tec_rigs + dfd2dfe7dfe4dfc8df82dfc8df81dfeddfc3dfdfdff7df8c + + + + + + + + mysql + com.mysql.jdbc.Driver + jdbc:mysql://alfie.codedinternet.com/tec_rigs + tec_rigs + dfd2dfe7dfe4dfc8df82dfc8df81dfeddfc3dfdfdff7df8c diff --git a/PyRIGS/settings.py b/PyRIGS/settings.py index 8a47e84a..b3af52ac 100644 --- a/PyRIGS/settings.py +++ b/PyRIGS/settings.py @@ -62,11 +62,22 @@ WSGI_APPLICATION = 'PyRIGS.wsgi.application' # Database # https://docs.djangoproject.com/en/1.7/ref/settings/#databases - +try: + import pymysql + pymysql.install_as_MySQLdb() +except ImportError: + pass DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + }, + 'legacy': { + 'ENGINE': 'django.db.backends.mysql', + 'HOST': 'alfie.codedinternet.com', + 'NAME': 'tec_rigs', + 'USER': 'tec_rigs', + 'PASSWORD': 'xMNb(b+Giu]&', } } @@ -99,6 +110,17 @@ USE_L10N = True USE_TZ = True +TEMPLATE_CONTEXT_PROCESSORS = ( + "django.contrib.auth.context_processors.auth", + "django.core.context_processors.debug", + "django.core.context_processors.i18n", + "django.core.context_processors.media", + "django.core.context_processors.static", + "django.core.context_processors.tz", + "django.core.context_processors.request", + "django.contrib.messages.context_processors.messages", +) + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ diff --git a/RIGS/importer.py b/RIGS/importer.py new file mode 100644 index 00000000..b9ff30ac --- /dev/null +++ b/RIGS/importer.py @@ -0,0 +1,75 @@ +__author__ = 'Ghost' +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "PyRIGS.settings") +import django +django.setup() + +from django.db import connections +from django.core.exceptions import ObjectDoesNotExist +from django.db.utils import ConnectionDoesNotExist +from django.db import transaction +from RIGS import models +import reversion + +def setup_cursor(): + try: + cursor = connections['legacy'].cursor() + return cursor + except ConnectionDoesNotExist: + print("Legacy database is not configured") + print(connections._databases) + return None + +def import_people(): + cursor = setup_cursor() + if cursor is None: + return + sql = """SELECT `id`, `name`, `phone`, `email`, `address`, `status` FROM `people`""" + cursor.execute(sql) + resp = cursor.fetchall() + for row in resp: + email = row[3] + if email is not "" and "@" not in email: + email += "@nottingham.ac.uk" + + notes = "" + if row[5] != "Normal": + notes = row[5] + + person, created = models.Person.objects.get_or_create(pk=row[0], name=row[1], phone=row[2], email=email, address=row[4], notes=notes) + if created: + print("Created: " + person.__unicode__()) + with transaction.atomic(), reversion.create_revision(): + person.save() + else: + print("Found: " + person.__unicode__()) + +def import_organisations(): + cursor = setup_cursor() + if cursor is None: + return + sql = """SELECT `id`, `name`, `phone`, `address`, `union_account`, `status` FROM `organisations`""" + cursor.execute(sql) + for row in cursor.fetchall(): + unionAccount = False + if row[4] == "1": + unionAccount = True + + notes = "" + if row[5] != "Normal": + notes = row[5] + + object, created = models.Organisation.objects.get_or_create(pk=row[0], name=row[1], phone=row[2], address=row[3], unionAccount=unionAccount, notes=notes) + if created: + print("Created: " + object.__unicode__()) + with transaction.atomic(), reversion.create_revision(): + object.save() + else: + print("Found: " + object.__unicode__()) + +def main(): + #import_people() + import_organisations() + +if __name__=="__main__": + main() \ No newline at end of file diff --git a/RIGS/migrations/0004_organisation.py b/RIGS/migrations/0004_organisation.py new file mode 100644 index 00000000..bf1bbbf4 --- /dev/null +++ b/RIGS/migrations/0004_organisation.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import RIGS.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0003_auto_20141031_0219'), + ] + + operations = [ + migrations.CreateModel( + name='Organisation', + fields=[ + ('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=50)), + ('phone', models.CharField(null=True, blank=True, max_length=15)), + ('email', models.EmailField(null=True, blank=True, max_length=75)), + ('address', models.TextField(null=True, blank=True)), + ('notes', models.TextField(null=True, blank=True)), + ('unionAccount', models.BooleanField(default=False)), + ], + options={ + }, + bases=(models.Model, RIGS.models.RevisionMixin), + ), + ] diff --git a/RIGS/migrations/0005_auto_20141104_1619.py b/RIGS/migrations/0005_auto_20141104_1619.py new file mode 100644 index 00000000..0e8b24d2 --- /dev/null +++ b/RIGS/migrations/0005_auto_20141104_1619.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('RIGS', '0004_organisation'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='initials', + field=models.CharField(blank=True, max_length=5, unique=True, null=True), + preserve_default=True, + ), + ] diff --git a/RIGS/models.py b/RIGS/models.py index 3a08fcf1..b41f8a33 100644 --- a/RIGS/models.py +++ b/RIGS/models.py @@ -6,7 +6,7 @@ import reversion # Create your models here. class Profile(AbstractUser): - initials = models.CharField(max_length=5, unique=True) + initials = models.CharField(max_length=5, unique=True, null=True, blank=True) phone = models.CharField(max_length=13, null=True, blank=True) @property @@ -16,8 +16,20 @@ class Profile(AbstractUser): url = "https://www.gravatar.com/avatar/" + hashlib.md5(self.email).hexdigest() + "?d=identicon&s=500" return url +class RevisionMixin(object): + @property + def last_edited_at(self): + version = reversion.get_for_object(self)[0] + return version.revision.date_created + + @property + def last_edited_by(self): + version = reversion.get_for_object(self)[0] + return version.revision.user + + @reversion.register -class Person(models.Model): +class Person(models.Model, RevisionMixin): name = models.CharField(max_length=50) phone = models.CharField(max_length=15, blank=True, null=True) email = models.EmailField(blank=True, null=True) @@ -26,6 +38,23 @@ class Person(models.Model): notes = models.TextField(blank=True, null=True) + def __unicode__(self): + string = self.name + if len(self.notes) > 0: + string += "*" + return string + +@reversion.register +class Organisation(models.Model, RevisionMixin): + name = models.CharField(max_length=50) + phone = models.CharField(max_length=15, blank=True, null=True) + email = models.EmailField(blank=True, null=True) + + address = models.TextField(blank=True, null=True) + + notes = models.TextField(blank=True, null=True) + unionAccount = models.BooleanField(default=False) + def __unicode__(self): string = self.name if len(self.notes) > 0: diff --git a/RIGS/templates/RIGS/person_detail.html b/RIGS/templates/RIGS/person_detail.html index a126e198..0b2007ef 100644 --- a/RIGS/templates/RIGS/person_detail.html +++ b/RIGS/templates/RIGS/person_detail.html @@ -4,15 +4,16 @@ {% block title %}{{ object.name }}{% endblock %} {% block content %} -
-

{{ object.name }}

- -
- Edit -
-
-
+
+ {% if not request.is_ajax %} +

{{ object.name }}

+
+ Edit +
+ {% endif %} +
+
Name
{{ object.name }}
@@ -32,4 +33,20 @@
-{% endblock %} \ No newline at end of file +{% endblock %} + +{% if request.is_ajax %} + {% block footer %} +
+
+ Lasted edited at {{ object.last_edited_at|date:"SHORT_DATE_FORMAT" }} by {{ user }} +
+
+
+ Edit +
+
+
+ {% endblock %} +{% endif %} \ No newline at end of file diff --git a/RIGS/templates/RIGS/person_list.html b/RIGS/templates/RIGS/person_list.html index 46093097..c7da422f 100644 --- a/RIGS/templates/RIGS/person_list.html +++ b/RIGS/templates/RIGS/person_list.html @@ -1,19 +1,35 @@ {% extends request.is_ajax|yesno:"base_ajax.html,base.html" %} {% load widget_tweaks %} +{% load paginator from filters %} +{% load url_replace from filters %} +{% load orderby from filters %} -{% block title %}People list{% endblock %} +{% block title %}People{% endblock %} {% block content %}
-

People

- New -
{% include 'pagination.html' %}
+
+
+

People

+
+
+ New +
+
+
+
+ +
+
+
+
+
{% paginator %}
- + @@ -28,7 +44,12 @@ - + {% empty %} @@ -39,6 +60,6 @@
NameName Email Phone Notes{{ person.email }} {{ person.phone }} {{ person.notes|yesno|capfirst }}Add buttons + + + + +
-
{% include 'pagination.html' %}
+
{% paginator %}
{% endblock %} \ No newline at end of file diff --git a/RIGS/templatetags/filters.py b/RIGS/templatetags/filters.py index d692e41b..a6be41ae 100644 --- a/RIGS/templatetags/filters.py +++ b/RIGS/templatetags/filters.py @@ -2,7 +2,6 @@ from django import template from django import forms from django.forms.forms import NON_FIELD_ERRORS from django.forms.util import ErrorDict -from reversion.revisions import RevisionManager register = template.Library() @@ -22,9 +21,67 @@ def nice_errors(form, non_field_msg='General form errors'): nice_errors[key] = errors return nice_errors -def lastedit(model): - if RevisionManager.is_registered(model): - versions = RevisionManager.get_for_object(model) - return versions[0].createdAt +def paginator(context, adjacent_pages=3): + """ + To be used in conjunction with the object_list generic view. + + Adds pagination context variables for use in displaying first, adjacent and + last page links in addition to those created by the object_list generic + view. + + """ + page = context['page_obj'] + paginator = context['paginator'] + startPage = max(page.number - adjacent_pages, 1) + if startPage <= 3: startPage = 1 + endPage = page.number + adjacent_pages + 1 + if endPage >= paginator.num_pages - 1: endPage = paginator.num_pages + 1 + page_numbers = [n for n in range(startPage, endPage) \ + if n > 0 and n <= paginator.num_pages] + + dict = { + 'request': context['request'], + 'is_paginated': paginator.num_pages > 0, + 'page_obj': page, + 'paginator': paginator, + 'results': paginator.per_page, + 'page_numbers': page_numbers, + 'show_first': 1 not in page_numbers, + 'show_last': paginator.num_pages not in page_numbers, + 'first': 1, + 'last': paginator.num_pages, + 'has_next': page.has_next(), + 'has_previous': page.has_previous(), + } + + if page.has_next(): + dict['next'] = page.next_page_number() + if page.has_previous(): + dict['previous'] = page.previous_page_number() + + return dict +register.inclusion_tag('pagination.html', takes_context=True)(paginator) + +@register.simple_tag +def url_replace(request, field, value): + + dict_ = request.GET.copy() + + dict_[field] = value + + return dict_.urlencode() + +@register.simple_tag +def orderby(request, field, attr): + + dict_ = request.GET.copy() + + if dict_[field] == attr: + if not dict_[field].startswith("-"): + dict_[field] = "-" + attr + else: + dict_[field] = attr else: - return "No version model saved" \ No newline at end of file + dict_[field] = attr + + return dict_.urlencode() \ No newline at end of file diff --git a/RIGS/views.py b/RIGS/views.py index a8a43daa..2cf03ef0 100644 --- a/RIGS/views.py +++ b/RIGS/views.py @@ -1,7 +1,9 @@ from django.http.response import HttpResponseRedirect from django.core.urlresolvers import reverse_lazy from django.views import generic -import models +from django.views.decorators.csrf import csrf_exempt +from django.db.models import Q +from RIGS import models # Create your views here. def login(request, **kwargs): @@ -26,6 +28,18 @@ class CloseModal(generic.TemplateView): class PersonIndex(generic.ListView): model = models.Person + paginate_by = 20 + + def get_queryset(self): + q = self.request.GET.get('q', "") + if len(q) >= 3: + object_list = self.model.objects.filter(Q(name__icontains=q) | Q(email__icontains=q)) + else: + object_list = self.model.objects.all() + orderBy = self.request.GET.get('orderBy', None) + if orderBy is not None: + object_list = object_list.order_by(orderBy) + return object_list class PersonDetail(generic.DetailView): model = models.Person diff --git a/db.sqlite3 b/db.sqlite3 index 803adbdf..50c06965 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..95f5a6b5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +Django==1.7.1 +PyMySQL==0.6.2 +django-debug-toolbar==1.2.2 +django-registration-redux==1.1 +django-reversion==1.8.5 +sqlparse==0.1.13 \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 69688764..c394f59c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -126,7 +126,6 @@ var dd = this.getDate().toString(); return yyyy + '-' + (mm[1]?mm:"0"+mm[0]) + '-' + (dd[1]?dd:"0"+dd[0]); // padding }; - @@ -136,6 +135,16 @@ + {% block js %} {% endblock %} diff --git a/templates/base_ajax.html b/templates/base_ajax.html new file mode 100644 index 00000000..ab7825a5 --- /dev/null +++ b/templates/base_ajax.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/templates/pagination.html b/templates/pagination.html index a8dc4121..ebf0539b 100644 --- a/templates/pagination.html +++ b/templates/pagination.html @@ -1,27 +1,36 @@ -{% if request.is_paginated %} +{% if is_paginated %} + {% load url_replace from filters %}
    - {% if page_obj.has_previous %} -
  • + {% if has_previous %} +
  • {% else %} {% endif %} - {% for page in pages %} - {% if page %} - {% ifequal page page_obj.number %} -
  • {{ page }}
  • - {% else %} -
  • {{ page }}
  • - {% endifequal %} - {% else %} - ... - {% endif %} - {% endfor %} - {% if page_obj.has_next %} -
  • - {% else %} - - {% endif %} -
+ + {% if show_first %} +
  • +
  • + {% endif %} + + {% for page in page_numbers %} + {% ifequal page page_obj.number %} +
  • {{ page }}
  • + {% else %} +
  • {{ page }}
  • + {% endifequal %} + {% endfor %} + + {% if show_last %} +
  • +
  • + {% endif %} + + {% if has_next %} +
  • + {% else %} + + {% endif %} +
    {% endif %} \ No newline at end of file diff --git a/templates/registration/registration_complete.html b/templates/registration/registration_complete.html index 23827032..c7b02238 100644 --- a/templates/registration/registration_complete.html +++ b/templates/registration/registration_complete.html @@ -5,6 +5,6 @@ {% block content %}

    Thanks for registering

    -

    Thanks for registering with RIGS, you application will now be moderated by an administrator and further instructions will be emailed to you

    +

    Thanks for registering with RIGS, further details will be emailed to you.

    {% endblock %} \ No newline at end of file diff --git a/templates/registration/registration_form.html b/templates/registration/registration_form.html index aa6ec221..c8f5bbbf 100644 --- a/templates/registration/registration_form.html +++ b/templates/registration/registration_form.html @@ -19,14 +19,6 @@
    {% endfor %} - {% for field in supplement_form %} -
    - -
    - {% render_field field class+="form-control" placeholder=field.label %} -
    -
    - {% endfor %}

    {% endblock %} \ No newline at end of file