Just checking in.

This commit is contained in:
Kumi 2021-03-22 18:42:07 +01:00
parent 54e84be36a
commit 4ca76378df
21 changed files with 200 additions and 35 deletions

View file

@ -1,11 +1,7 @@
from django.db import models from django.db import models
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
class Profile(models.Model): from localauth.models import Profile
user = models.ForeignKey(get_user_model(), models.CASCADE)
class ClientProfile(Profile): class ClientProfile(Profile):
pass pass
class PartnerProfile(Profile):
pass

View file

@ -1,4 +1,10 @@
class SuperUserRequiredMixin(object): from django.utils.decorators import method_decorator
from django.shortcuts import redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.conf import settings
class SuperUserRequiredMixin:
""" """
View mixin which requires that the authenticated user is a super user View mixin which requires that the authenticated user is a super user
(i.e. `is_superuser` is True). (i.e. `is_superuser` is True).
@ -12,5 +18,17 @@ class SuperUserRequiredMixin(object):
'You do not have the permission required to perform the ' 'You do not have the permission required to perform the '
'requested operation.') 'requested operation.')
return redirect(settings.LOGIN_URL) return redirect(settings.LOGIN_URL)
return super(SuperUserRequiredMixin, self).dispatch(request, return super().dispatch(request, *args, **kwargs)
*args, **kwargs)
class LoginRequiredMixin:
"""
View mixin which verifies that the user has authenticated.
NOTE:
This should be the left-most mixin of a view.
"""
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)

View file

@ -3,6 +3,8 @@ from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.utils import timezone from django.utils import timezone
from django_countries.fields import CountryField
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
use_in_migrations = True use_in_migrations = True
@ -57,3 +59,18 @@ class User(AbstractBaseUser):
has_module_perms = has_permission has_module_perms = has_permission
has_perm = has_permission has_perm = has_permission
class Profile(models.Model):
user = models.OneToOneField(User, models.CASCADE)
company = models.CharField(max_length=64, null=True, blank=True)
vat_id = models.CharField(max_length=32, null=True, blank=True)
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
street = models.CharField(max_length=64)
city = models.CharField(max_length=64)
zip = models.CharField(max_length=16)
state = models.CharField(max_length=64)
country = CountryField()
class Meta:
abstract = True

View file

@ -1,6 +1,8 @@
from django.contrib.auth.views import LoginView as Login, LogoutView as Logout from django.contrib.auth.views import LoginView as Login, LogoutView as Logout
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.contrib.auth import login from django.contrib.auth import login
from django.shortcuts import resolve_url
from django.conf import settings
from .forms import RegistrationForm from .forms import RegistrationForm
from .models import User from .models import User

View file

@ -1,3 +1,22 @@
from django.db import models from django.db import models
# Create your models here. from localauth.models import User, Profile
from django_countries.fields import CountryField
class PartnerProfile(Profile):
pass
class Establishment(models.Model):
owner = models.ForeignKey(PartnerProfile, models.CASCADE)
name = models.CharField(max_length=64)
stars = models.IntegerField(null=True, blank=True)
street = models.CharField(max_length=64)
city = models.CharField(max_length=64)
zip = models.CharField(max_length=16)
state = models.CharField(max_length=64)
country = CountryField()
class RoomCategory(models.Model):
establishment = models.ForeignKey(Establishment, models.CASCADE)
name = models.CharField(max_length=64)

View file

@ -3,6 +3,27 @@ from django import template
register = template.Library() register = template.Library()
@register.simple_tag @register.simple_tag
def stars(count, color="yellow"): def stars(number, classes=""):
return """ number = int(number)
""" if not 1 <= number <= 5:
raise ValueError("Number of stars must be between 1 and 5.")
output = ""
for i in range(5):
output += '<span><i class="fa%s fa-star %s"></i></span>' % (("" if i < number else "r"), classes)
return output
@register.simple_tag
def hearts(number, classes=""):
number = int(number)
if not 1 <= number <= 5:
raise ValueError("Number of hearts must be between 1 and 5.")
output = ""
for i in range(5):
output += '<span><i class="fa%s fa-heart %s"></i></span>' % (("" if i < number else "r"), classes)
return output

View file

@ -1,3 +1,9 @@
from django.shortcuts import render from django.views.generic import CreateView
# Create your views here. from .models import PartnerProfile
from localauth.mixins import LoginRequiredMixin
class PartnerRegistrationView(LoginRequiredMixin, CreateView):
model = PartnerProfile
exclude = ["user"]

View file

@ -21,6 +21,8 @@ from .functions import invoice_upload_path
class BillingAddress(models.Model): class BillingAddress(models.Model):
user = models.ForeignKey(get_user_model(), models.CASCADE) user = models.ForeignKey(get_user_model(), models.CASCADE)
company = models.CharField(max_length=64, null=True, blank=True)
vat_id = models.CharField(max_length=32, null=True, blank=True)
first_name = models.CharField(max_length=64) first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64) last_name = models.CharField(max_length=64)
street = models.CharField(max_length=128) street = models.CharField(max_length=128)
@ -129,6 +131,6 @@ class InvoicePayment(PolymorphicModel):
def gateway(self): def gateway(self):
raise NotImplementedError("%s does not implement gateway" % type(self)) raise NotImplementedError("%s does not implement gateway" % type(self))
@staticmethod @classmethod
def initiate(invoice): def initiate(cls, invoice):
raise NotImplementedError("%s does not implement initiate()" % type(self)) raise NotImplementedError("%s does not implement initiate()" % cls.__name__)

View file

@ -11,6 +11,9 @@ class SepaPaymentReference(models.Model):
invoice = models.ForeignKey(Invoice, models.CASCADE) invoice = models.ForeignKey(Invoice, models.CASCADE)
reference = models.IntegerField(default=generate_reference) reference = models.IntegerField(default=generate_reference)
def create_payment(self, amount):
return SepaInvoicePayment.objects.create(invoice=self.invoice, gateway_id=self.reference, amount=amount)
class SepaInvoicePayment(InvoicePayment): class SepaInvoicePayment(InvoicePayment):
@property @property
def gateway(self): def gateway(self):

View file

@ -1,4 +1,7 @@
from django.urls import path from django.urls import path
from .views import SepaApplyPaymentView
urlpatterns = [ urlpatterns = [
path('apply/', SepaApplyPaymentView.as_view(), name="superuser_apply"),
] ]

View file

@ -1,6 +1,7 @@
from django.views.generic import FormView from django.views.generic import FormView
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.contrib import messages from django.contrib import messages
from django.urls import reverse_lazy
from localauth.mixins import SuperUserRequiredMixin from localauth.mixins import SuperUserRequiredMixin
@ -8,15 +9,14 @@ from .forms import SepaApplyPaymentForm
from .models import SepaPaymentReference, SepaInvoicePayment from .models import SepaPaymentReference, SepaInvoicePayment
class SepaApplyPaymentView(SuperUserRequiredMixin, FormView): class SepaApplyPaymentView(SuperUserRequiredMixin, FormView):
template_name = "payment/sepa/apply.html"
form_class = SepaApplyPaymentForm form_class = SepaApplyPaymentForm
success_url = '/' success_url = reverse_lazy("sepa:apply")
def form_valid(self, form): def form_valid(self, form):
reference = form.cleaned_data["reference"] reference = form.cleaned_data["reference"]
pr = get_object_or_404(SepaPaymentReference, reference=reference) pr = get_object_or_404(SepaPaymentReference, reference=reference)
invoice = pr.invoice pr.create_payment(form.cleaned_data["amount"])
SepaInvoicePayment.objects.create(invoice=invoice, amount=form.cleaned_data["amount"])
messages.success(self.request, "Zahlung angewendet.") messages.success(self.request, "Zahlung angewendet.")

View file

@ -1,6 +1,6 @@
from django.urls import path, include from django.urls import path, include
urlpatterns = [ urlpatterns = [
path('gateways/paypal/', include("payment.paypal.urls")), path('gateways/paypal/', include("payment.paypal.urls"), name="paypal"),
path('gateways/sepa/', include("payment.sepa.urls")), path('gateways/sepa/', include("payment.sepa.urls"), name="sepa"),
] ]

View file

@ -1,3 +1,16 @@
from django.db import models from django.db import models
from django.conf import settings
from django.core.validators import MaxValueValidator, MinValueValidator
# Create your models here. # Create your models here.
class Testimonial(models.Model):
name = models.CharField(max_length=128)
text = models.TextField()
stars = models.PositiveIntegerField(
validators=[
MaxValueValidator(5),
MinValueValidator(1)
])
language = models.CharField(max_length=12, choices=settings.LANGUAGES)
public = models.BooleanField(default=False)

View file

@ -1,8 +1,13 @@
from django import template from django import template
from random import SystemRandom
from public.models import Testimonial
register = template.Library() register = template.Library()
@register.simple_tag @register.simple_tag
def testimonials(): def testimonials(count=5, language="de"):
return """ objects = list(Testimonial.objects.filter(language=language)) # pylint: disable=no-member
""" SystemRandom().shuffle(objects)
return objects[:min(count, len(objects))]

View file

@ -6,3 +6,4 @@ django-bootstrap4
pyinvoice pyinvoice
django-countries django-countries
paypal-checkout-serversdk paypal-checkout-serversdk
python-dateutil

1
static/frontend/css/toastr.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
static/frontend/js/toastr.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
<link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon"> <link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon">
<!-- Google Fonts --> <!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i,900,900i%7CMerriweather:300,300i,400,400i,700,700i,900,900i" rel="stylesheet"> <link href="https://fontproxy.kumi.systems/css?family=Lato:300,300i,400,400i,700,700i,900,900i%7CMerriweather:300,300i,400,400i,700,700i,900,900i" rel="stylesheet">
<!-- Bootstrap Stylesheet --> <!-- Bootstrap Stylesheet -->
<link rel="stylesheet" href="{% static "frontend/css/bootstrap.min4.2.1.css" %}"> <link rel="stylesheet" href="{% static "frontend/css/bootstrap.min4.2.1.css" %}">
@ -40,6 +40,9 @@
<!-- Magnific Gallery --> <!-- Magnific Gallery -->
<link rel="stylesheet" href="{% static "frontend/css/magnific-popup.css" %}"> <link rel="stylesheet" href="{% static "frontend/css/magnific-popup.css" %}">
<!-- Toastr -->
<link rel="stylesheet" href="{% static "frontend/css/toastr.min.css" %}">
</head> </head>
@ -175,7 +178,15 @@
<li><a class="dropdown-item" href="/">{% trans "Impressum" %}</a></li> <li><a class="dropdown-item" href="/">{% trans "Impressum" %}</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown-item search-btn"> {% if request.user.is_superuser %}
<li class="nav-item dropdown">
<a href="#" class="nav-link" data-toggle="dropdown">Admin<span><i class="fa fa-angle-down"></i></span></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url "payment:sepa:apply" %}">{% trans "SEPA-Zahlung anwenden" %}</a></li>
</ul>
</li>
{% endif %}
<li class="dropdown-item search-btn" style="display: none;">
<a href="#" class="search-button" onClick="openSearch()"><span><i class="fa fa-search"></i></span></a> <a href="#" class="search-button" onClick="openSearch()"><span><i class="fa fa-search"></i></span></a>
</li> </li>
</ul> </ul>
@ -520,6 +531,7 @@
<script src="{% static "frontend/js/bootstrap.min4.2.1.js" %}"></script> <script src="{% static "frontend/js/bootstrap.min4.2.1.js" %}"></script>
<script src="{% static "frontend/js/jquery.flexslider.js" %}"></script> <script src="{% static "frontend/js/jquery.flexslider.js" %}"></script>
<script src="{% static "frontend/js/bootstrap-datepicker.js" %}"></script> <script src="{% static "frontend/js/bootstrap-datepicker.js" %}"></script>
<script src="{% static "frontend/js/toastr.min.js" %}"></script>
<script src="{% static "frontend/js/owl.carousel.min.js" %}"></script> <script src="{% static "frontend/js/owl.carousel.min.js" %}"></script>
<script src="{% static "frontend/js/custom-navigation.js" %}"></script> <script src="{% static "frontend/js/custom-navigation.js" %}"></script>
<script src="{% static "frontend/js/custom-flex.js" %}"></script> <script src="{% static "frontend/js/custom-flex.js" %}"></script>
@ -528,6 +540,21 @@
<script src="{% static "frontend/js/custom-video.js" %}"></script> <script src="{% static "frontend/js/custom-video.js" %}"></script>
<script src="{% static "frontend/js/popup-ad.js" %}"></script> <script src="{% static "frontend/js/popup-ad.js" %}"></script>
<script src="{% static "frontend/js/autocomplete.js" %}"></script> <script src="{% static "frontend/js/autocomplete.js" %}"></script>
{% if messages %}
{% for message in messages %}
{% if message.tags == 'success'%}
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
{% elif message.tags == 'info' %}
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
{% elif message.tags == 'warning' %}
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
{% elif message.tags == 'error' %}
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
{% endif %}
{% endfor %}
{% endif %}
{% block "scripts" %} {% block "scripts" %}
{% endblock %} {% endblock %}
<!-- Page Scripts Ends --> <!-- Page Scripts Ends -->

View file

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
<html> <html>
<head> <head>
<title>Urlaubsauktion - {% trans "Weiterleitung" %}</title> <title>JourneyJoker - {% trans "Weiterleitung" %}</title>
</head> </head>
<body> <body>
<p>{% trans "Sie werden zu unserem Zahlungsdienstleister weitergeleitet. Wir bitten um einen Augenblick Geduld." %}</p> <p>{% trans "Sie werden zu unserem Zahlungsdienstleister weitergeleitet. Wir bitten um einen Augenblick Geduld." %}</p>

View file

@ -0,0 +1,24 @@
{% extends "frontend/base.html" %}
{% load i18n %}
{% load bootstrap4 %}
{% block "content" %}
<!--===== INNERPAGE-WRAPPER ====-->
<section class="innerpage-wrapper">
<div id="payment-success" class="section-padding">
<div class="container text-center">
<div class="row d-flex justify-content-center">
<div class="col-md-12 col-lg-8 col-lg-offset-2">
<div class="payment-success-text">
<h2>{% trans "SEPA-Zahlung anwenden" %}</h2>
<form method="POST">
{% csrf_token %}
{% bootstrap_form form %}
<button class="btn btn-orange btn-block">{% trans "Anwenden" %}</button>
</div>
</div><!-- end columns -->
</div><!-- end row -->
</div><!-- end container -->
</div><!-- end coming-soon-text -->
</section><!-- end innerpage-wrapper -->
{% endblock %}

View file

@ -18,8 +18,8 @@ from django.urls import path, include
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('', include('public.urls')), path('', include('public.urls'), name="frontend"),
path('auth/', include('localauth.urls')), path('auth/', include('localauth.urls'), name="localauth"),
path('auction/', include('auction.urls')), path('auction/', include('auction.urls'), name="auction"),
path('payment/', include('payment.urls')), path('payment/', include('payment.urls'), name="payment"),
] ]