This commit is contained in:
Oliver Marks 2018-09-04 07:33:28 +01:00
parent 2a68819aed
commit 55af847443
14 changed files with 162 additions and 132 deletions

View File

@ -156,8 +156,9 @@ sudo chmod -R a+rX static/
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(setq python-shell-interpreter "/docker:hackdev_django_1:/usr/local/bin/python") (setq python-shell-interpreter "/docker:hackdev_django_1:/usr/local/bin/python")
(setq python-environment-directory "/docker:hackdev_django_1:/")
#+END_SRC #+END_SRC
#+RESULTS: #+RESULTS:
: /docker:hackdev_django_1:/usr/local/bin/python : /docker:hackdev_django_1:/

View File

@ -60,8 +60,8 @@ urlpatterns = [
name='requests_detail'), name='requests_detail'),
url(r'^requests/(?P<pk>\d+)/submit/$', RequestsDetailForm.as_view(template_name='pages/requests-detail.html'), name='requests_detail_form'), url(r'^requests/(?P<pk>\d+)/submit/$', RequestsDetailForm.as_view(template_name='pages/requests-detail.html'), name='requests_detail_form'),
url(r'^discuss/', include('spirit.urls')), url(r'^discuss/', include(('spirit.urls', 'spirit'), namespace='spirit')),
url(r'^api/v1/', include(router.urls, namespace='v1')), url(r'^api/v1/', include((router.urls, 'v1'), namespace='v1')),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^martor/', include('martor.urls')), url(r'^martor/', include('martor.urls')),
url( url(
@ -88,8 +88,9 @@ urlpatterns = [
url(r'^api/docs/', include_docs_urls(title='Hackspace API')), url(r'^api/docs/', include_docs_urls(title='Hackspace API')),
# User management # User management
url(r'^users/', include('mhackspace.users.urls', namespace='users')), url(r'^users/', include(('mhackspace.users.urls', 'users'), namespace='users')),
url(r'^accounts/', include('allauth.urls')), url(r'^accounts/', include('allauth.urls')),
url('^accounts/', include('django.contrib.auth.urls')),
# Your stuff: custom urls includes go here # Your stuff: custom urls includes go here
url(r'^latest/$', LatestEntriesFeed()), url(r'^latest/$', LatestEntriesFeed()),
@ -98,10 +99,10 @@ urlpatterns = [
url(r'membership/cancel/$', subscription.MembershipCancelView.as_view(), name='cancel_membership'), url(r'membership/cancel/$', subscription.MembershipCancelView.as_view(), name='cancel_membership'),
url(r'membership/(?P<provider>[\w\-]+)/success$', subscription.MembershipJoinSuccessView.as_view(), name='join_hackspace_success'), url(r'membership/(?P<provider>[\w\-]+)/success$', subscription.MembershipJoinSuccessView.as_view(), name='join_hackspace_success'),
url(r'membership/(?P<provider>\w{0,50})/failure$', subscription.MembershipJoinFailureView.as_view(), name='join_hackspace_failure'), url(r'membership/(?P<provider>\w{0,50})/failure$', subscription.MembershipJoinFailureView.as_view(), name='join_hackspace_failure'),
url(r'^admin/password_reset/$', auth_views.password_reset, name='admin_password_reset'), url(r'^admin/password_reset/$', auth_views.PasswordResetView.as_view(), name='admin_password_reset'),
url(r'^admin/password_reset/done/$', auth_views.password_reset_done, name='password_reset_done'), url(r'^admin/password_reset/done/$', auth_views.PasswordChangeDoneView.as_view(), name='password_reset_done'),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', auth_views.password_reset_confirm, name='password_reset_confirm'), url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
url(r'^reset/done/$', auth_views.password_reset_complete, name='password_reset_complete'), url(r'^reset/done/$', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
url(r'^register/$', RegisterForm.as_view(), name='register_form'), url(r'^register/$', RegisterForm.as_view(), name='register_form'),
url(r'^register/success$', TemplateView.as_view(template_name='pages/register.html'), name='register_success'), url(r'^register/success$', TemplateView.as_view(template_name='pages/register.html'), name='register_success'),

View File

@ -19,37 +19,26 @@ class Category(models.Model):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
return reverse('blog-category', kwargs={'category': self.slug}) return reverse("blog-category", kwargs={"category": self.slug})
class Post(models.Model): class Post(models.Model):
title = models.CharField(max_length=100, unique=True) title = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True) slug = models.SlugField(max_length=100, unique=True)
categories = models.ManyToManyField(Category) categories = models.ManyToManyField(Category)
author = models.ForeignKey(User) author = models.ForeignKey(User, on_delete=models.CASCADE)
image = StdImageField( image = StdImageField(
upload_to=UploadToAutoSlugClassNameDir(populate_from='title'), upload_to=UploadToAutoSlugClassNameDir(populate_from="title"),
blank=True, blank=True,
null=True, null=True,
variations={ variations={
'home': { "home": {"width": 530, "height": 220, "crop": True},
"width": 530, "mobilethumb": {"width": 580, "height": 150, "crop": True},
"height": 220, "thumbnail": {"width": 250, "height": 150, "crop": True},
"crop": True}, "full": {"width": 825, "height": 450, "crop": True},
'mobilethumb': { },
"width": 580, validators=[MinSizeValidator(730, 410)],
"height": 150, )
"crop": True},
'thumbnail': {
"width": 250,
"height": 150,
"crop": True},
'full': {
"width": 825,
"height": 450,
"crop": True}},
validators=[
MinSizeValidator(730, 410)])
description = MartorField() description = MartorField()
excerpt = models.TextField(blank=True, null=True) excerpt = models.TextField(blank=True, null=True)
@ -62,8 +51,7 @@ class Post(models.Model):
return self.title return self.title
def get_absolute_url(self): def get_absolute_url(self):
return reverse('blog-item', kwargs={'slug': self.slug}) return reverse("blog-item", kwargs={"slug": self.slug})
class Meta: class Meta:
ordering = ('-published_date',) ordering = ("-published_date",)

View File

@ -8,11 +8,7 @@ from stdimage.models import StdImageField
from stdimage.utils import UploadToAutoSlugClassNameDir from stdimage.utils import UploadToAutoSlugClassNameDir
image_variations = { image_variations = {"home": {"width": 530, "height": 220, "crop": True}}
'home': {
"width": 530,
"height": 220,
"crop": True}}
@python_2_unicode_compatible @python_2_unicode_compatible
@ -23,10 +19,11 @@ class Feed(models.Model):
author = models.CharField(max_length=255) author = models.CharField(max_length=255)
tags = models.CharField(max_length=255, blank=True) tags = models.CharField(max_length=255, blank=True)
image = StdImageField( image = StdImageField(
upload_to=UploadToAutoSlugClassNameDir(populate_from='title'), upload_to=UploadToAutoSlugClassNameDir(populate_from="title"),
blank=True, blank=True,
null=True, null=True,
variations=image_variations) variations=image_variations,
)
enabled = models.BooleanField(default=True) enabled = models.BooleanField(default=True)
def __str__(self): def __str__(self):
@ -35,14 +32,15 @@ class Feed(models.Model):
class Article(models.Model): class Article(models.Model):
url = models.URLField() url = models.URLField()
feed = models.ForeignKey(Feed) feed = models.ForeignKey(Feed, on_delete=models.CASCADE)
title = models.CharField(max_length=255) title = models.CharField(max_length=255)
original_image = models.URLField(max_length=255, blank=True, null=True) original_image = models.URLField(max_length=255, blank=True, null=True)
image = StdImageField( image = StdImageField(
upload_to=UploadToAutoSlugClassNameDir(populate_from='title'), upload_to=UploadToAutoSlugClassNameDir(populate_from="title"),
blank=True, blank=True,
null=True, null=True,
variations=image_variations) variations=image_variations,
)
description = models.TextField() description = models.TextField()
displayed = models.BooleanField(default=True) displayed = models.BooleanField(default=True)
@ -52,4 +50,4 @@ class Article(models.Model):
return self.title return self.title
class Meta: class Meta:
ordering = ('pk',) ordering = ("pk",)

View File

@ -5,11 +5,17 @@ from mhackspace.register.managers import RegisteredUserManager
class RegisteredUser(models.Model): class RegisteredUser(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+', null=True, blank=True) user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name="+",
null=True,
blank=True,
on_delete=models.CASCADE,
)
name = models.CharField(max_length=100, null=False, blank=False) name = models.CharField(max_length=100, null=False, blank=False)
created_at = models.DateTimeField(default=timezone.now) created_at = models.DateTimeField(default=timezone.now)
objects = RegisteredUserManager() objects = RegisteredUserManager()
class Meta: class Meta:
ordering = ('-created_at',) ordering = ("-created_at",)

View File

@ -11,53 +11,60 @@ from mhackspace.base.tasks import matrix_message
REQUEST_TYPES = ( REQUEST_TYPES = (
(0, 'Equipment request'), (0, "Equipment request"),
(1, 'Educational request'), (1, "Educational request"),
(2, 'Training request')) (2, "Training request"),
)
class UserRequest(models.Model): class UserRequest(models.Model):
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL, related_name="+", on_delete=models.CASCADE
related_name='+' )
title = models.CharField(
max_length=255, help_text="Whats being requested ?"
) )
title = models.CharField(max_length=255, help_text='Whats being requested ?')
request_type = models.IntegerField(choices=REQUEST_TYPES, null=False) request_type = models.IntegerField(choices=REQUEST_TYPES, null=False)
acquired = models.BooleanField(default=False) acquired = models.BooleanField(default=False)
cost = models.DecimalField( cost = models.DecimalField(
max_digits=6, max_digits=6,
decimal_places=2, decimal_places=2,
help_text='Leave blank, if no associated cost, or add estimated cost if not sure.' help_text="Leave blank, if no associated cost, or add estimated cost if not sure.",
)
description = MartorField(
help_text="detail of what's being requested and where it can be purchased"
) )
description = MartorField(help_text="detail of what's being requested and where it can be purchased")
created_date = models.DateTimeField(default=timezone.now) created_date = models.DateTimeField(default=timezone.now)
def request_type_string(self): def request_type_string(self):
return REQUEST_TYPES[self.request_type][1] return REQUEST_TYPES[self.request_type][1]
def get_absolute_url(self): def get_absolute_url(self):
return reverse( return reverse("requests_detail", kwargs={"pk": self.pk})
'requests_detail',
kwargs={'pk': self.pk})
class Meta: class Meta:
ordering = ('acquired', 'created_date',) ordering = ("acquired", "created_date")
class UserRequestsComment(models.Model): class UserRequestsComment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE
)
request = models.ForeignKey(UserRequest, on_delete=models.CASCADE) request = models.ForeignKey(UserRequest, on_delete=models.CASCADE)
comment = MartorField(help_text='Your comments') comment = MartorField(help_text="Your comments")
created_date = models.DateTimeField(default=timezone.now) created_date = models.DateTimeField(default=timezone.now)
def send_topic_update_email(sender, instance, **kwargs): def send_topic_update_email(sender, instance, **kwargs):
matrix_message.delay( matrix_message.delay(
prefix=' - REQUEST', prefix=" - REQUEST",
message='%s - https://%s%s' % ( message="%s - https://%s%s"
% (
instance.title, instance.title,
Site.objects.get_current().domain, Site.objects.get_current().domain,
instance.get_absolute_url())) instance.get_absolute_url(),
),
)
post_save.connect(send_topic_update_email, sender=UserRequest) post_save.connect(send_topic_update_email, sender=UserRequest)

View File

@ -29,8 +29,10 @@ class Device(models.Model):
class DeviceAuth(models.Model): class DeviceAuth(models.Model):
rfid = models.ForeignKey( rfid = models.ForeignKey(
Rfid, Rfid,
on_delete=models.CASCADE
) )
device = models.ForeignKey( device = models.ForeignKey(
Device, Device,
on_delete=models.CASCADE
) )

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals, absolute_import
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -22,7 +22,8 @@ class Payments(models.Model):
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
null=True, blank=True, null=True, blank=True,
default=None, default=None,
related_name='from_user' related_name='from_user',
on_delete=models.CASCADE
) )
user_reference = models.CharField(max_length=255) user_reference = models.CharField(max_length=255)
user_email = models.CharField(max_length=255) user_email = models.CharField(max_length=255)

View File

@ -2,7 +2,7 @@ from django.contrib.messages.storage.fallback import FallbackStorage
# from django.contrib.auth.models import Group # from django.contrib.auth.models import Group
from django.test import Client from django.test import Client
from django.test import RequestFactory from django.test import RequestFactory
from django.core.urlresolvers import reverse from django.urls import reverse
from test_plus.test import TestCase from test_plus.test import TestCase
from mock import patch, Mock from mock import patch, Mock
from mhackspace.users.models import Membership from mhackspace.users.models import Membership

View File

@ -0,0 +1,18 @@
# Generated by Django 2.1.1 on 2018-09-04 20:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0008_auto_20170917_0948'),
]
operations = [
migrations.AlterField(
model_name='user',
name='last_name',
field=models.CharField(blank=True, max_length=150, verbose_name='last name'),
),
]

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals, absolute_import
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse from django.urls import reverse
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from stdimage.models import StdImageField from stdimage.models import StdImageField
@ -12,19 +12,17 @@ from mhackspace.base.tasks import matrix_message
class User(AbstractUser): class User(AbstractUser):
name = models.CharField(_('Name of User'), blank=True, max_length=255) name = models.CharField(_("Name of User"), blank=True, max_length=255)
public = models.BooleanField( public = models.BooleanField(
default=False, help_text='If the users email is public on post feeds') default=False, help_text="If the users email is public on post feeds"
)
_image = StdImageField( _image = StdImageField(
upload_to='avatars/', upload_to="avatars/",
blank=True, blank=True,
null=True, null=True,
db_column='image', db_column="image",
variations={ variations={"profile": {"width": 256, "height": 256, "crop": True}},
'profile': { )
"width": 256,
"height": 256,
"crop": True}})
# https://github.com/pennersr/django-allauth/issues/520 # https://github.com/pennersr/django-allauth/issues/520
@property @property
@ -39,51 +37,58 @@ class User(AbstractUser):
return self.username return self.username
def get_absolute_url(self): def get_absolute_url(self):
return reverse('users:detail', kwargs={'username': self.username}) return reverse("users:detail", kwargs={"username": self.username})
class Blurb(models.Model): class Blurb(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='+') user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="+"
)
skills = models.CharField(max_length=255) skills = models.CharField(max_length=255)
description = models.TextField() description = models.TextField()
MEMBERSHIP_ACTIVE = 1 MEMBERSHIP_ACTIVE = 1
MEMBERSHIP_CANCELLED = 4 MEMBERSHIP_CANCELLED = 4
MEMBERSHIP_STATUS_CHOICES = ( MEMBERSHIP_STATUS_CHOICES = (
(0, 'Guest user'), (0, "Guest user"),
(MEMBERSHIP_ACTIVE, 'Active membership'), (MEMBERSHIP_ACTIVE, "Active membership"),
(3, 'Membership Expired'), (3, "Membership Expired"),
(MEMBERSHIP_CANCELLED, 'Membership Cancelled') (MEMBERSHIP_CANCELLED, "Membership Cancelled"),
) )
MEMBERSHIP_STRING = { MEMBERSHIP_STRING = {
0: 'Guest user', 0: "Guest user",
MEMBERSHIP_ACTIVE: 'Active membership', MEMBERSHIP_ACTIVE: "Active membership",
3: 'Membership Expired', 3: "Membership Expired",
MEMBERSHIP_CANCELLED: 'Membership Cancelled' MEMBERSHIP_CANCELLED: "Membership Cancelled",
} }
MEMBERSHIP_STATUS = { MEMBERSHIP_STATUS = {
'signup': 0, # This means the user has not completed signup "signup": 0, # This means the user has not completed signup
'active': MEMBERSHIP_ACTIVE, "active": MEMBERSHIP_ACTIVE,
'expired': 3, "expired": 3,
'cancelled': MEMBERSHIP_CANCELLED "cancelled": MEMBERSHIP_CANCELLED,
} }
class Membership(models.Model): class Membership(models.Model):
user = models.OneToOneField( user = models.OneToOneField(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
null=True, blank=True, null=True,
blank=True,
default=None, default=None,
related_name='user', related_name="user",
unique=True unique=True,
on_delete=models.CASCADE,
) )
payment = models.DecimalField(max_digits=6, decimal_places=2, default=0.0) payment = models.DecimalField(max_digits=6, decimal_places=2, default=0.0)
date = models.DateTimeField() date = models.DateTimeField()
reference = models.CharField(max_length=255) reference = models.CharField(max_length=255)
status = models.PositiveSmallIntegerField(default=0, choices=MEMBERSHIP_STATUS_CHOICES) status = models.PositiveSmallIntegerField(
default=0, choices=MEMBERSHIP_STATUS_CHOICES
)
email = models.CharField(max_length=255, unique=True) email = models.CharField(max_length=255, unique=True)
@property @property
@ -107,10 +112,14 @@ class Membership(models.Model):
# users rfid card to user mapping, user can have more than one card # users rfid card to user mapping, user can have more than one card
class Rfid(models.Model): class Rfid(models.Model):
code = models.CharField(max_length=7) code = models.CharField(max_length=7)
description = models.CharField(_('Short rfid description'), blank=True, max_length=255) description = models.CharField(
_("Short rfid description"), blank=True, max_length=255
)
user = models.ForeignKey( user = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
null=True, blank=True, null=True,
blank=True,
on_delete=models.CASCADE
# related_name='rfid_user' # related_name='rfid_user'
) )
@ -130,5 +139,5 @@ def send_subscription_update_message(sender, instance, **kwargs):
instance.user.username)) instance.user.username))
#Needs to be change to seend to admin room, and not triger on scheduled job # Needs to be change to seend to admin room, and not triger on scheduled job
#post_save.connect(send_subscription_update_message, sender=Membership) # post_save.connect(send_subscription_update_message, sender=Membership)

View File

@ -1,4 +1,4 @@
from django.core.urlresolvers import reverse, resolve from django.urls import reverse, resolve
from test_plus.test import TestCase from test_plus.test import TestCase

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.http import Http404 from django.http import Http404
from django.core.urlresolvers import reverse from django.urls import reverse
from django.views.generic import DetailView, ListView, RedirectView, UpdateView from django.views.generic import DetailView, ListView, RedirectView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin

View File

@ -2,66 +2,66 @@
# like Pillow and psycopg2 # like Pillow and psycopg2
# See http://bitly.com/wheel-building-fails-CPython-35 # See http://bitly.com/wheel-building-fails-CPython-35
# Verified bug on Python 3.5.1 # Verified bug on Python 3.5.1
wheel==0.29.0 wheel==0.31.1
# Bleeding edge Django # Bleeding edge Django
django==1.11.4 django==2.1.1
# Configuration # Configuration
django-environ==0.4.3 django-environ==0.4.5
whitenoise==3.2.3 whitenoise==4.0
# Static and Media Storage # Static and Media Storage
# ------------------------------------------------ # ------------------------------------------------
boto3==1.5.21 boto3==1.8.6
django-storages==1.6.5 django-storages==1.7
# django-storages-redux==1.3.2 # django-storages-redux==1.3.2
# Forms # Forms
django-braces==1.11.0 django-braces==1.13.0
django-crispy-forms==1.6.1 django-crispy-forms==1.7.2
django-extensions==1.8.0 django-extensions==2.1.2
Werkzeug==0.12.2 Werkzeug==0.14.1
# Models # Models
django-stdimage==2.4.0 django-stdimage==3.2.0
django-model-utils==3.0.0 django-model-utils==3.1.2
# Images # Images
Pillow==4.2.0 Pillow==5.2.0
# For user registration, either via email or social # For user registration, either via email or social
# Well-built with regular release cycles! # Well-built with regular release cycles!
django-allauth==0.32.0 django-allauth==0.37.1
# Python-PostgreSQL Database Adapter # Python-PostgreSQL Database Adapter
psycopg2==2.7.1 psycopg2==2.7.5
# Unicode slugification # Unicode slugification
awesome-slugify==1.6.5 awesome-slugify==1.6.5
# Time zones support # Time zones support
pytz==2017.2 pytz==2018.5
# Redis support # Redis support
django-redis==4.8.0 django-redis==4.9.0
redis>=2.10.5 redis>=2.10.6
rcssmin==1.0.6 rcssmin==1.0.6
django-compressor==2.1.1 django-compressor==2.2
#fix for use with s3 buckets merged in master, so next release we can remove this #fix for use with s3 buckets merged in master, so next release we can remove this
#django-sass-processor==0.5.7 #django-sass-processor==0.5.7
git+https://github.com/jrief/django-sass-processor.git git+https://github.com/jrief/django-sass-processor.git
libsass==0.13.2 libsass==0.14.5
lxml==3.7.3 lxml==4.2.4
# WSGI Handler # WSGI Handler
# ------------------------------------------------ # ------------------------------------------------
gevent==1.2.2 gevent==1.3.6
gunicorn==19.7.1 gunicorn==19.9.0
#https://github.com/jonashaag/bjoern #https://github.com/jonashaag/bjoern
#bjoern #bjoern
@ -69,7 +69,7 @@ gunicorn==19.7.1
mock==2.0.0 mock==2.0.0
gocardless_pro gocardless_pro
braintree==3.37.2 braintree==3.48.0
django-autofixture==0.12.1 django-autofixture==0.12.1
@ -77,30 +77,29 @@ git+https://github.com/olymk2/scaffold.git
#git+git://github.com/olymk2/django-wiki.git #git+git://github.com/olymk2/django-wiki.git
git+git://github.com/django-wiki/django-wiki.git git+git://github.com/django-wiki/django-wiki.git
djangorestframework==3.6.3 djangorestframework==3.8.2
djangorestframework-jwt djangorestframework-jwt==1.11.0
django-filter==1.0.2 django-filter==2.0
coreapi coreapi
# api libraries end # api libraries end
martor==1.2.5 martor==1.3.2
#git+git://github.com/olymk2/django-markdown-editor.git #git+git://github.com/olymk2/django-markdown-editor.git
# django-spirit django-spirit==0.6.0
django-djconfig django-djconfig
django-haystack django-haystack
git+https://github.com/nitely/Spirit.git
django-xforwardedfor-middleware==2.0 django-xforwardedfor-middleware==2.0
# Application queue celery # Application queue celery
celery==4.1.0 celery==4.2.1
django-celery-results==1.0.1 django-celery-results==1.0.1
django-celery-beat==1.0.1 django-celery-beat==1.1.1
argon2-cffi argon2-cffi
django-cors-headers django-cors-headers
python-magic python-magic
ldap3 ldap3
bcrypt==3.1.4 bcrypt==3.1.4
python-twitter==3.4.1 python-twitter==3.4.2