mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-03-20 19:05:58 +00:00
Compare commits
22 Commits
requires-i
...
assets-tes
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e114484fe | |||
|
ea696deb1e
|
|||
|
b8a4a70133
|
|||
|
3028c053d4
|
|||
|
3e16075b34
|
|||
|
762af5a1eb
|
|||
|
d312634f68
|
|||
|
ca553137b6
|
|||
|
1c577cdbee
|
|||
|
eaeb56f9f9
|
|||
|
b8d9d24e2c
|
|||
|
731f9865c6
|
|||
|
be9d4115d0
|
|||
|
c6c8501640
|
|||
|
2641e80832
|
|||
|
7c30522906
|
|||
|
b93bb29777
|
|||
|
bf6d22bc38
|
|||
|
|
5265ef835e | ||
|
39b22690f1
|
|||
|
2a99e0912b
|
|||
|
|
a25c41150e |
@@ -12,7 +12,6 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
|
|||||||
import os
|
import os
|
||||||
import raven
|
import raven
|
||||||
import secrets
|
import secrets
|
||||||
import datetime
|
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
@@ -45,9 +44,9 @@ if not DEBUG:
|
|||||||
|
|
||||||
INTERNAL_IPS = ['127.0.0.1']
|
INTERNAL_IPS = ['127.0.0.1']
|
||||||
|
|
||||||
ADMINS = [('Tom Price', 'tomtom5152@gmail.com'), ('IT Manager', 'it@nottinghamtec.co.uk'), ('Arona Jones', 'arona.jones@nottinghamtec.co.uk')]
|
ADMINS = (
|
||||||
if DEBUG:
|
('Tom Price', 'tomtom5152@gmail.com')
|
||||||
ADMINS.append(('Testing Superuser', 'superuser@example.com'))
|
)
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
@@ -183,8 +182,6 @@ if not DEBUG or EMAILER_TEST:
|
|||||||
else:
|
else:
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||||
|
|
||||||
EMAIL_COOLDOWN = datetime.timedelta(minutes=15)
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
||||||
|
|
||||||
|
|||||||
@@ -22,22 +22,13 @@ admin.site.register(models.Invoice)
|
|||||||
admin.site.register(models.Payment)
|
admin.site.register(models.Payment)
|
||||||
|
|
||||||
|
|
||||||
def approve_user(modeladmin, request, queryset):
|
|
||||||
queryset.update(is_approved=True)
|
|
||||||
|
|
||||||
|
|
||||||
approve_user.short_description = "Approve selected users"
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(models.Profile)
|
@admin.register(models.Profile)
|
||||||
class ProfileAdmin(UserAdmin):
|
class ProfileAdmin(UserAdmin):
|
||||||
# Don't know how to add 'is_approved' whilst preserving the default list...
|
|
||||||
list_filter = ('is_approved', 'is_active', 'is_staff', 'is_superuser', 'groups')
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('username', 'password')}),
|
(None, {'fields': ('username', 'password')}),
|
||||||
(_('Personal info'), {
|
(_('Personal info'), {
|
||||||
'fields': ('first_name', 'last_name', 'email', 'initials', 'phone')}),
|
'fields': ('first_name', 'last_name', 'email', 'initials', 'phone')}),
|
||||||
(_('Permissions'), {'fields': ('is_approved', 'is_active', 'is_staff', 'is_superuser',
|
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
|
||||||
'groups', 'user_permissions')}),
|
'groups', 'user_permissions')}),
|
||||||
(_('Important dates'), {
|
(_('Important dates'), {
|
||||||
'fields': ('last_login', 'date_joined')}),
|
'fields': ('last_login', 'date_joined')}),
|
||||||
@@ -50,7 +41,6 @@ class ProfileAdmin(UserAdmin):
|
|||||||
)
|
)
|
||||||
form = forms.ProfileChangeForm
|
form = forms.ProfileChangeForm
|
||||||
add_form = forms.ProfileCreationForm
|
add_form = forms.ProfileCreationForm
|
||||||
actions = [approve_user]
|
|
||||||
|
|
||||||
|
|
||||||
class AssociateAdmin(VersionAdmin):
|
class AssociateAdmin(VersionAdmin):
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ from django import forms
|
|||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
|
||||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm, PasswordResetForm
|
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, AuthenticationForm, PasswordResetForm
|
||||||
from registration.forms import RegistrationFormUniqueEmail
|
from registration.forms import RegistrationFormUniqueEmail
|
||||||
from django.contrib.auth.forms import AuthenticationForm
|
|
||||||
from captcha.fields import ReCaptchaField
|
from captcha.fields import ReCaptchaField
|
||||||
import simplejson
|
import simplejson
|
||||||
|
|
||||||
@@ -35,16 +33,8 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
|||||||
return self.cleaned_data['initials']
|
return self.cleaned_data['initials']
|
||||||
|
|
||||||
|
|
||||||
class CheckApprovedForm(AuthenticationForm):
|
|
||||||
def confirm_login_allowed(self, user):
|
|
||||||
if user.is_approved or user.is_superuser:
|
|
||||||
return AuthenticationForm.confirm_login_allowed(self, user)
|
|
||||||
else:
|
|
||||||
raise forms.ValidationError("Your account hasn't been approved by an administrator yet. Please check back in a few minutes!")
|
|
||||||
|
|
||||||
|
|
||||||
# Embedded Login form - remove the autofocus
|
# Embedded Login form - remove the autofocus
|
||||||
class EmbeddedAuthenticationForm(CheckApprovedForm):
|
class EmbeddedAuthenticationForm(AuthenticationForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields['username'].widget.attrs.pop('autofocus', None)
|
self.fields['username'].widget.attrs.pop('autofocus', None)
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 2.0.13 on 2020-01-10 14:52
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0035_auto_20191124_1319'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='profile',
|
|
||||||
name='is_approved',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='profile',
|
|
||||||
name='last_emailed',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 2.0.13 on 2020-01-11 18:29
|
|
||||||
# This migration ensures that legacy Profiles from before approvals were implemented are automatically approved
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
def approve_legacy(apps, schema_editor):
|
|
||||||
Profile = apps.get_model('RIGS', 'Profile')
|
|
||||||
for person in Profile.objects.all():
|
|
||||||
person.is_approved = True
|
|
||||||
person.save()
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('RIGS', '0036_profile_is_approved'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(approve_legacy)
|
|
||||||
]
|
|
||||||
@@ -27,8 +27,6 @@ class Profile(AbstractUser):
|
|||||||
initials = models.CharField(max_length=5, unique=True, null=True, blank=False)
|
initials = models.CharField(max_length=5, unique=True, null=True, blank=False)
|
||||||
phone = models.CharField(max_length=13, null=True, blank=True)
|
phone = models.CharField(max_length=13, null=True, blank=True)
|
||||||
api_key = models.CharField(max_length=40, blank=True, editable=False, null=True)
|
api_key = models.CharField(max_length=40, blank=True, editable=False, null=True)
|
||||||
is_approved = models.BooleanField(default=False)
|
|
||||||
last_emailed = models.DateTimeField(blank=True, null=True) # Currently only populated by the admin approval email. TODO: Populate it each time we send any email, might need that...
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def make_api_key(cls):
|
def make_api_key(cls):
|
||||||
@@ -55,14 +53,6 @@ class Profile(AbstractUser):
|
|||||||
def latest_events(self):
|
def latest_events(self):
|
||||||
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
return self.event_mic.order_by('-start_date').select_related('person', 'organisation', 'venue', 'mic')
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def admins(cls):
|
|
||||||
return Profile.objects.filter(email__in=[y for x in settings.ADMINS for y in x])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def users_awaiting_approval_count(cls):
|
|
||||||
return Profile.objects.filter(models.Q(is_approved=False)).count()
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import datetime
|
|
||||||
import re
|
import re
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
@@ -11,9 +10,6 @@ from django.conf import settings
|
|||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||||
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
from django.core.mail import EmailMessage, EmailMultiAlternatives
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils import timezone
|
|
||||||
from registration.signals import user_activated
|
|
||||||
from premailer import Premailer
|
from premailer import Premailer
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
|
|
||||||
@@ -106,35 +102,3 @@ def on_revision_commit(sender, instance, created, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
post_save.connect(on_revision_commit, sender=models.EventAuthorisation)
|
post_save.connect(on_revision_commit, sender=models.EventAuthorisation)
|
||||||
|
|
||||||
|
|
||||||
def send_admin_awaiting_approval_email(user, request, **kwargs):
|
|
||||||
# Bit more controlled than just emailing all superusers
|
|
||||||
for admin in models.Profile.admins():
|
|
||||||
# Check we've ever emailed them before and if so, if cooldown has passed.
|
|
||||||
if admin.last_emailed is None or admin.last_emailed + settings.EMAIL_COOLDOWN <= timezone.now():
|
|
||||||
context = {
|
|
||||||
'request': request,
|
|
||||||
'link_suffix': reverse("admin:RIGS_profile_changelist") + '?is_approved__exact=0',
|
|
||||||
'number_of_users': models.Profile.users_awaiting_approval_count(),
|
|
||||||
'to_name': admin.first_name
|
|
||||||
}
|
|
||||||
|
|
||||||
email = EmailMultiAlternatives(
|
|
||||||
"%s new users awaiting approval on RIGS" % (context['number_of_users']),
|
|
||||||
get_template("RIGS/admin_awaiting_approval.txt").render(context),
|
|
||||||
to=[admin.email],
|
|
||||||
reply_to=[user.email],
|
|
||||||
)
|
|
||||||
css = staticfiles_storage.path('css/email.css')
|
|
||||||
html = Premailer(get_template("RIGS/admin_awaiting_approval.html").render(context),
|
|
||||||
external_styles=css).transform()
|
|
||||||
email.attach_alternative(html, 'text/html')
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
# Update last sent
|
|
||||||
admin.last_emailed = timezone.now()
|
|
||||||
admin.save()
|
|
||||||
|
|
||||||
|
|
||||||
user_activated.connect(send_admin_awaiting_approval_email)
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{% extends 'base_client_email.html' %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p>Hi {{ to_name|default_if_none:"Administrator" }},</p>
|
|
||||||
|
|
||||||
<p>{{ number_of_users|default_if_none:"Some" }} new users are awaiting administrator approval on RIGS. Click <a href="{{ request.scheme }}://{{ request.get_host }}{{ link_suffix }}">here</a> to approve them.</p>
|
|
||||||
|
|
||||||
<p>TEC PA & Lighting</p>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
Hi {{ to_name|default_if_none:"Administrator" }},
|
|
||||||
|
|
||||||
{{ number_of_users|default_if_none:"Some" }} new users are awaiting administrator approval on RIGS. Use this link to approve them: {{ request.scheme }}://{{ request.get_host }}/{{ link_suffix }}
|
|
||||||
|
|
||||||
TEC PA & Lighting
|
|
||||||
@@ -10,14 +10,12 @@
|
|||||||
| {{ object.name }} {% if event.dry_hire %}<span class="badge">Dry Hire</span>{% endif %}
|
| {{ object.name }} {% if event.dry_hire %}<span class="badge">Dry Hire</span>{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
{% include 'RIGS/event_detail_buttons.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if object.is_rig and perms.RIGS.view_event %}
|
{% if object.is_rig %}
|
||||||
{# only need contact details for a rig #}
|
{# only need contact details for a rig #}
|
||||||
<div class="col-sm-12 col-md-6 col-lg-5">
|
<div class="col-sm-12 col-md-6 col-lg-5">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
@@ -74,7 +72,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="col-sm-12 {% if event.is_rig and perms.RIGS.view_event %}col-md-6 col-lg-7{% endif %}">
|
<div class="col-sm-12 {% if event.is_rig %}col-md-6 col-lg-7{% endif %}">
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
<div class="panel-heading">Event Info</div>
|
<div class="panel-heading">Event Info</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@@ -149,7 +147,7 @@
|
|||||||
<dd>{{ object.collector }}</dd>
|
<dd>{{ object.collector }}</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if event.is_rig and not event.internal and perms.RIGS.view_event %}
|
{% if event.is_rig and not event.internal %}
|
||||||
<dd> </dd>
|
<dd> </dd>
|
||||||
<dt>PO</dt>
|
<dt>PO</dt>
|
||||||
<dd>{{ object.purchase_order }}</dd>
|
<dd>{{ object.purchase_order }}</dd>
|
||||||
@@ -158,7 +156,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if event.is_rig and event.internal and perms.RIGS.view_event %}
|
{% if event.is_rig and event.internal %}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="panel panel-default
|
<div class="panel panel-default
|
||||||
{% if object.authorised %}
|
{% if object.authorised %}
|
||||||
@@ -214,7 +212,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not request.is_ajax and perms.RIGS.view_event %}
|
{% if not request.is_ajax %}
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
{% include 'RIGS/event_detail_buttons.html' %}
|
||||||
</div>
|
</div>
|
||||||
@@ -224,23 +222,21 @@
|
|||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Event Details</div>
|
<div class="panel-heading">Event Details</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<div class="well well-sm">
|
<div class="well well-sm">
|
||||||
<h4>Notes</h4>
|
<h4>Notes</h4>
|
||||||
<div class="dont-break-out">{{ event.notes|linebreaksbr }}</div>
|
<div class="dont-break-out">{{ event.notes|linebreaksbr }}</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% include 'RIGS/item_table.html' %}
|
{% include 'RIGS/item_table.html' %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if not request.is_ajax and perms.RIGS.view_event %}
|
{% if not request.is_ajax %}
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
{% include 'RIGS/event_detail_buttons.html' %}
|
{% include 'RIGS/event_detail_buttons.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not request.is_ajax and perms.RIGS.view_event %}
|
{% if not request.is_ajax %}
|
||||||
<div class="col-sm-12 text-right">
|
<div class="col-sm-12 text-right">
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||||
@@ -255,16 +251,12 @@
|
|||||||
{% if request.is_ajax %}
|
{% if request.is_ajax %}
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<div class="col-sm-10 align-left">
|
<div class="col-sm-10 align-left">
|
||||||
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
<a href="{% url 'event_history' object.pk %}" title="View Revision History">
|
||||||
Last edited at {{ object.last_edited_at|default:'never' }} by {{ object.last_edited_by.name|default:'nobody' }}
|
Last edited at {{ object.last_edited_at|default:'never' }} by {{ object.last_edited_by.name|default:'nobody' }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
{% else %}
|
|
||||||
<div class="col-sm-12">
|
|
||||||
{% endif %}
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a href="{% url 'event_detail' object.pk %}" class="btn btn-primary">Open Event Page <span
|
<a href="{% url 'event_detail' object.pk %}" class="btn btn-primary">Open Event Page <span
|
||||||
class="glyphicon glyphicon-eye"></span></a>
|
class="glyphicon glyphicon-eye"></span></a>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<span class="source"> R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></span>
|
<span class="source"> R<small>ig</small> I<small>nformation</small> G<small>athering</small> S<small>ystem</small></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
<span class="glyphicon glyphicon-exclamation-sign"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h3>
|
<h3>
|
||||||
<a href="{% url 'event_detail' object.pk %}">
|
<a {% if perms.RIGS.view_event %}href="{% url 'event_detail' object.pk %}"{% endif %}>
|
||||||
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
|
{% if object.is_rig %}N{{ object.pk|stringformat:"05d" }}{% else %}{{ object.pk }}{% endif %}
|
||||||
| {{ object.name }} </a>
|
| {{ object.name }} </a>
|
||||||
{% if object.venue %}
|
{% if object.venue %}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-6">
|
<div class="col-xs-6">
|
||||||
|
|
||||||
{% if object.meet_at %}
|
{% if object.meet_at %}
|
||||||
<p>
|
<p>
|
||||||
<strong>Crew meet:</strong>
|
<strong>Crew meet:</strong>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
{{ object.description|linebreaksbr }}
|
{{ object.description|linebreaksbr }}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h4>
|
<h4>
|
||||||
<a href="{% url 'event_detail' event.pk %}">
|
<a {% if perms.RIGS.view_event %}href="{% url 'event_detail' event.pk %}" {% endif %}>
|
||||||
{{ event.name }}
|
{{ event.name }}
|
||||||
</a>
|
</a>
|
||||||
{% if event.venue %}
|
{% if event.venue %}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-{% if perms.RIGS.view_event %}6{% else %}12{% endif %}">
|
<div class="col-sm-{% if perms.RIGS.view_event %}6{% else %}12{% endif %}">
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h4 class="list-group-item-heading">Quick Links</h4>
|
<h4 class="list-group-item-heading">Quick Links</h4>
|
||||||
@@ -26,11 +26,10 @@
|
|||||||
|
|
||||||
<a class="list-group-item" href="https://forum.nottinghamtec.co.uk" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Forum</a>
|
<a class="list-group-item" href="https://forum.nottinghamtec.co.uk" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Forum</a>
|
||||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a>
|
<a class="list-group-item" href="//members.nottinghamtec.co.uk/wiki" target="_blank"><span class="glyphicon glyphicon-link"></span> TEC Wiki</a>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<a class="list-group-item" href="http://members.nottinghamtec.co.uk/wiki/images/2/22/Event_Risk_Assesment.pdf" target="_blank"><span class="glyphicon glyphicon-link"></span> Pre-Event Risk Assessment</a>
|
<a class="list-group-item" href="http://members.nottinghamtec.co.uk/wiki/images/2/22/Event_Risk_Assesment.pdf" target="_blank"><span class="glyphicon glyphicon-link"></span> Pre-Event Risk Assessment</a>
|
||||||
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a>
|
<a class="list-group-item" href="//members.nottinghamtec.co.uk/price" target="_blank"><span class="glyphicon glyphicon-link"></span> Price List</a>
|
||||||
<a class="list-group-item" href="https://goo.gl/forms/jdPWov8PCNPoXtbn2" target="_blank"><span class="glyphicon glyphicon-link"></span> Subhire Insurance Form</a>
|
<a class="list-group-item" href="https://goo.gl/forms/jdPWov8PCNPoXtbn2" target="_blank"><span class="glyphicon glyphicon-link"></span> Subhire Insurance Form</a>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if perms.RIGS.view_event %}
|
{% if perms.RIGS.view_event %}
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
{% include 'RIGS/activity_feed.html' %}
|
{% include 'RIGS/activity_feed.html' %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,21 +6,17 @@
|
|||||||
<em class="description">{{item.description|linebreaksbr}}</em>
|
<em class="description">{{item.description|linebreaksbr}}</em>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<td>£ <span class="cost">{{item.cost|floatformat:2}}</span></td>
|
<td>£ <span class="cost">{{item.cost|floatformat:2}}</span></td>
|
||||||
{% endif %}
|
|
||||||
<td class="quantity">{{item.quantity}}</td>
|
<td class="quantity">{{item.quantity}}</td>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<td>£ <span class="sub-total" data-subtotal="{{item.total_cost}}">{{item.total_cost|floatformat:2}}</span></td>
|
<td>£ <span class="sub-total" data-subtotal="{{item.total_cost}}">{{item.total_cost|floatformat:2}}</span></td>
|
||||||
{% endif %}
|
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="vert-align text-right">
|
<td class="vert-align text-right">
|
||||||
<button type="button" class="item-edit btn btn-xs btn-default"
|
<button type="button" class="item-edit btn btn-xs btn-default"
|
||||||
data-pk="{{item.pk}}"
|
data-pk="{{item.pk}}"
|
||||||
data-toggle="modal" data-target="#itemModal">
|
data-toggle="modal" data-target="#itemModal">
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
<span class="glyphicon glyphicon-edit"></span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="item-delete btn btn-xs btn-danger"
|
<button type="button" class="item-delete btn btn-xs btn-danger"
|
||||||
data-pk="{{item.pk}}">
|
data-pk="{{item.pk}}">
|
||||||
<span class="glyphicon glyphicon-remove"></span>
|
<span class="glyphicon glyphicon-remove"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,13 +3,9 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Item</td>
|
<td>Item</td>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<td>Price</td>
|
<td>Price</td>
|
||||||
{% endif %}
|
|
||||||
<td>Quantity</td>
|
<td>Quantity</td>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<td>Sub-total</td>
|
<td>Sub-total</td>
|
||||||
{% endif %}
|
|
||||||
{% if edit %}
|
{% if edit %}
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button type="button" class="btn btn-default btn-xs item-add"
|
<button type="button" class="btn btn-default btn-xs item-add"
|
||||||
@@ -26,7 +22,6 @@
|
|||||||
{% include 'RIGS/item_row.html' %}
|
{% include 'RIGS/item_row.html' %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
{% if perms.RIGS.view_event %}
|
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="3" colspan="2"></td>
|
<td rowspan="3" colspan="2"></td>
|
||||||
@@ -48,7 +43,6 @@
|
|||||||
<td colspan="2">£ <span id="total">{{object.total|default:0|floatformat:2}}</span></td>
|
<td colspan="2">£ <span id="total">{{object.total|default:0|floatformat:2}}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
{% endif %}
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<table class="hidden invisible">
|
<table class="hidden invisible">
|
||||||
|
|||||||
@@ -141,41 +141,18 @@ class UserRegistrationTest(LiveServerTestCase):
|
|||||||
self.assertEqual(password.get_attribute('placeholder'), 'Password')
|
self.assertEqual(password.get_attribute('placeholder'), 'Password')
|
||||||
self.assertEqual(password.get_attribute('type'), 'password')
|
self.assertEqual(password.get_attribute('type'), 'password')
|
||||||
|
|
||||||
# Expected to fail as not approved
|
|
||||||
username.send_keys('TestUsername')
|
username.send_keys('TestUsername')
|
||||||
password.send_keys('correcthorsebatterystaple')
|
password.send_keys('correcthorsebatterystaple')
|
||||||
self.browser.execute_script(
|
self.browser.execute_script(
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
||||||
password.send_keys(Keys.ENTER)
|
password.send_keys(Keys.ENTER)
|
||||||
|
|
||||||
# Test approval
|
|
||||||
profileObject = models.Profile.objects.all()[0]
|
|
||||||
self.assertFalse(profileObject.is_approved)
|
|
||||||
|
|
||||||
# Read what the error is
|
|
||||||
alert = self.browser.find_element_by_css_selector(
|
|
||||||
'div.alert-danger').text
|
|
||||||
self.assertIn("approved", alert)
|
|
||||||
|
|
||||||
# Approve the user so we can proceed
|
|
||||||
profileObject.is_approved = True
|
|
||||||
profileObject.save()
|
|
||||||
|
|
||||||
# Retry login
|
|
||||||
self.browser.get(self.live_server_url + '/user/login')
|
|
||||||
username = self.browser.find_element_by_id('id_username')
|
|
||||||
username.send_keys('TestUsername')
|
|
||||||
password = self.browser.find_element_by_id('id_password')
|
|
||||||
password.send_keys('correcthorsebatterystaple')
|
|
||||||
self.browser.execute_script(
|
|
||||||
"return function() {jQuery('#g-recaptcha-response').val('PASSED'); return 0}()")
|
|
||||||
password.send_keys(Keys.ENTER)
|
|
||||||
|
|
||||||
# Check we are logged in
|
# Check we are logged in
|
||||||
udd = self.browser.find_element_by_class_name('navbar').text
|
udd = self.browser.find_element_by_class_name('navbar').text
|
||||||
self.assertIn('Hi John', udd)
|
self.assertIn('Hi John', udd)
|
||||||
|
|
||||||
# Check all the data actually got saved
|
# Check all the data actually got saved
|
||||||
|
profileObject = models.Profile.objects.all()[0]
|
||||||
self.assertEqual(profileObject.username, 'TestUsername')
|
self.assertEqual(profileObject.username, 'TestUsername')
|
||||||
self.assertEqual(profileObject.first_name, 'John')
|
self.assertEqual(profileObject.first_name, 'John')
|
||||||
self.assertEqual(profileObject.last_name, 'Smith')
|
self.assertEqual(profileObject.last_name, 'Smith')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from RIGS import models, views, rigboard, finance, ical, versioning, forms
|
|||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||||
|
|
||||||
from PyRIGS.decorators import permission_required_with_403, has_oembed
|
from PyRIGS.decorators import permission_required_with_403
|
||||||
from PyRIGS.decorators import api_key_required
|
from PyRIGS.decorators import api_key_required
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -87,7 +87,8 @@ urlpatterns = [
|
|||||||
permission_required_with_403('RIGS.view_event')(versioning.ActivityFeed.as_view()),
|
permission_required_with_403('RIGS.view_event')(versioning.ActivityFeed.as_view()),
|
||||||
name='activity_feed'),
|
name='activity_feed'),
|
||||||
|
|
||||||
url(r'^event/(?P<pk>\d+)/$', has_oembed(oembed_view="event_oembed")(
|
url(r'^event/(?P<pk>\d+)/$',
|
||||||
|
permission_required_with_403('RIGS.view_event', oembed_view="event_oembed")(
|
||||||
rigboard.EventDetail.as_view()),
|
rigboard.EventDetail.as_view()),
|
||||||
name='event_detail'),
|
name='event_detail'),
|
||||||
url(r'^event/(?P<pk>\d+)/embed/$',
|
url(r'^event/(?P<pk>\d+)/embed/$',
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ def login(request, **kwargs):
|
|||||||
else:
|
else:
|
||||||
from django.contrib.auth.views import login
|
from django.contrib.auth.views import login
|
||||||
|
|
||||||
return login(request, authentication_form=forms.CheckApprovedForm)
|
return login(request)
|
||||||
|
|
||||||
|
|
||||||
# This view should be exempt from requiring CSRF token.
|
# This view should be exempt from requiring CSRF token.
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
beautifulsoup4==4.8.2
|
beautifulsoup4==4.6.0
|
||||||
contextlib2==0.6.0.post1
|
contextlib2==0.5.5
|
||||||
diff-match-patch==20181111
|
diff-match-patch==20121119
|
||||||
dj-database-url==0.5.0
|
dj-database-url==0.5.0
|
||||||
dj-static==0.0.6
|
dj-static==0.0.6
|
||||||
Django==3.0.3
|
Django==2.0.13
|
||||||
django-filter==2.2.0
|
django-filter==2.0.0
|
||||||
django-widget-tweaks==1.4.5
|
django-widget-tweaks==1.4.3
|
||||||
django-debug-toolbar==2.2
|
django-debug-toolbar==1.9.1
|
||||||
django-ical==1.7.0
|
django-ical==1.4
|
||||||
django-recaptcha==2.0.6
|
django-recaptcha==1.4.0
|
||||||
django-registration-redux==2.7
|
django-registration-redux==2.4
|
||||||
django-reversion==3.0.7
|
django-reversion==2.0.13
|
||||||
django-toolbelt==0.0.1
|
django-toolbelt==0.0.1
|
||||||
premailer==3.6.1
|
premailer==3.2.0
|
||||||
git+git://github.com/jazzband/django-widget-tweaks.git@1.4.2
|
git+git://github.com/jazzband/django-widget-tweaks.git@1.4.2
|
||||||
gunicorn==20.0.4
|
gunicorn==19.8.1
|
||||||
icalendar==4.0.4
|
icalendar==4.0.1
|
||||||
lxml==4.5.0
|
lxml==4.2.1
|
||||||
Markdown==3.2.1
|
Markdown==2.6.11
|
||||||
Pillow==7.0.0
|
Pillow==6.2.0
|
||||||
psycopg2==2.8.4
|
psycopg2==2.7.4
|
||||||
Pygments==2.5.2
|
Pygments==2.2.0
|
||||||
PyPDF2==1.26.0
|
PyPDF2==1.26.0
|
||||||
python-dateutil==2.8.1
|
python-dateutil==2.7.3
|
||||||
pytz==2019.3
|
pytz==2018.4
|
||||||
raven==6.10.0
|
raven==6.8.0
|
||||||
reportlab==3.5.34
|
reportlab==3.4.0
|
||||||
selenium==3.141.0
|
selenium==3.12.0
|
||||||
simplejson==3.17.0
|
simplejson==3.15.0
|
||||||
six==1.14.0
|
six==1.11.0
|
||||||
sqlparse==0.3.0
|
sqlparse==0.2.4
|
||||||
static3==0.7.0
|
static3==0.7.0
|
||||||
svg2rlg==0.3
|
svg2rlg==0.3
|
||||||
yolk==0.4.3
|
yolk==0.4.3
|
||||||
whitenoise==5.0.1
|
whitenoise==4.1.2
|
||||||
z3c.rml==3.9.1
|
z3c.rml==3.5.0
|
||||||
zope.event==4.4
|
zope.event==4.3.0
|
||||||
zope.interface==4.7.1
|
zope.interface==4.5.0
|
||||||
zope.schema==4.9.3
|
zope.schema==4.5.0
|
||||||
pypom==2.2.0
|
pypom==2.2.0
|
||||||
@@ -5,6 +5,6 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<h2>Activation Complete</h2>
|
<h2>Activation Complete</h2>
|
||||||
<p>Your user account is now awaiting administrator approval. Won't be long!</p>
|
<p>You user account is now fully registered. Enjoy RIGS</p>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user