diff --git a/.gitignore b/.gitignore index 13a0b84..c6d0013 100644 --- a/.gitignore +++ b/.gitignore @@ -63,9 +63,12 @@ coverage.xml # Django stuff: *.log -local_settings.py -#db.sqlite3 -db.sqlite3-journal +*.pot +*.pyc +__pycache__ +db.sqlite3 +*.sql +media # Flask stuff: instance/ @@ -117,6 +120,7 @@ venv/ ENV/ env.bak/ venv.bak/ +data/ # Spyder project settings .spyderproject diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..f77ba1d --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +release: python manage.py migrate +web: gunicorn config.wsgi diff --git a/src/billing/views.py b/src/billing/views.py index 15aa2cd..41f78cb 100644 --- a/src/billing/views.py +++ b/src/billing/views.py @@ -26,6 +26,7 @@ from .forms import ( from tools.pdf_generator import BillPaper +@login_required @require_http_methods(["GET"]) def client_lookup(request): """ Récupère la liste des clients à la volée suivant des caractères de recherches entrés. @@ -42,6 +43,7 @@ def client_lookup(request): return HttpResponse(json, content_type="application/json") +@login_required @require_http_methods(["GET"]) def client_listing(request): """ Récupère la liste de tous les clients. """ @@ -50,6 +52,7 @@ def client_listing(request): return render(request, "billing/clients/listing.html", context) +@login_required @require_http_methods(["GET"]) def client_details(request, client_id=None): """ Récupère les informations d'un client. @@ -62,7 +65,7 @@ def client_details(request, client_id=None): return render(request, "billing/clients/details.html", context) -# @login_required +@login_required @require_http_methods(["GET", "POST"]) def client_create_or_update(request, client_id=None): """ Création d'un client. @@ -90,6 +93,7 @@ def client_create_or_update(request, client_id=None): return render(request, "billing/clients/create.html", context) +@login_required @require_http_methods(["GET"]) def contract_listing(request): """ Récupère la liste de tous les contrats. """ @@ -98,6 +102,7 @@ def contract_listing(request): return render(request, "billing/contracts/listing.html", context) +@login_required @require_http_methods(["GET"]) def contract_detail(request, contract_id): """ @@ -123,7 +128,7 @@ def contract_detail(request, contract_id): return render(request, "billing/contracts/details.html", context) -# @login_required +@login_required @require_http_methods(["GET", "POST"]) def contract_create_or_update(request, contract_id=None): """ Création d'un contract. @@ -151,6 +156,7 @@ def contract_create_or_update(request, contract_id=None): return render(request, "billing/contracts/create.html", context) +@login_required @require_http_methods(["GET"]) def contract_export(request, contract_id): """ Génere un fichier PDF pour fournir au client. @@ -173,6 +179,7 @@ def contract_export(request, contract_id): return response +@login_required @require_http_methods(["GET", "POST"]) def prestation_create_or_update(request, prestation_id=None): """ Création d'un contract. @@ -202,6 +209,7 @@ def prestation_create_or_update(request, prestation_id=None): return render(request, "billing/prestations/create.html", context) +@login_required @require_http_methods(["GET"]) def contract_lookup(request): """ Récupère la liste des contrat à la volée suivant des caractères de recherches entrés. diff --git a/src/comptaClub/settings.py b/src/comptaClub/settings.py index c21354d..9552c56 100644 --- a/src/comptaClub/settings.py +++ b/src/comptaClub/settings.py @@ -1,4 +1,23 @@ import os +import environ + +# Initialise environment variables +env = environ.Env() +environ.Env.read_env() + +# Sentry +SENTRY_DSN = env("SENTRY_DSN", default=None) +if SENTRY_DSN is not None: + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + + sentry_sdk.init( + dsn=SENTRY_DSN, + integrations=[DjangoIntegration()], + traces_sample_rate=env("SENTRY_TRACES_SAMPLE_RATE", default=1.0), + send_default_pii=True, + debug=env("SENTRY_DEBUG", default=True) + ) # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -8,12 +27,14 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "lf#a+mh&9gw&wwn32d!=7_a)g7s5ju2z0m)r(l3xhhe+eb$fp@" +# SECRET_KEY = "lf#a+mh&9gw&wwn32d!=7_a)g7s5ju2z0m)r(l3xhhe+eb$fp@" +SECRET_KEY = env('SECRET_KEY', default="Super Little Poney 2000") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +# ALLOWED_HOSTS = [] +ALLOWED_HOSTS = env('ALLOWED_HOSTS', default="localhost").split() # Application definition @@ -68,10 +89,11 @@ TEMPLATES = [ # https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } + # "default": { + # "ENGINE": "django.db.backends.sqlite3", + # "NAME": os.path.join(BASE_DIR, "db.sqlite3"), + # } + 'default': env.db_url("DATABASE_URL", default="sqlite:///db.sqlite3") } # CACHES = { diff --git a/src/comptaClub/urls.py b/src/comptaClub/urls.py index da57c74..e5b79bb 100644 --- a/src/comptaClub/urls.py +++ b/src/comptaClub/urls.py @@ -39,12 +39,12 @@ urlpatterns = [ ), # Billing - # TODO: une seule ligne ! path(r"billing/client/", include(billing.urls.client_urlpatterns)), path(r"billing/contract/", include(billing.urls.contract_urlpatterns)), path(r"billing/prestation/", include(billing.urls.prestation_urlpatterns)), # Home path(r"", year_listing), + path("", include("core.urls")), path(r"admin/", admin.site.urls), ] diff --git a/src/comptabilite/views.py b/src/comptabilite/views.py index 63e188e..7e6188d 100644 --- a/src/comptabilite/views.py +++ b/src/comptabilite/views.py @@ -8,6 +8,7 @@ from django.urls import reverse from collections import OrderedDict from django.views.decorators.http import require_http_methods +from django.contrib.auth.decorators import login_required from .models import ( Transaction, @@ -39,6 +40,7 @@ EXTENSES = 0 RECETTES = 1 +@login_required @require_http_methods(["GET"]) def comptability_export(request, accounting_year, export_type): """ @@ -58,6 +60,7 @@ def comptability_export(request, accounting_year, export_type): return get_transaction_list_for_accountingyear_ooo(request, accounting_year) +@login_required @require_http_methods(["GET"]) def get_transaction_list_for_accountingyear_ooo(request, accounting_year): """ @@ -82,6 +85,7 @@ def get_transaction_list_for_accountingyear_ooo(request, accounting_year): return render(request, "comptability/year_transaction_export_ooo.html", context) +@login_required @require_http_methods(["GET"]) def get_transaction_list_for_accountingyear_sxs(request, accounting_year): """ @@ -112,6 +116,7 @@ def get_transaction_list_for_accountingyear_sxs(request, accounting_year): return render(request, "comptability/year_transaction_export_sxs.html", context) +@login_required @require_http_methods(["GET"]) def export_year_spf_finance(request, accounting_year): """ @@ -188,6 +193,7 @@ def export_year_spf_finance(request, accounting_year): return render(request, "comptability/year_transaction_export_spf.html", context) +@login_required @require_http_methods(["GET"]) def generate_pdf_for_spf(request, accounting_year): """ Génère un fichier PDF suivant les contraintes du SPF Finances @@ -237,6 +243,7 @@ def __get_transactions_for_accounting_year_and_kind( return transactions_list, transaction_kind +@login_required @require_http_methods(["GET"]) def transaction_by_year_listing(request, accounting_year, transaction_kind=None): """ Liste toutes les lignes de comptabilité pour une année recue en paramètre @@ -323,6 +330,7 @@ def transaction_by_year_listing(request, accounting_year, transaction_kind=None) return render(request, "comptability/transactions/listing.html", context) +@login_required @require_http_methods(["GET"]) def year_listing(request): """ @@ -338,6 +346,7 @@ def year_listing(request): return render(request, "comptability/year_listing.html", context) +@login_required @require_http_methods(["GET"]) def transaction_listing_for_year_and_type( request, accounting_year, transaction_type_id @@ -384,6 +393,7 @@ def transaction_listing_for_year_and_type( return render(request, "comptability/transactions/listing.html", context) +@login_required @require_http_methods(["GET"]) def transaction_details(request, transaction_id): """ @@ -395,6 +405,7 @@ def transaction_details(request, transaction_id): return render(request, "comptability/transactions/details.html", context) +@login_required @require_http_methods(["GET", "POST"]) def transaction_create_or_update(request, transaction_id=None): """ Création ou modificatin d'une transaction. diff --git a/src/core/__init__.py b/src/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/core/urls.py b/src/core/urls.py new file mode 100644 index 0000000..06cbf87 --- /dev/null +++ b/src/core/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from .views import login, logout #, home, search + + +urlpatterns = [ + # path(r"search/", search, name="global_search"), + path(r"login/", login, name="login"), + path(r"logout/", logout, name="logout"), + # path(r"", home, name="home"), +] diff --git a/src/core/views.py b/src/core/views.py new file mode 100644 index 0000000..c176615 --- /dev/null +++ b/src/core/views.py @@ -0,0 +1,41 @@ +from datetime import datetime, timedelta + +from django.db.models import Q +from django.shortcuts import render +from django.utils import timezone +from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout +from django.http import HttpResponseRedirect +from django.contrib.auth.decorators import login_required +from django.views.decorators.http import require_http_methods +from django.urls import reverse + + +def login(request): + """Formulaire d'authentifictation.""" + + if request.method == "POST": + username = request.POST["login"] + password = request.POST["password"] + + user = authenticate(username=username, password=password) + + if user is not None: + if user.is_active: + auth_login(request, user) + return HttpResponseRedirect(reverse("year_listing")) + + context = {"message": "Account disabled."} + else: + context = {"message": "Wrong login/password."} + else: + context = {} + + return render(request, "login.html", context) + + +@login_required +@require_http_methods(["GET"]) +def logout(request): + """Fonction de déconnexion.""" + auth_logout(request) + return HttpResponseRedirect(reverse("login")) \ No newline at end of file diff --git a/src/eventCompta/views.py b/src/eventCompta/views.py index e797cda..704d541 100644 --- a/src/eventCompta/views.py +++ b/src/eventCompta/views.py @@ -2,6 +2,7 @@ from django.db.models import Sum from django.shortcuts import render, get_object_or_404 +from django.contrib.auth.decorators import login_required from collections import OrderedDict @@ -88,6 +89,7 @@ def __compute_sum_amount(transaction_list, with_simulated=None): return total +@login_required @require_http_methods(["GET"]) def event_details(request, event_id): """ @@ -162,6 +164,7 @@ def event_details(request, event_id): return render(request, "event/details.html", context) +@login_required @require_http_methods(["GET"]) def event_listing(request): """ @@ -172,6 +175,7 @@ def event_listing(request): return render(request, "event/listing.html", context) +@login_required @require_http_methods(["GET", "POST"]) def event_create_or_update(request, event_id=None): """ Création ou modificatin d'une event. diff --git a/src/templates/base.html b/src/templates/base.html index 2b175e2..086188d 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -49,7 +49,10 @@
  • Liste contracts
  • -
  • Administration
  • + {% if user.username == 'Sulley' %} +
  • Administration
  • + {% endif %} +
  • Déconnexion
  • diff --git a/src/templates/billing/prestations/create.html b/src/templates/billing/prestations/create.html new file mode 100644 index 0000000..2478554 --- /dev/null +++ b/src/templates/billing/prestations/create.html @@ -0,0 +1,99 @@ +{% extends "base.html" %} + +{% block content %} + + + +{% endblock %} \ No newline at end of file diff --git a/src/templates/billing/prestations/listing.html b/src/templates/billing/prestations/listing.html new file mode 100644 index 0000000..9e77b1d --- /dev/null +++ b/src/templates/billing/prestations/listing.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} + +{% block content %} + + + + +{% endblock %} \ No newline at end of file diff --git a/src/templates/login.html b/src/templates/login.html new file mode 100644 index 0000000..74401a9 --- /dev/null +++ b/src/templates/login.html @@ -0,0 +1,106 @@ +{% load static %} + + + + + + + + + + + + + + + + + + {% block extra_head %}{% endblock %} + {% block page_title %}Comptabilité{% endblock %} + + + + + + + + + + + + + + + + {% block extra_script %}{% endblock %} + + +
    {% block content %}{% endblock %}
    + + + + diff --git a/tox.ini b/tox.ini index a2073d4..2032883 100644 --- a/tox.ini +++ b/tox.ini @@ -3,6 +3,6 @@ max-line-length = 100 exclude = migrations, manage.py, ._* [pytest] -DJANGO_SETTINGS_MODULE = comptaClub.settings +DJANGO_SETTINGS_MODULE = config.settings # -- recommended but optional: python_files = tests.py test_*.py *_tests.py \ No newline at end of file