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.contrib.auth import get_user_model
class Profile(models.Model):
user = models.ForeignKey(get_user_model(), models.CASCADE)
from localauth.models import Profile
class ClientProfile(Profile):
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
(i.e. `is_superuser` is True).
@ -12,5 +18,17 @@ class SuperUserRequiredMixin(object):
'You do not have the permission required to perform the '
'requested operation.')
return redirect(settings.LOGIN_URL)
return super(SuperUserRequiredMixin, self).dispatch(request,
*args, **kwargs)
return super().dispatch(request, *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.utils import timezone
from django_countries.fields import CountryField
class UserManager(BaseUserManager):
use_in_migrations = True
@ -56,4 +58,19 @@ class User(AbstractBaseUser):
return self.is_superuser
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.http.response import HttpResponseRedirect
from django.contrib.auth import login
from django.shortcuts import resolve_url
from django.conf import settings
from .forms import RegistrationForm
from .models import User

View file

@ -1,3 +1,22 @@
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.simple_tag
def stars(count, color="yellow"):
return """
"""
def stars(number, classes=""):
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):
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)
last_name = models.CharField(max_length=64)
street = models.CharField(max_length=128)
@ -129,6 +131,6 @@ class InvoicePayment(PolymorphicModel):
def gateway(self):
raise NotImplementedError("%s does not implement gateway" % type(self))
@staticmethod
def initiate(invoice):
raise NotImplementedError("%s does not implement initiate()" % type(self))
@classmethod
def initiate(cls, invoice):
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)
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):
@property
def gateway(self):

View file

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

View file

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

View file

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

View file

@ -1,3 +1,16 @@
from django.db import models
from django.conf import settings
from django.core.validators import MaxValueValidator, MinValueValidator
# 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 random import SystemRandom
from public.models import Testimonial
register = template.Library()
@register.simple_tag
def testimonials():
return """
"""
def testimonials(count=5, language="de"):
objects = list(Testimonial.objects.filter(language=language)) # pylint: disable=no-member
SystemRandom().shuffle(objects)
return objects[:min(count, len(objects))]

View file

@ -5,4 +5,5 @@ dbsettings
django-bootstrap4
pyinvoice
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">
<!-- 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 -->
<link rel="stylesheet" href="{% static "frontend/css/bootstrap.min4.2.1.css" %}">
@ -40,6 +40,9 @@
<!-- Magnific Gallery -->
<link rel="stylesheet" href="{% static "frontend/css/magnific-popup.css" %}">
<!-- Toastr -->
<link rel="stylesheet" href="{% static "frontend/css/toastr.min.css" %}">
</head>
@ -175,7 +178,15 @@
<li><a class="dropdown-item" href="/">{% trans "Impressum" %}</a></li>
</ul>
</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>
</li>
</ul>
@ -520,6 +531,7 @@
<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/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/custom-navigation.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/popup-ad.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" %}
{% endblock %}
<!-- Page Scripts Ends -->

View file

@ -1,7 +1,7 @@
{% load i18n %}
<html>
<head>
<title>Urlaubsauktion - {% trans "Weiterleitung" %}</title>
<title>JourneyJoker - {% trans "Weiterleitung" %}</title>
</head>
<body>
<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 = [
path('admin/', admin.site.urls),
path('', include('public.urls')),
path('auth/', include('localauth.urls')),
path('auction/', include('auction.urls')),
path('payment/', include('payment.urls')),
path('', include('public.urls'), name="frontend"),
path('auth/', include('localauth.urls'), name="localauth"),
path('auction/', include('auction.urls'), name="auction"),
path('payment/', include('payment.urls'), name="payment"),
]