Get rid of wrapt hack. Django 2.2 introduced setup() method on views. Yay!

This commit is contained in:
Víðir Valberg Guðmundsson 2019-04-02 12:32:12 +02:00
parent 63890131c8
commit 75c8db4577
4 changed files with 316 additions and 257 deletions

View file

@ -1,208 +1,176 @@
import os
import wrapt
import django.views
from .environment_settings import *
def local_dir(entry):
return os.path.join(
os.path.dirname(os.path.dirname(__file__)),
entry
)
# We do this hacky monkeypatching to enable us to define a setup method
# on class based views for setting up variables without touching the dispatch
# method.
@wrapt.patch_function_wrapper(django.views.View, 'dispatch')
def monkey_patched_dispatch(wrapped, instance, args, kwargs):
if hasattr(instance, 'setup'):
instance.setup(*args, **kwargs)
return wrapped(*args, **kwargs)
return os.path.join(os.path.dirname(os.path.dirname(__file__)), entry)
DJANGO_BASE_PATH = os.path.dirname(os.path.dirname(__file__))
WSGI_APPLICATION = 'bornhack.wsgi.application'
ASGI_APPLICATION = 'bornhack.routing.application'
ROOT_URLCONF = 'bornhack.urls'
WSGI_APPLICATION = "bornhack.wsgi.application"
ASGI_APPLICATION = "bornhack.routing.application"
ROOT_URLCONF = "bornhack.urls"
ACCOUNT_ADAPTER = 'allauth_2fa.adapter.OTPAdapter'
ACCOUNT_ADAPTER = "allauth_2fa.adapter.OTPAdapter"
SITE_ID = 1
ADMINS = (
('bornhack sysadm', 'sysadm@bornhack.org'),
)
ADMINS = (("bornhack sysadm", "sysadm@bornhack.org"),)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'graphene_django',
'channels',
'corsheaders',
'profiles',
'camps',
'shop',
'news',
'utils',
'villages',
'program',
'info',
'sponsors',
'ircbot',
'teams',
'people',
'tickets',
'bar',
'backoffice',
'events',
'rideshare',
'tokens',
'feedback',
'economy',
'allauth',
'allauth.account',
'allauth_2fa',
'django_otp',
'django_otp.plugins.otp_totp',
'django_otp.plugins.otp_static',
'bootstrap3',
'django_extensions',
'reversion',
'betterforms',
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
"graphene_django",
"channels",
"corsheaders",
"profiles",
"camps",
"shop",
"news",
"utils",
"villages",
"program",
"info",
"sponsors",
"ircbot",
"teams",
"people",
"tickets",
"bar",
"backoffice",
"events",
"rideshare",
"tokens",
"feedback",
"economy",
"allauth",
"allauth.account",
"allauth_2fa",
"django_otp",
"django_otp.plugins.otp_totp",
"django_otp.plugins.otp_static",
"bootstrap3",
"django_extensions",
"reversion",
"betterforms",
]
#MEDIA_URL = '/media/'
STATIC_URL = '/static/'
STATIC_ROOT = local_dir('static')
STATICFILES_DIRS = [local_dir('static_src')]
LANGUAGE_CODE = 'en-us'
#USE_I18N = True
#USE_L10N = True
# MEDIA_URL = '/media/'
STATIC_URL = "/static/"
STATIC_ROOT = local_dir("static")
STATICFILES_DIRS = [local_dir("static_src")]
LANGUAGE_CODE = "en-us"
# USE_I18N = True
# USE_L10N = True
USE_TZ = True
SHORT_DATE_FORMAT = 'd/m-Y'
DATE_FORMAT = 'd/m-Y'
DATETIME_FORMAT = 'd/m-Y H:i'
TIME_FORMAT = 'H:i'
SHORT_DATE_FORMAT = "d/m-Y"
DATE_FORMAT = "d/m-Y"
DATETIME_FORMAT = "d/m-Y H:i"
TIME_FORMAT = "H:i"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [local_dir('templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.template.context_processors.media',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'shop.context_processors.current_order',
'camps.context_processors.camp',
],
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [local_dir("templates")],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.template.context_processors.media",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"shop.context_processors.current_order",
"camps.context_processors.camp",
]
},
},
}
]
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # Handles login to admin with username
'allauth.account.auth_backends.AuthenticationBackend', # Handles regular logins
"django.contrib.auth.backends.ModelBackend", # Handles login to admin with username
"allauth.account.auth_backends.AuthenticationBackend", # Handles regular logins
)
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = True
ACCOUNT_EMAIL_SUBJECT_PREFIX = '[bornhack] '
ACCOUNT_EMAIL_SUBJECT_PREFIX = "[bornhack] "
ACCOUNT_USERNAME_REQUIRED = False
LOGIN_REDIRECT_URL='/'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = "/"
LOGIN_URL = "/login/"
ACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "https"
BOOTSTRAP3 = {
'jquery_url': '/static/js/jquery.min.js',
'javascript_url': '/static/js/bootstrap.min.js'
"jquery_url": "/static/js/jquery.min.js",
"javascript_url": "/static/js/bootstrap.min.js",
}
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django_otp.middleware.OTPMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django_otp.middleware.OTPMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_URLS_REGEX = r'^/api/*$'
CORS_URLS_REGEX = r"^/api/*$"
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
INSTALLED_APPS += [
'debug_toolbar',
]
MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware'] + MIDDLEWARE
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
INSTALLED_APPS += ["debug_toolbar"]
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
INTERNAL_IPS = "127.0.0.1"
DEBUG_TOOLBAR_PANELS = [
'debug_toolbar.panels.versions.VersionsPanel',
'debug_toolbar.panels.timer.TimerPanel',
'debug_toolbar.panels.settings.SettingsPanel',
'debug_toolbar.panels.headers.HeadersPanel',
'debug_toolbar.panels.request.RequestPanel',
'debug_toolbar.panels.sql.SQLPanel',
'debug_toolbar.panels.staticfiles.StaticFilesPanel',
'debug_toolbar.panels.templates.TemplatesPanel',
'debug_toolbar.panels.cache.CachePanel',
'debug_toolbar.panels.signals.SignalsPanel',
'debug_toolbar.panels.logging.LoggingPanel',
'debug_toolbar.panels.redirects.RedirectsPanel',
"debug_toolbar.panels.versions.VersionsPanel",
"debug_toolbar.panels.timer.TimerPanel",
"debug_toolbar.panels.settings.SettingsPanel",
"debug_toolbar.panels.headers.HeadersPanel",
"debug_toolbar.panels.request.RequestPanel",
"debug_toolbar.panels.sql.SQLPanel",
"debug_toolbar.panels.staticfiles.StaticFilesPanel",
"debug_toolbar.panels.templates.TemplatesPanel",
"debug_toolbar.panels.cache.CachePanel",
"debug_toolbar.panels.signals.SignalsPanel",
"debug_toolbar.panels.logging.LoggingPanel",
"debug_toolbar.panels.redirects.RedirectsPanel",
]
else:
SESSION_COOKIE_SECURE=True
CSRF_COOKIE_SECURE=True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'syslog': {
'format': '%(levelname)s %(name)s.%(funcName)s(): %(message)s'
},
'console': {
'format': '[%(asctime)s] %(name)s.%(funcName)s() %(levelname)s %(message)s',
'datefmt': '%d/%b/%Y %H:%M:%S'
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"syslog": {"format": "%(levelname)s %(name)s.%(funcName)s(): %(message)s"},
"console": {
"format": "[%(asctime)s] %(name)s.%(funcName)s() %(levelname)s %(message)s",
"datefmt": "%d/%b/%Y %H:%M:%S",
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'console'
},
"handlers": {
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "console",
}
},
'loggers': {
"loggers": {
# send the bornhack logger to console at DEBUG level,
# do not propagate bornhack.* messages up to the root logger
'bornhack': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
},
"bornhack": {"handlers": ["console"], "level": "DEBUG", "propagate": False}
},
}
GRAPHENE = {
'SCHEMA': 'bornhack.schema.schema'
}
GRAPHENE = {"SCHEMA": "bornhack.schema.schema"}

View file

@ -8,25 +8,21 @@ class ChainViewMixin(object):
"""
The ChainViewMixin sets self.chain based on chain_slug from the URL
"""
def setup(self, *args, **kwargs):
if hasattr(super(), 'setup'):
super().setup(*args, **kwargs)
self.chain = get_object_or_404(
Chain,
slug=self.kwargs["chain_slug"],
)
super().setup(*args, **kwargs)
self.chain = get_object_or_404(Chain, slug=self.kwargs["chain_slug"])
class CredebtorViewMixin(object):
"""
The CredebtorViewMixin sets self.credebtor based on credebtor_slug from the URL
"""
def setup(self, *args, **kwargs):
if hasattr(super(), 'setup'):
super().setup(*args, **kwargs)
super().setup(*args, **kwargs)
self.credebtor = get_object_or_404(
Credebtor,
slug=self.kwargs["credebtor_slug"],
Credebtor, slug=self.kwargs["credebtor_slug"]
)
@ -34,9 +30,12 @@ class ExpensePermissionMixin(object):
"""
This mixin checks if request.user submitted the Expense, or if request.user has camps.economyteam_permission
"""
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
if obj.user == self.request.user or self.request.user.has_perm('camps.economyteam_permission'):
if obj.user == self.request.user or self.request.user.has_perm(
"camps.economyteam_permission"
):
return obj
else:
# the current user is different from the user who submitted the expense, and current user is not in the economy team; fuckery is afoot, no thanks
@ -47,9 +46,12 @@ class RevenuePermissionMixin(object):
"""
This mixin checks if request.user submitted the Revenue, or if request.user has camps.economyteam_permission
"""
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
if obj.user == self.request.user or self.request.user.has_perm('camps.economyteam_permission'):
if obj.user == self.request.user or self.request.user.has_perm(
"camps.economyteam_permission"
):
return obj
else:
# the current user is different from the user who submitted the revenue, and current user is not in the economy team; fuckery is afoot, no thanks
@ -60,11 +62,13 @@ class ReimbursementPermissionMixin(object):
"""
This mixin checks if request.user owns the Reimbursement, or if request.user has camps.economyteam_permission
"""
def get_object(self, queryset=None):
obj = super().get_object(queryset=queryset)
if obj.reimbursement_user == self.request.user or self.request.user.has_perm('camps.economyteam_permission'):
if obj.reimbursement_user == self.request.user or self.request.user.has_perm(
"camps.economyteam_permission"
):
return obj
else:
# the current user is different from the user who "owns" the reimbursement, and current user is not in the economy team; fuckery is afoot, no thanks
raise Http404()

View file

@ -6,7 +6,14 @@ from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.urls import reverse
from django.views.generic import CreateView, ListView, DetailView, TemplateView, UpdateView, DeleteView
from django.views.generic import (
CreateView,
ListView,
DetailView,
TemplateView,
UpdateView,
DeleteView,
)
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Sum
@ -20,7 +27,7 @@ from .forms import *
class EconomyDashboardView(LoginRequiredMixin, CampViewMixin, TemplateView):
template_name = 'dashboard.html'
template_name = "dashboard.html"
def get_context_data(self, **kwargs):
"""
@ -29,27 +36,55 @@ class EconomyDashboardView(LoginRequiredMixin, CampViewMixin, TemplateView):
context = super().get_context_data(**kwargs)
# get reimbursement stats
context['reimbursement_count'] = Reimbursement.objects.filter(reimbursement_user=self.request.user, camp=self.camp).count()
context['unpaid_reimbursement_count'] = Reimbursement.objects.filter(reimbursement_user=self.request.user, paid=False, camp=self.camp).count()
context['paid_reimbursement_count'] = Reimbursement.objects.filter(reimbursement_user=self.request.user, paid=True, camp=self.camp).count()
context["reimbursement_count"] = Reimbursement.objects.filter(
reimbursement_user=self.request.user, camp=self.camp
).count()
context["unpaid_reimbursement_count"] = Reimbursement.objects.filter(
reimbursement_user=self.request.user, paid=False, camp=self.camp
).count()
context["paid_reimbursement_count"] = Reimbursement.objects.filter(
reimbursement_user=self.request.user, paid=True, camp=self.camp
).count()
reimbursement_total = 0
for reimbursement in Reimbursement.objects.filter(reimbursement_user=self.request.user, camp=self.camp):
for reimbursement in Reimbursement.objects.filter(
reimbursement_user=self.request.user, camp=self.camp
):
reimbursement_total += reimbursement.amount
context['reimbursement_total'] = reimbursement_total
context["reimbursement_total"] = reimbursement_total
# get expense stats
context['expense_count'] = Expense.objects.filter(user=self.request.user, camp=self.camp).count()
context['unapproved_expense_count'] = Expense.objects.filter(user=self.request.user, approved__isnull=True, camp=self.camp).count()
context['approved_expense_count'] = Expense.objects.filter(user=self.request.user, approved=True, camp=self.camp).count()
context['rejected_expense_count'] = Expense.objects.filter(user=self.request.user, approved=False, camp=self.camp).count()
context['expense_total'] = Expense.objects.filter(user=self.request.user, camp=self.camp).aggregate(Sum('amount'))['amount__sum']
context["expense_count"] = Expense.objects.filter(
user=self.request.user, camp=self.camp
).count()
context["unapproved_expense_count"] = Expense.objects.filter(
user=self.request.user, approved__isnull=True, camp=self.camp
).count()
context["approved_expense_count"] = Expense.objects.filter(
user=self.request.user, approved=True, camp=self.camp
).count()
context["rejected_expense_count"] = Expense.objects.filter(
user=self.request.user, approved=False, camp=self.camp
).count()
context["expense_total"] = Expense.objects.filter(
user=self.request.user, camp=self.camp
).aggregate(Sum("amount"))["amount__sum"]
# get revenue stats
context['revenue_count'] = Revenue.objects.filter(user=self.request.user, camp=self.camp).count()
context['unapproved_revenue_count'] = Revenue.objects.filter(user=self.request.user, approved__isnull=True, camp=self.camp).count()
context['approved_revenue_count'] = Revenue.objects.filter(user=self.request.user, approved=True, camp=self.camp).count()
context['rejected_revenue_count'] = Revenue.objects.filter(user=self.request.user, approved=False, camp=self.camp).count()
context['revenue_total'] = Revenue.objects.filter(user=self.request.user, camp=self.camp).aggregate(Sum('amount'))['amount__sum']
context["revenue_count"] = Revenue.objects.filter(
user=self.request.user, camp=self.camp
).count()
context["unapproved_revenue_count"] = Revenue.objects.filter(
user=self.request.user, approved__isnull=True, camp=self.camp
).count()
context["approved_revenue_count"] = Revenue.objects.filter(
user=self.request.user, approved=True, camp=self.camp
).count()
context["rejected_revenue_count"] = Revenue.objects.filter(
user=self.request.user, approved=False, camp=self.camp
).count()
context["revenue_total"] = Revenue.objects.filter(
user=self.request.user, camp=self.camp
).aggregate(Sum("amount"))["amount__sum"]
return context
@ -59,9 +94,9 @@ class EconomyDashboardView(LoginRequiredMixin, CampViewMixin, TemplateView):
class ChainCreateView(CampViewMixin, RaisePermissionRequiredMixin, CreateView):
model = Chain
template_name = 'chain_create.html'
permission_required = ("camps.expense_create_permission")
fields = ['name', 'notes']
template_name = "chain_create.html"
permission_required = "camps.expense_create_permission"
fields = ["name", "notes"]
def form_valid(self, form):
chain = form.save()
@ -69,33 +104,38 @@ class ChainCreateView(CampViewMixin, RaisePermissionRequiredMixin, CreateView):
# a message for the user
messages.success(
self.request,
"The new Chain %s has been saved. You can now add Creditor(s)/Debtor(s) for it." % chain.name,
"The new Chain %s has been saved. You can now add Creditor(s)/Debtor(s) for it."
% chain.name,
)
return HttpResponseRedirect(reverse('economy:credebtor_create', kwargs={
'camp_slug': self.camp.slug,
'chain_slug': chain.slug,
}))
return HttpResponseRedirect(
reverse(
"economy:credebtor_create",
kwargs={"camp_slug": self.camp.slug, "chain_slug": chain.slug},
)
)
class ChainListView(CampViewMixin, RaisePermissionRequiredMixin, ListView):
model = Chain
template_name = 'chain_list.html'
permission_required = ("camps.expense_create_permission")
template_name = "chain_list.html"
permission_required = "camps.expense_create_permission"
class CredebtorCreateView(CampViewMixin, ChainViewMixin, RaisePermissionRequiredMixin, CreateView):
class CredebtorCreateView(
CampViewMixin, ChainViewMixin, RaisePermissionRequiredMixin, CreateView
):
model = Credebtor
template_name = 'credebtor_create.html'
permission_required = ("camps.expense_create_permission")
fields = ['name', 'address', 'notes']
template_name = "credebtor_create.html"
permission_required = "camps.expense_create_permission"
fields = ["name", "address", "notes"]
def get_context_data(self, **kwargs):
"""
Add chain to context
"""
context = super().get_context_data(**kwargs)
context['chain'] = self.chain
context["chain"] = self.chain
return context
def form_valid(self, form):
@ -106,26 +146,31 @@ class CredebtorCreateView(CampViewMixin, ChainViewMixin, RaisePermissionRequired
# a message for the user
messages.success(
self.request,
"The Creditor/Debtor %s has been saved. You can now add Expenses/Revenues for it." % credebtor.name,
"The Creditor/Debtor %s has been saved. You can now add Expenses/Revenues for it."
% credebtor.name,
)
return HttpResponseRedirect(reverse('economy:credebtor_list', kwargs={
'camp_slug': self.camp.slug,
'chain_slug': self.chain.slug,
}))
return HttpResponseRedirect(
reverse(
"economy:credebtor_list",
kwargs={"camp_slug": self.camp.slug, "chain_slug": self.chain.slug},
)
)
class CredebtorListView(CampViewMixin, ChainViewMixin, RaisePermissionRequiredMixin, ListView):
class CredebtorListView(
CampViewMixin, ChainViewMixin, RaisePermissionRequiredMixin, ListView
):
model = Credebtor
template_name = 'credebtor_list.html'
permission_required = ("camps.expense_create_permission")
template_name = "credebtor_list.html"
permission_required = "camps.expense_create_permission"
def get_context_data(self, **kwargs):
"""
Add chain to context
"""
context = super().get_context_data(**kwargs)
context['chain'] = self.chain
context["chain"] = self.chain
return context
@ -134,7 +179,7 @@ class CredebtorListView(CampViewMixin, ChainViewMixin, RaisePermissionRequiredMi
class ExpenseListView(LoginRequiredMixin, CampViewMixin, ListView):
model = Expense
template_name = 'expense_list.html'
template_name = "expense_list.html"
def get_queryset(self):
# only return Expenses belonging to the current user
@ -143,13 +188,15 @@ class ExpenseListView(LoginRequiredMixin, CampViewMixin, ListView):
class ExpenseDetailView(CampViewMixin, ExpensePermissionMixin, DetailView):
model = Expense
template_name = 'expense_detail.html'
template_name = "expense_detail.html"
class ExpenseCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequiredMixin, CreateView):
class ExpenseCreateView(
CampViewMixin, CredebtorViewMixin, RaisePermissionRequiredMixin, CreateView
):
model = Expense
template_name = 'expense_form.html'
permission_required = ("camps.expense_create_permission")
template_name = "expense_form.html"
permission_required = "camps.expense_create_permission"
form_class = ExpenseCreateForm
def get_context_data(self, **kwargs):
@ -157,8 +204,10 @@ class ExpenseCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequir
Do not show teams that are not part of the current camp in the dropdown
"""
context = super().get_context_data(**kwargs)
context['form'].fields['responsible_team'].queryset = Team.objects.filter(camp=self.camp)
context['creditor'] = self.credebtor
context["form"].fields["responsible_team"].queryset = Team.objects.filter(
camp=self.camp
)
context["creditor"] = self.credebtor
return context
def form_valid(self, form):
@ -178,24 +227,32 @@ class ExpenseCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequir
add_outgoing_email(
"emails/expense_awaiting_approval_email.txt",
formatdict=dict(expense=expense),
subject="New %s expense for %s Team is awaiting approval" % (expense.camp.title, expense.responsible_team.name),
subject="New %s expense for %s Team is awaiting approval"
% (expense.camp.title, expense.responsible_team.name),
to_recipients=[settings.ECONOMYTEAM_EMAIL],
)
# return to the expense list page
return HttpResponseRedirect(reverse('economy:expense_list', kwargs={'camp_slug': self.camp.slug}))
return HttpResponseRedirect(
reverse("economy:expense_list", kwargs={"camp_slug": self.camp.slug})
)
class ExpenseUpdateView(CampViewMixin, ExpensePermissionMixin, UpdateView):
model = Expense
template_name = 'expense_form.html'
template_name = "expense_form.html"
form_class = ExpenseUpdateForm
def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
if self.get_object().approved:
messages.error(self.request, "This expense has already been approved, it cannot be updated")
return redirect(reverse('economy:expense_list', kwargs={'camp_slug': self.camp.slug}))
messages.error(
self.request,
"This expense has already been approved, it cannot be updated",
)
return redirect(
reverse("economy:expense_list", kwargs={"camp_slug": self.camp.slug})
)
return response
def get_context_data(self, **kwargs):
@ -203,24 +260,31 @@ class ExpenseUpdateView(CampViewMixin, ExpensePermissionMixin, UpdateView):
Do not show teams that are not part of the current camp in the dropdown
"""
context = super().get_context_data(**kwargs)
context['form'].fields['responsible_team'].queryset = Team.objects.filter(camp=self.camp)
context['creditor'] = self.get_object().creditor
context["form"].fields["responsible_team"].queryset = Team.objects.filter(
camp=self.camp
)
context["creditor"] = self.get_object().creditor
return context
def get_success_url(self):
messages.success(self.request, "Expense %s has been updated" % self.get_object().pk)
return(reverse('economy:expense_list', kwargs={'camp_slug': self.camp.slug}))
messages.success(
self.request, "Expense %s has been updated" % self.get_object().pk
)
return reverse("economy:expense_list", kwargs={"camp_slug": self.camp.slug})
class ExpenseDeleteView(CampViewMixin, ExpensePermissionMixin, UpdateView):
model = Expense
template_name = 'expense_delete.html'
template_name = "expense_delete.html"
fields = []
def form_valid(self, form):
expense = self.get_object()
if expense.approved:
messages.error(self.request, "This expense has already been approved, it cannot be deleted")
messages.error(
self.request,
"This expense has already been approved, it cannot be deleted",
)
else:
message = "Expense %s has been deleted" % expense.pk
expense.delete()
@ -228,7 +292,7 @@ class ExpenseDeleteView(CampViewMixin, ExpensePermissionMixin, UpdateView):
return redirect(self.get_success_url())
def get_success_url(self):
return(reverse('economy:expense_list', kwargs={'camp_slug': self.camp.slug}))
return reverse("economy:expense_list", kwargs={"camp_slug": self.camp.slug})
class ExpenseInvoiceView(CampViewMixin, ExpensePermissionMixin, DetailView):
@ -236,6 +300,7 @@ class ExpenseInvoiceView(CampViewMixin, ExpensePermissionMixin, DetailView):
This view returns the invoice for an Expense with the proper mimetype
Uses ExpensePermissionMixin to make sure the user is allowed to see the image
"""
model = Expense
def get(self, request, *args, **kwargs):
@ -246,9 +311,11 @@ class ExpenseInvoiceView(CampViewMixin, ExpensePermissionMixin, DetailView):
# find mimetype
mimetype = magic.from_buffer(invoicedata, mime=True)
# check if we have a PDF, no preview if so, load a pdf icon instead
if mimetype=="application/pdf" and 'preview' in request.GET:
invoicedata = open(os.path.join(settings.DJANGO_BASE_PATH, "static_src/img/pdf.png"), "rb").read()
mimetype = magic.from_buffer(invoicedata, mime=True)
if mimetype == "application/pdf" and "preview" in request.GET:
invoicedata = open(
os.path.join(settings.DJANGO_BASE_PATH, "static_src/img/pdf.png"), "rb"
).read()
mimetype = magic.from_buffer(invoicedata, mime=True)
# put the response together and return it
response = HttpResponse(content_type=mimetype)
response.write(invoicedata)
@ -260,7 +327,7 @@ class ExpenseInvoiceView(CampViewMixin, ExpensePermissionMixin, DetailView):
class ReimbursementListView(LoginRequiredMixin, CampViewMixin, ListView):
model = Reimbursement
template_name = 'reimbursement_list.html'
template_name = "reimbursement_list.html"
def get_queryset(self):
# only return Expenses belonging to the current user
@ -269,7 +336,7 @@ class ReimbursementListView(LoginRequiredMixin, CampViewMixin, ListView):
class ReimbursementDetailView(CampViewMixin, ReimbursementPermissionMixin, DetailView):
model = Reimbursement
template_name = 'reimbursement_detail.html'
template_name = "reimbursement_detail.html"
########### Revenue related views ###############
@ -277,7 +344,7 @@ class ReimbursementDetailView(CampViewMixin, ReimbursementPermissionMixin, Detai
class RevenueListView(LoginRequiredMixin, CampViewMixin, ListView):
model = Revenue
template_name = 'revenue_list.html'
template_name = "revenue_list.html"
def get_queryset(self):
# only return Revenues belonging to the current user
@ -286,13 +353,15 @@ class RevenueListView(LoginRequiredMixin, CampViewMixin, ListView):
class RevenueDetailView(CampViewMixin, RevenuePermissionMixin, DetailView):
model = Revenue
template_name = 'revenue_detail.html'
template_name = "revenue_detail.html"
class RevenueCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequiredMixin, CreateView):
class RevenueCreateView(
CampViewMixin, CredebtorViewMixin, RaisePermissionRequiredMixin, CreateView
):
model = Revenue
template_name = 'revenue_form.html'
permission_required = ("camps.revenue_create_permission")
template_name = "revenue_form.html"
permission_required = "camps.revenue_create_permission"
form_class = RevenueCreateForm
def get_context_data(self, **kwargs):
@ -300,8 +369,10 @@ class RevenueCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequir
Do not show teams that are not part of the current camp in the dropdown
"""
context = super().get_context_data(**kwargs)
context['form'].fields['responsible_team'].queryset = Team.objects.filter(camp=self.camp)
context['debtor'] = self.credebtor
context["form"].fields["responsible_team"].queryset = Team.objects.filter(
camp=self.camp
)
context["debtor"] = self.credebtor
return context
def form_valid(self, form):
@ -321,24 +392,32 @@ class RevenueCreateView(CampViewMixin, CredebtorViewMixin, RaisePermissionRequir
add_outgoing_email(
"emails/revenue_awaiting_approval_email.txt",
formatdict=dict(revenue=revenue),
subject="New %s revenue for %s Team is awaiting approval" % (revenue.camp.title, revenue.responsible_team.name),
subject="New %s revenue for %s Team is awaiting approval"
% (revenue.camp.title, revenue.responsible_team.name),
to_recipients=[settings.ECONOMYTEAM_EMAIL],
)
# return to the revenue list page
return HttpResponseRedirect(reverse('economy:revenue_list', kwargs={'camp_slug': self.camp.slug}))
return HttpResponseRedirect(
reverse("economy:revenue_list", kwargs={"camp_slug": self.camp.slug})
)
class RevenueUpdateView(CampViewMixin, RevenuePermissionMixin, UpdateView):
model = Revenue
template_name = 'revenue_form.html'
template_name = "revenue_form.html"
form_class = RevenueUpdateForm
def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
if self.get_object().approved:
messages.error(self.request, "This revenue has already been approved, it cannot be updated")
return redirect(reverse('economy:revenue_list', kwargs={'camp_slug': self.camp.slug}))
messages.error(
self.request,
"This revenue has already been approved, it cannot be updated",
)
return redirect(
reverse("economy:revenue_list", kwargs={"camp_slug": self.camp.slug})
)
return response
def get_context_data(self, **kwargs):
@ -346,23 +425,30 @@ class RevenueUpdateView(CampViewMixin, RevenuePermissionMixin, UpdateView):
Do not show teams that are not part of the current camp in the dropdown
"""
context = super().get_context_data(**kwargs)
context['form'].fields['responsible_team'].queryset = Team.objects.filter(camp=self.camp)
context["form"].fields["responsible_team"].queryset = Team.objects.filter(
camp=self.camp
)
return context
def get_success_url(self):
messages.success(self.request, "Revenue %s has been updated" % self.get_object().pk)
return(reverse('economy:revenue_list', kwargs={'camp_slug': self.camp.slug}))
messages.success(
self.request, "Revenue %s has been updated" % self.get_object().pk
)
return reverse("economy:revenue_list", kwargs={"camp_slug": self.camp.slug})
class RevenueDeleteView(CampViewMixin, RevenuePermissionMixin, UpdateView):
model = Revenue
template_name = 'revenue_delete.html'
template_name = "revenue_delete.html"
fields = []
def form_valid(self, form):
revenue = self.get_object()
if revenue.approved:
messages.error(self.request, "This revenue has already been approved, it cannot be deleted")
messages.error(
self.request,
"This revenue has already been approved, it cannot be deleted",
)
else:
message = "Revenue %s has been deleted" % revenue.pk
revenue.delete()
@ -370,7 +456,7 @@ class RevenueDeleteView(CampViewMixin, RevenuePermissionMixin, UpdateView):
return redirect(self.get_success_url())
def get_success_url(self):
return(reverse('economy:revenue_list', kwargs={'camp_slug': self.camp.slug}))
return reverse("economy:revenue_list", kwargs={"camp_slug": self.camp.slug})
class RevenueInvoiceView(CampViewMixin, RevenuePermissionMixin, DetailView):
@ -378,6 +464,7 @@ class RevenueInvoiceView(CampViewMixin, RevenuePermissionMixin, DetailView):
This view returns a http response with the invoice for a Revenue object, with the proper mimetype
Uses RevenuePermissionMixin to make sure the user is allowed to see the file
"""
model = Revenue
def get(self, request, *args, **kwargs):
@ -388,11 +475,12 @@ class RevenueInvoiceView(CampViewMixin, RevenuePermissionMixin, DetailView):
# find mimetype
mimetype = magic.from_buffer(invoicedata, mime=True)
# check if we have a PDF, no preview if so, load a pdf icon instead
if mimetype=="application/pdf" and 'preview' in request.GET:
invoicedata = open(os.path.join(settings.DJANGO_BASE_PATH, "static_src/img/pdf.png"), "rb").read()
mimetype = magic.from_buffer(invoicedata, mime=True)
if mimetype == "application/pdf" and "preview" in request.GET:
invoicedata = open(
os.path.join(settings.DJANGO_BASE_PATH, "static_src/img/pdf.png"), "rb"
).read()
mimetype = magic.from_buffer(invoicedata, mime=True)
# put the response together and return it
response = HttpResponse(content_type=mimetype)
response.write(invoicedata)
return response

View file

@ -38,5 +38,4 @@ six==1.12.0
sqlparse==0.3.0
venusian==1.2.0
webencodings==0.5.1
wrapt==1.11.1
graphene-django==2.2.0