Compare commits
43 Commits
django2
...
heroku-upg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
458059fd06 | ||
|
|
1a49bb50e5 | ||
|
|
86b349f60e | ||
|
|
35997aa882 | ||
|
|
faa4573f6d | ||
|
|
7babaee44c | ||
|
|
c0fe176495 | ||
|
|
b269069b6a | ||
|
|
7e06b5a162 | ||
|
|
a18bb07d78 | ||
|
|
bd28d2054e | ||
|
|
14836f135c | ||
|
|
5f8a77586a | ||
|
|
e5b7fdbae1 | ||
|
|
f1c8dca8c4 | ||
|
|
843b76d8ea | ||
|
|
e81af9e479 | ||
|
|
efab8c8cef | ||
|
|
3f7531e157 | ||
|
|
988f3dced4 | ||
|
|
bd3240c2bc | ||
|
|
7fbbe2871f | ||
|
|
109ece508b | ||
|
|
971144c2e6 | ||
|
|
a3c6edda0b | ||
|
|
71bb4696b8 | ||
|
|
2a3ed0b763 | ||
|
|
632fa56353 | ||
|
|
f3020fc783 | ||
|
|
9fdf5e674e | ||
|
|
cfe03a8628 | ||
|
|
eccf224b63 | ||
|
|
0b2c86ebb5 | ||
|
|
f616857131 | ||
|
|
60fb90a50c | ||
|
|
66f024e961 | ||
|
|
06daacf611 | ||
|
|
c74bc945b6 | ||
|
|
3c605d2976 | ||
|
|
9720066fd7 | ||
|
|
b157e3b187 | ||
|
|
9c2603557c | ||
|
|
7dff951f28 |
12
Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM python:3.6
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ADD . /app
|
||||||
|
|
||||||
|
RUN pip install -r requirements.txt && \
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
|
||||||
@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
|
|||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
import os
|
import os
|
||||||
import raven
|
import raven
|
||||||
|
import secrets
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ if STAGING:
|
|||||||
if DEBUG:
|
if DEBUG:
|
||||||
ALLOWED_HOSTS.append('localhost')
|
ALLOWED_HOSTS.append('localhost')
|
||||||
ALLOWED_HOSTS.append('example.com')
|
ALLOWED_HOSTS.append('example.com')
|
||||||
|
ALLOWED_HOSTS.append('127.0.0.1')
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
if not DEBUG:
|
if not DEBUG:
|
||||||
@@ -232,3 +234,7 @@ USE_GRAVATAR = True
|
|||||||
|
|
||||||
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
||||||
|
RISK_ASSESSMENT_URL = os.environ.get('RISK_ASSESSMENT_URL') if os.environ.get(
|
||||||
|
'RISK_ASSESSMENT_URL') else "http://example.com"
|
||||||
|
RISK_ASSESSMENT_SECRET = os.environ.get('RISK_ASSESSMENT_SECRET') if os.environ.get(
|
||||||
|
'RISK_ASSESSMENT_SECRET') else secrets.token_hex(15)
|
||||||
|
|||||||
@@ -77,6 +77,13 @@ python manage.py runserver
|
|||||||
```
|
```
|
||||||
Please refer to Django documentation for a full list of options available here.
|
Please refer to Django documentation for a full list of options available here.
|
||||||
|
|
||||||
|
### Development using docker
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build . -t pyrigs
|
||||||
|
docker run -it --rm -p=8000:8000 -v $(pwd):/app pyrigs
|
||||||
|
```
|
||||||
|
|
||||||
### Sample Data ###
|
### Sample Data ###
|
||||||
Sample data is available to aid local development and user acceptance testing. To load this data into your local database, first ensure the database is empty:
|
Sample data is available to aid local development and user acceptance testing. To load this data into your local database, first ensure the database is empty:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ class ProfileRegistrationFormUniqueEmail(RegistrationFormUniqueEmail):
|
|||||||
return self.cleaned_data['initials']
|
return self.cleaned_data['initials']
|
||||||
|
|
||||||
|
|
||||||
# Login form
|
# Embedded Login form - remove the autofocus
|
||||||
|
class EmbeddedAuthenticationForm(AuthenticationForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['username'].widget.attrs.pop('autofocus', None)
|
||||||
|
|
||||||
class PasswordReset(PasswordResetForm):
|
class PasswordReset(PasswordResetForm):
|
||||||
captcha = ReCaptchaField(label='Captcha')
|
captcha = ReCaptchaField(label='Captcha')
|
||||||
|
|
||||||
|
|||||||
18
RIGS/migrations/0034_event_risk_assessment_edit_url.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.0.5 on 2019-07-28 21:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0033_auto_20180325_0016'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='event',
|
||||||
|
name='risk_assessment_edit_url',
|
||||||
|
field=models.CharField(blank=True, max_length=255, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -338,6 +338,9 @@ class Event(models.Model, RevisionMixin):
|
|||||||
auth_request_at = models.DateTimeField(null=True, blank=True)
|
auth_request_at = models.DateTimeField(null=True, blank=True)
|
||||||
auth_request_to = models.EmailField(null=True, blank=True)
|
auth_request_to = models.EmailField(null=True, blank=True)
|
||||||
|
|
||||||
|
# Risk assessment info
|
||||||
|
risk_assessment_edit_url = models.CharField(verbose_name="risk assessment", max_length=255, blank=True, null=True)
|
||||||
|
|
||||||
# Calculated values
|
# Calculated values
|
||||||
"""
|
"""
|
||||||
EX Vat
|
EX Vat
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from django.core.exceptions import SuspiciousOperation
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from z3c.rml import rml2pdf
|
from z3c.rml import rml2pdf
|
||||||
from PyPDF2 import PdfFileMerger, PdfFileReader
|
from PyPDF2 import PdfFileMerger, PdfFileReader
|
||||||
import simplejson
|
import simplejson
|
||||||
@@ -80,6 +81,24 @@ class EventEmbed(EventDetail):
|
|||||||
template_name = 'RIGS/event_embed.html'
|
template_name = 'RIGS/event_embed.html'
|
||||||
|
|
||||||
|
|
||||||
|
class EventRA(generic.base.RedirectView):
|
||||||
|
permanent = False
|
||||||
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
|
event = get_object_or_404(models.Event, pk=kwargs['pk'])
|
||||||
|
|
||||||
|
if event.risk_assessment_edit_url:
|
||||||
|
return event.risk_assessment_edit_url
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'entry.708610078': f'N{event.pk:05}',
|
||||||
|
'entry.905899507': event.name,
|
||||||
|
'entry.139491562': event.venue.name if event.venue else '',
|
||||||
|
'entry.1689826056': event.start_date.strftime('%Y-%m-%d') + ((' - ' + event.end_date.strftime('%Y-%m-%d')) if event.end_date else ''),
|
||||||
|
'entry.902421165': event.mic.name if event.mic else ''
|
||||||
|
}
|
||||||
|
return settings.RISK_ASSESSMENT_URL + "?" + urllib.parse.urlencode(params)
|
||||||
|
|
||||||
|
|
||||||
class EventCreate(generic.CreateView):
|
class EventCreate(generic.CreateView):
|
||||||
model = models.Event
|
model = models.Event
|
||||||
form_class = forms.EventForm
|
form_class = forms.EventForm
|
||||||
@@ -138,7 +157,11 @@ class EventDuplicate(EventUpdate):
|
|||||||
old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
|
old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
|
||||||
new = copy.copy(old) # Make a copy of the object in memory
|
new = copy.copy(old) # Make a copy of the object in memory
|
||||||
new.based_on = old # Make the new event based on the old event
|
new.based_on = old # Make the new event based on the old event
|
||||||
new.purchase_order = None
|
new.purchase_order = None # Remove old PO
|
||||||
|
|
||||||
|
# Clear checked in by if it's a dry hire
|
||||||
|
if new.dry_hire is True:
|
||||||
|
new.checked_in_by = None
|
||||||
|
|
||||||
# Remove all the authorisation information from the new event
|
# Remove all the authorisation information from the new event
|
||||||
new.auth_request_to = None
|
new.auth_request_to = None
|
||||||
@@ -340,8 +363,10 @@ class EventAuthorisationRequest(generic.FormView, generic.detail.SingleObjectMix
|
|||||||
'sent_by': self.request.user.pk,
|
'sent_by': self.request.user.pk,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
if email == event.person.email:
|
if event.person is not None and email == event.person.email:
|
||||||
context['to_name'] = event.person.name
|
context['to_name'] = event.person.name
|
||||||
|
elif event.organisation is not None and email == event.organisation.email:
|
||||||
|
context['to_name'] = event.organisation.name
|
||||||
|
|
||||||
msg = EmailMultiAlternatives(
|
msg = EmailMultiAlternatives(
|
||||||
"N%05d | %s - Event Authorisation Request" % (self.object.pk, self.object.name),
|
"N%05d | %s - Event Authorisation Request" % (self.object.pk, self.object.name),
|
||||||
@@ -380,3 +405,26 @@ class EventAuthoriseRequestEmailPreview(generic.DetailView):
|
|||||||
})
|
})
|
||||||
context['to_name'] = self.request.GET.get('to_name', None)
|
context['to_name'] = self.request.GET.get('to_name', None)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@method_decorator(csrf_exempt, name='dispatch')
|
||||||
|
class LogRiskAssessment(generic.View):
|
||||||
|
http_method_names = ["post"]
|
||||||
|
|
||||||
|
def post(self, request, **kwargs):
|
||||||
|
data = request.POST
|
||||||
|
shared_secret = data.get("secret")
|
||||||
|
edit_url = data.get("editUrl")
|
||||||
|
rig_number = data.get("rigNum")
|
||||||
|
if shared_secret is None or edit_url is None or rig_number is None:
|
||||||
|
return HttpResponse(status=422)
|
||||||
|
|
||||||
|
if shared_secret != settings.RISK_ASSESSMENT_SECRET:
|
||||||
|
return HttpResponse(status=403)
|
||||||
|
|
||||||
|
rig_number = int(re.sub("[^0-9]", "", rig_number))
|
||||||
|
|
||||||
|
event = get_object_or_404(models.Event, pk=rig_number)
|
||||||
|
event.risk_assessment_edit_url = edit_url
|
||||||
|
event.save()
|
||||||
|
|
||||||
|
return HttpResponse(status=200)
|
||||||
|
|||||||
@@ -50,8 +50,10 @@ def send_eventauthorisation_success_email(instance):
|
|||||||
'object': instance,
|
'object': instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
if instance.email == instance.event.person.email:
|
if instance.event.person is not None and instance.email == instance.event.person.email:
|
||||||
context['to_name'] = instance.event.person.name
|
context['to_name'] = instance.event.person.name
|
||||||
|
elif instance.event.organisation is not None and instance.email == instance.event.organisation.email:
|
||||||
|
context['to_name'] = instance.event.organisation.name
|
||||||
|
|
||||||
subject = "N%05d | %s - Event Authorised" % (instance.event.pk, instance.event.name)
|
subject = "N%05d | %s - Event Authorised" % (instance.event.pk, instance.event.name)
|
||||||
|
|
||||||
@@ -89,6 +91,10 @@ def send_eventauthorisation_success_email(instance):
|
|||||||
client_email.send(fail_silently=True)
|
client_email.send(fail_silently=True)
|
||||||
mic_email.send(fail_silently=True)
|
mic_email.send(fail_silently=True)
|
||||||
|
|
||||||
|
# Set event to booked now that it's authorised
|
||||||
|
instance.event.status = models.Event.BOOKED
|
||||||
|
instance.event.save()
|
||||||
|
|
||||||
|
|
||||||
def on_revision_commit(sender, instance, created, **kwargs):
|
def on_revision_commit(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 2.2 KiB |
@@ -149,16 +149,19 @@ ins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html.embedded{
|
html.embedded{
|
||||||
min-height:100%;
|
display: flex;
|
||||||
display: table;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
body{
|
body{
|
||||||
padding:0;
|
padding:0;
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
width:100%;
|
width:100%;
|
||||||
background:none;
|
background:none;
|
||||||
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.embed_container{
|
.embed_container{
|
||||||
|
|||||||
@@ -3,6 +3,17 @@
|
|||||||
class="glyphicon glyphicon-edit"></span> <span
|
class="glyphicon glyphicon-edit"></span> <span
|
||||||
class="hidden-xs">Edit</span></a>
|
class="hidden-xs">Edit</span></a>
|
||||||
{% if event.is_rig %}
|
{% if event.is_rig %}
|
||||||
|
{% if not event.dry_hire %}
|
||||||
|
<a href="{% url 'event_ra' event.pk %}" class="btn btn-default
|
||||||
|
{% if event.risk_assessment_edit_url %}
|
||||||
|
btn-success
|
||||||
|
{% else %}
|
||||||
|
btn-warning
|
||||||
|
{% endif %}
|
||||||
|
"><span
|
||||||
|
class="glyphicon glyphicon-paperclip"></span> <span
|
||||||
|
class="hidden-xs">RA</span></a>
|
||||||
|
{% endif %}
|
||||||
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
<a href="{% url 'event_print' event.pk %}" target="_blank" class="btn btn-default"><span
|
||||||
class="glyphicon glyphicon-print"></span> <span
|
class="glyphicon glyphicon-print"></span> <span
|
||||||
class="hidden-xs">Print</span></a>
|
class="hidden-xs">Print</span></a>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<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>
|
||||||
<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://form.jotformeu.com/62203600438344" 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>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ urlpatterns = [
|
|||||||
url(r'^event/(?P<pk>\d+)/print/$',
|
url(r'^event/(?P<pk>\d+)/print/$',
|
||||||
permission_required_with_403('RIGS.view_event')(rigboard.EventPrint.as_view()),
|
permission_required_with_403('RIGS.view_event')(rigboard.EventPrint.as_view()),
|
||||||
name='event_print'),
|
name='event_print'),
|
||||||
|
url(r'^event/(?P<pk>\d+)/ra/$',
|
||||||
|
permission_required_with_403('RIGS.change_event')(rigboard.EventRA.as_view()),
|
||||||
|
name='event_ra'),
|
||||||
url(r'^event/create/$',
|
url(r'^event/create/$',
|
||||||
permission_required_with_403('RIGS.add_event')(rigboard.EventCreate.as_view()),
|
permission_required_with_403('RIGS.add_event')(rigboard.EventCreate.as_view()),
|
||||||
name='event_create'),
|
name='event_create'),
|
||||||
@@ -185,6 +188,9 @@ urlpatterns = [
|
|||||||
url(r'^api/(?P<model>\w+)/(?P<pk>\d+)/$', login_required(views.SecureAPIRequest.as_view()),
|
url(r'^api/(?P<model>\w+)/(?P<pk>\d+)/$', login_required(views.SecureAPIRequest.as_view()),
|
||||||
name="api_secure"),
|
name="api_secure"),
|
||||||
|
|
||||||
|
# Risk assessment API
|
||||||
|
url(r'^log_risk_assessment/$', rigboard.LogRiskAssessment.as_view(), name='log_risk_assessment'),
|
||||||
|
|
||||||
# Legacy URL's
|
# Legacy URL's
|
||||||
url(r'^rig/show/(?P<pk>\d+)/$',
|
url(r'^rig/show/(?P<pk>\d+)/$',
|
||||||
RedirectView.as_view(permanent=True, pattern_name='event_detail')),
|
RedirectView.as_view(permanent=True, pattern_name='event_detail')),
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class FieldComparison(object):
|
|||||||
def display_value(self, value):
|
def display_value(self, value):
|
||||||
if isinstance(self.field, IntegerField) and len(self.field.choices) > 0:
|
if isinstance(self.field, IntegerField) and len(self.field.choices) > 0:
|
||||||
return [x[1] for x in self.field.choices if x[0] == value][0]
|
return [x[1] for x in self.field.choices if x[0] == value][0]
|
||||||
|
if self.field.name == "risk_assessment_edit_url":
|
||||||
|
return "completed" if value else ""
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ def login_embed(request, **kwargs):
|
|||||||
messages.warning(request, 'Cookies do not seem to be enabled. Try logging in using a new tab.')
|
messages.warning(request, 'Cookies do not seem to be enabled. Try logging in using a new tab.')
|
||||||
request.method = 'GET' # Render the page without trying to login
|
request.method = 'GET' # Render the page without trying to login
|
||||||
|
|
||||||
return login(request, template_name="registration/login_embed.html")
|
return login(request, template_name="registration/login_embed.html", authentication_form=forms.EmbeddedAuthenticationForm)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
3
app.json
@@ -49,5 +49,6 @@
|
|||||||
{
|
{
|
||||||
"url": "heroku/python"
|
"url": "heroku/python"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"stack": "heroku-18"
|
||||||
}
|
}
|
||||||
@@ -3,36 +3,36 @@ contextlib2==0.5.5
|
|||||||
diff-match-patch==20121119
|
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==2.0.3
|
Django==2.0.13
|
||||||
django-debug-toolbar==1.9.1
|
django-debug-toolbar==1.9.1
|
||||||
django-ical==1.4
|
django-ical==1.4
|
||||||
django-recaptcha==1.4.0
|
django-recaptcha==1.4.0
|
||||||
django-registration-redux==2.2
|
django-registration-redux==2.4
|
||||||
django-reversion==2.0.13
|
django-reversion==2.0.13
|
||||||
django-toolbelt==0.0.1
|
django-toolbelt==0.0.1
|
||||||
premailer==3.1.1
|
premailer==3.2.0
|
||||||
#django-widget-tweaks==1.4.1
|
#django-widget-tweaks==1.4.1
|
||||||
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==19.7.1
|
gunicorn==19.8.1
|
||||||
icalendar==4.0.1
|
icalendar==4.0.1
|
||||||
lxml==4.2.1
|
lxml==4.2.1
|
||||||
Markdown==2.6.11
|
Markdown==2.6.11
|
||||||
Pillow==5.0.0
|
Pillow==5.1.0
|
||||||
psycopg2==2.7.4
|
psycopg2==2.7.4
|
||||||
Pygments==2.2.0
|
Pygments==2.2.0
|
||||||
PyPDF2==1.26.0
|
PyPDF2==1.26.0
|
||||||
python-dateutil==2.7.1
|
python-dateutil==2.7.3
|
||||||
pytz==2018.3
|
pytz==2018.4
|
||||||
raven==6.6.0
|
raven==6.8.0
|
||||||
reportlab==3.4.0
|
reportlab==3.4.0
|
||||||
selenium==3.11.0
|
selenium==3.12.0
|
||||||
simplejson==3.13.2
|
simplejson==3.15.0
|
||||||
six==1.11.0
|
six==1.11.0
|
||||||
sqlparse==0.2.4
|
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
|
||||||
z3c.rml==3.3.0
|
z3c.rml==3.5.0
|
||||||
zope.event==4.3.0
|
zope.event==4.3.0
|
||||||
zope.interface==4.4.3
|
zope.interface==4.5.0
|
||||||
zope.schema==4.5.0
|
zope.schema==4.5.0
|
||||||