mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-08-19 13:43:40 +00:00
style: 🎨 Apply black and isort
This commit is contained in:
parent
6736caf9f4
commit
ec2b4afd41
141 changed files with 1687 additions and 1942 deletions
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class ApiConfig(AppConfig):
|
||||
"""Configuration of api app."""
|
||||
|
||||
name = "api"
|
||||
name = "api"
|
||||
|
|
|
@ -31,12 +31,10 @@ from rest_framework.authentication import TokenAuthentication
|
|||
|
||||
|
||||
class ExpiringTokenAuthentication(TokenAuthentication):
|
||||
"""Authenticate a user if the provided token is valid and not expired.
|
||||
"""
|
||||
"""Authenticate a user if the provided token is valid and not expired."""
|
||||
|
||||
def authenticate_credentials(self, key):
|
||||
"""See base class. Add the verification the token is not expired.
|
||||
"""
|
||||
"""See base class. Add the verification the token is not expired."""
|
||||
base = super(ExpiringTokenAuthentication, self)
|
||||
user, token = base.authenticate_credentials(key)
|
||||
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
"""Defines the permission classes used in the API.
|
||||
"""
|
||||
|
||||
from rest_framework import permissions, exceptions
|
||||
from django.http import Http404
|
||||
from rest_framework import exceptions, permissions
|
||||
|
||||
from . import acl
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
# The namespace used for the API. It must match the namespace used in the
|
||||
# urlpatterns to include the API URLs.
|
||||
API_NAMESPACE = "api"
|
||||
|
@ -59,7 +58,3 @@ class NamespacedHMSerializer(serializers.HyperlinkedModelSerializer):
|
|||
|
||||
serializer_related_field = NamespacedHRField
|
||||
serializer_url_field = NamespacedHIField
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -28,12 +28,13 @@ can also be register. That way a complete API root page presenting all URLs
|
|||
can be generated automatically.
|
||||
"""
|
||||
|
||||
from django.urls import path, include
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import include, path
|
||||
|
||||
from . import views
|
||||
from .routers import AllViewsRouter
|
||||
from django.conf import settings
|
||||
|
||||
app_name = "api"
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ the response (JSON or other), the CSRF exempting, ...
|
|||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.contrib.auth.models import Group
|
||||
from rest_framework import viewsets, generics, views
|
||||
from django.db.models import Q
|
||||
from rest_framework import generics, views, viewsets
|
||||
from rest_framework.authtoken.models import Token
|
||||
from rest_framework.authtoken.views import ObtainAuthToken
|
||||
from rest_framework.response import Response
|
||||
|
@ -41,7 +41,6 @@ from .pagination import PageSizedPagination
|
|||
from .permissions import ACLPermission
|
||||
|
||||
|
||||
|
||||
class ObtainExpiringAuthToken(ObtainAuthToken):
|
||||
"""Exposes a view to obtain a authentication token.
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ from __future__ import unicode_literals
|
|||
from django.contrib import admin
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
from .models import Facture, Article, Banque, Paiement, Cotisation, Vente
|
||||
from .models import CustomInvoice, CostEstimate
|
||||
from .models import (Article, Banque, CostEstimate, Cotisation, CustomInvoice,
|
||||
Facture, Paiement, Vente)
|
||||
|
||||
|
||||
class FactureAdmin(VersionAdmin):
|
||||
|
|
|
@ -23,13 +23,13 @@ from rest_framework import serializers
|
|||
|
||||
import cotisations.models as cotisations
|
||||
import preferences.models as preferences
|
||||
from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer
|
||||
from api.serializers import (NamespacedHIField, NamespacedHMSerializer,
|
||||
NamespacedHRField)
|
||||
from users.api.serializers import UserSerializer
|
||||
|
||||
|
||||
class FactureSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Facture` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Facture` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Facture
|
||||
|
@ -54,8 +54,7 @@ class BaseInvoiceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class VenteSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Vente` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Vente` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Vente
|
||||
|
@ -74,17 +73,24 @@ class VenteSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ArticleSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Article` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Article` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Article
|
||||
fields = ("name", "prix", "duration_membership", "duration_days_membership", "duration_connection", "duration_days_connection", "type_user", "api_url")
|
||||
fields = (
|
||||
"name",
|
||||
"prix",
|
||||
"duration_membership",
|
||||
"duration_days_membership",
|
||||
"duration_connection",
|
||||
"duration_days_connection",
|
||||
"type_user",
|
||||
"api_url",
|
||||
)
|
||||
|
||||
|
||||
class BanqueSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Banque` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Banque` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Banque
|
||||
|
@ -92,8 +98,7 @@ class BanqueSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class PaiementSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Paiement` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Paiement` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Paiement
|
||||
|
@ -101,17 +106,23 @@ class PaiementSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class CotisationSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `cotisations.models.Cotisation` objects.
|
||||
"""
|
||||
"""Serialize `cotisations.models.Cotisation` objects."""
|
||||
|
||||
class Meta:
|
||||
model = cotisations.Cotisation
|
||||
fields = ("vente", "type_cotisation", "date_start_con", "date_end_con", "date_start_memb", "date_end_memb", "api_url")
|
||||
fields = (
|
||||
"vente",
|
||||
"type_cotisation",
|
||||
"date_start_con",
|
||||
"date_end_con",
|
||||
"date_start_memb",
|
||||
"date_end_memb",
|
||||
"api_url",
|
||||
)
|
||||
|
||||
|
||||
class ReminderUsersSerializer(UserSerializer):
|
||||
"""Serialize the data about a mailing member.
|
||||
"""
|
||||
"""Serialize the data about a mailing member."""
|
||||
|
||||
class Meta(UserSerializer.Meta):
|
||||
fields = ("get_full_name", "get_mail")
|
||||
|
|
|
@ -27,12 +27,11 @@ urls_viewset = [
|
|||
(r"cotisations/article", views.ArticleViewSet, None),
|
||||
(r"cotisations/banque", views.BanqueViewSet, None),
|
||||
(r"cotisations/paiement", views.PaiementViewSet, None),
|
||||
(r"cotisations/cotisation", views.CotisationViewSet, None)
|
||||
(r"cotisations/cotisation", views.CotisationViewSet, None),
|
||||
]
|
||||
|
||||
urls_view = [
|
||||
(r"cotisations/reminder-get-users", views.ReminderView),
|
||||
|
||||
# Deprecated
|
||||
(r"reminder/get-users", views.ReminderView),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -19,71 +19,65 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from rest_framework import viewsets, generics
|
||||
from rest_framework import generics, viewsets
|
||||
|
||||
from . import serializers
|
||||
import cotisations.models as cotisations
|
||||
import preferences.models as preferences
|
||||
|
||||
from . import serializers
|
||||
|
||||
|
||||
class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects."""
|
||||
|
||||
queryset = cotisations.Facture.objects.all()
|
||||
serializer_class = serializers.FactureSerializer
|
||||
|
||||
|
||||
class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects."""
|
||||
|
||||
queryset = cotisations.BaseInvoice.objects.all()
|
||||
serializer_class = serializers.BaseInvoiceSerializer
|
||||
|
||||
|
||||
class VenteViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Vente` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Vente` objects."""
|
||||
|
||||
queryset = cotisations.Vente.objects.all()
|
||||
serializer_class = serializers.VenteSerializer
|
||||
|
||||
|
||||
class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Article` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Article` objects."""
|
||||
|
||||
queryset = cotisations.Article.objects.all()
|
||||
serializer_class = serializers.ArticleSerializer
|
||||
|
||||
|
||||
class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Banque` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Banque` objects."""
|
||||
|
||||
queryset = cotisations.Banque.objects.all()
|
||||
serializer_class = serializers.BanqueSerializer
|
||||
|
||||
|
||||
class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Paiement` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Paiement` objects."""
|
||||
|
||||
queryset = cotisations.Paiement.objects.all()
|
||||
serializer_class = serializers.PaiementSerializer
|
||||
|
||||
|
||||
class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Cotisation` objects.
|
||||
"""
|
||||
"""Exposes list and details of `cotisations.models.Cotisation` objects."""
|
||||
|
||||
queryset = cotisations.Cotisation.objects.all()
|
||||
serializer_class = serializers.CotisationSerializer
|
||||
|
||||
|
||||
class ReminderView(generics.ListAPIView):
|
||||
"""Output for users to remind an end of their subscription.
|
||||
"""
|
||||
"""Output for users to remind an end of their subscription."""
|
||||
|
||||
queryset = preferences.Reminder.objects.all()
|
||||
serializer_class = serializers.ReminderSerializer
|
||||
serializer_class = serializers.ReminderSerializer
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class CotisationsConfig(AppConfig):
|
||||
"""Configuration of cotisations app."""
|
||||
|
||||
name = "cotisations"
|
||||
name = "cotisations"
|
||||
|
|
|
@ -37,25 +37,18 @@ of each of the method.
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.forms import ModelForm, Form
|
||||
from django.core.validators import MinValueValidator
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import Q
|
||||
from django.forms import Form, ModelForm
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.field_permissions import FieldPermissionFormMixin
|
||||
from re2o.mixins import FormRevMixin
|
||||
from re2o.widgets import AutocompleteModelWidget
|
||||
from .models import (
|
||||
Article,
|
||||
Paiement,
|
||||
Facture,
|
||||
Banque,
|
||||
CustomInvoice,
|
||||
Vente,
|
||||
CostEstimate,
|
||||
)
|
||||
|
||||
from .models import (Article, Banque, CostEstimate, CustomInvoice, Facture,
|
||||
Paiement, Vente)
|
||||
from .payment_methods import balance
|
||||
|
||||
|
||||
|
|
|
@ -32,29 +32,29 @@ each.
|
|||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.contrib import messages
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
from django.db.models import Q, Max
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.db.models import Max, Q
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.dispatch import receiver
|
||||
from django.forms import ValidationError
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib import messages
|
||||
|
||||
from preferences.models import CotisationsOption
|
||||
import users.models
|
||||
import users.signals
|
||||
from cotisations.utils import (find_payment_method, send_mail_invoice,
|
||||
send_mail_voucher)
|
||||
from cotisations.validators import check_no_balance
|
||||
from machines.models import regen
|
||||
from preferences.models import CotisationsOption
|
||||
from re2o.field_permissions import FieldPermissionModelMixin
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
import users.signals
|
||||
import users.models
|
||||
|
||||
from cotisations.utils import find_payment_method, send_mail_invoice, send_mail_voucher
|
||||
from cotisations.validators import check_no_balance
|
||||
|
||||
|
||||
class BaseInvoice(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
||||
|
@ -360,7 +360,13 @@ def facture_post_save(**kwargs):
|
|||
if facture.valid:
|
||||
user = facture.user
|
||||
user.set_active()
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=True, mac_refresh=False)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=True,
|
||||
mac_refresh=False,
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Facture)
|
||||
|
@ -369,7 +375,13 @@ def facture_post_delete(**kwargs):
|
|||
Synchronise the LDAP user after an invoice has been deleted.
|
||||
"""
|
||||
user = kwargs["instance"].user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=True, mac_refresh=False)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=True,
|
||||
mac_refresh=False,
|
||||
)
|
||||
|
||||
|
||||
class CustomInvoice(BaseInvoice):
|
||||
|
@ -481,9 +493,7 @@ class Vente(RevMixin, AclMixin, models.Model):
|
|||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("change_all_vente", _("Can edit all the previous purchases")),
|
||||
)
|
||||
permissions = (("change_all_vente", _("Can edit all the previous purchases")),)
|
||||
verbose_name = _("purchase")
|
||||
verbose_name_plural = _("purchases")
|
||||
|
||||
|
@ -660,7 +670,13 @@ def vente_post_save(**kwargs):
|
|||
purchase.cotisation.save()
|
||||
user = purchase.facture.facture.user
|
||||
user.set_active()
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=True, access_refresh=True, mac_refresh=False)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=True,
|
||||
access_refresh=True,
|
||||
mac_refresh=False,
|
||||
)
|
||||
|
||||
|
||||
# TODO : change vente to purchase
|
||||
|
@ -676,7 +692,13 @@ def vente_post_delete(**kwargs):
|
|||
return
|
||||
if purchase.type_cotisation:
|
||||
user = invoice.user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=True, access_refresh=True, mac_refresh=False)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=True,
|
||||
access_refresh=True,
|
||||
mac_refresh=False,
|
||||
)
|
||||
|
||||
|
||||
class Article(RevMixin, AclMixin, models.Model):
|
||||
|
@ -740,9 +762,7 @@ class Article(RevMixin, AclMixin, models.Model):
|
|||
unique_together = ("name", "type_user")
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("buy_every_article", _("Can buy every article")),
|
||||
)
|
||||
permissions = (("buy_every_article", _("Can buy every article")),)
|
||||
verbose_name = "article"
|
||||
verbose_name_plural = "articles"
|
||||
|
||||
|
@ -844,9 +864,7 @@ class Paiement(RevMixin, AclMixin, models.Model):
|
|||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("use_every_payment", _("Can use every payment method")),
|
||||
)
|
||||
permissions = (("use_every_payment", _("Can use every payment method")),)
|
||||
verbose_name = _("payment method")
|
||||
verbose_name_plural = _("payment methods")
|
||||
|
||||
|
|
|
@ -127,6 +127,6 @@ method to your model, where `form` is an instance of
|
|||
"""
|
||||
|
||||
|
||||
from . import comnpay, cheque, balance, note_kfet, free, urls
|
||||
from . import balance, cheque, comnpay, free, note_kfet, urls
|
||||
|
||||
PAYMENT_METHODS = [comnpay, cheque, balance, note_kfet, free]
|
||||
|
|
|
@ -18,12 +18,11 @@
|
|||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.contrib import messages
|
||||
from django.db import models
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
from cotisations.models import Paiement
|
||||
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django import forms
|
||||
|
||||
from re2o.mixins import FormRevMixin
|
||||
from cotisations.models import Facture as Invoice
|
||||
from re2o.mixins import FormRevMixin
|
||||
|
||||
|
||||
class InvoiceForm(FormRevMixin, forms.ModelForm):
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [url(r"^validate/(?P<invoice_pk>[0-9]+)$", views.cheque, name="validate")]
|
||||
|
|
|
@ -23,17 +23,17 @@
|
|||
Here are defined some views dedicated to cheque payement.
|
||||
"""
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, render, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from cotisations.models import Facture as Invoice
|
||||
from cotisations.utils import find_payment_method
|
||||
|
||||
from .models import ChequePayment
|
||||
from .forms import InvoiceForm
|
||||
from .models import ChequePayment
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -3,15 +3,15 @@ The module in charge of handling the negociation with Comnpay
|
|||
for online payment
|
||||
"""
|
||||
|
||||
import time
|
||||
from random import randrange
|
||||
import base64
|
||||
import hashlib
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
from random import randrange
|
||||
|
||||
|
||||
class Transaction:
|
||||
""" The class representing a transaction with all the functions
|
||||
"""The class representing a transaction with all the functions
|
||||
used during the negociation
|
||||
"""
|
||||
|
||||
|
@ -35,7 +35,7 @@ class Transaction:
|
|||
self.idTransaction = ""
|
||||
|
||||
def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""):
|
||||
""" Build an HTML hidden form with the different parameters for the
|
||||
"""Build an HTML hidden form with the different parameters for the
|
||||
transaction
|
||||
"""
|
||||
if idTransaction == "":
|
||||
|
|
|
@ -25,8 +25,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from cotisations.models import Paiement
|
||||
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||
|
||||
from re2o.aes_field import AESEncryptedField
|
||||
|
||||
from .comnpay import Transaction
|
||||
|
||||
|
||||
|
@ -53,8 +53,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
|
|||
minimum_payment = models.DecimalField(
|
||||
verbose_name=_("minimum payment"),
|
||||
help_text=_(
|
||||
"The minimal amount of money you have to use when paying with"
|
||||
" ComNpay."
|
||||
"The minimal amount of money you have to use when paying with" " ComNpay."
|
||||
),
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
|
@ -107,8 +106,7 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
|
|||
return render(request, "cotisations/payment.html", r)
|
||||
|
||||
def check_price(self, price, *args, **kwargs):
|
||||
"""Checks that the price meets the requirement to be paid with ComNpay.
|
||||
"""
|
||||
"""Checks that the price meets the requirement to be paid with ComNpay."""
|
||||
return (
|
||||
(price >= self.minimum_payment),
|
||||
_(
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
@ -25,16 +25,17 @@ Here are the views needed by comnpay
|
|||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.datastructures import MultiValueDictKeyError
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from cotisations.models import Facture
|
||||
|
||||
from .comnpay import Transaction
|
||||
from .models import ComnpayPayment
|
||||
|
||||
|
@ -55,7 +56,10 @@ def accept_payment(request, factureid):
|
|||
)
|
||||
# In case a cotisation was bought, inform the user, the
|
||||
# cotisation time has been extended too
|
||||
if any(purchase.test_membership_or_connection() for purchase in invoice.vente_set.all()):
|
||||
if any(
|
||||
purchase.test_membership_or_connection()
|
||||
for purchase in invoice.vente_set.all()
|
||||
):
|
||||
messages.success(
|
||||
request,
|
||||
_(
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from . import PAYMENT_METHODS
|
||||
from cotisations.utils import find_payment_method
|
||||
|
||||
from . import PAYMENT_METHODS
|
||||
|
||||
|
||||
def payment_method_factory(payment, *args, creation=True, **kwargs):
|
||||
"""This function finds the right payment method form for a given payment.
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.contrib import messages
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
from cotisations.models import Paiement
|
||||
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||
|
@ -43,8 +42,7 @@ class FreePayment(PaymentMethodMixin, models.Model):
|
|||
)
|
||||
|
||||
def end_payment(self, invoice, request):
|
||||
"""Ends the payment normally.
|
||||
"""
|
||||
"""Ends the payment normally."""
|
||||
return invoice.paiement.end_payment(invoice, request, use_payment_method=False)
|
||||
|
||||
def check_price(self, price, user, *args, **kwargs):
|
||||
|
|
|
@ -19,17 +19,15 @@
|
|||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.contrib import messages
|
||||
from django.db import models
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
|
||||
from cotisations.models import Paiement
|
||||
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
|
||||
|
||||
class NotePayment(PaymentMethodMixin, models.Model):
|
||||
"""
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
""" Module pour dialoguer avec la NoteKfet2015 """
|
||||
|
||||
import socket
|
||||
import json
|
||||
import socket
|
||||
import ssl
|
||||
import traceback
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
@ -26,22 +26,23 @@ Here are the views needed by comnpay
|
|||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.datastructures import MultiValueDictKeyError
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from cotisations.models import Facture
|
||||
from cotisations.utils import find_payment_method
|
||||
from .models import NotePayment
|
||||
from re2o.views import form
|
||||
from re2o.acl import can_create, can_edit
|
||||
from .note import login, don
|
||||
from re2o.views import form
|
||||
|
||||
from .forms import NoteCredentialForm
|
||||
from .models import NotePayment
|
||||
from .note import don, login
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
from django.conf.urls import include, url
|
||||
from . import comnpay, cheque, note_kfet
|
||||
|
||||
from . import cheque, comnpay, note_kfet
|
||||
|
||||
urlpatterns = [
|
||||
url(r"^comnpay/", include((comnpay.urls, 'comnpay'), namespace="comnpay")),
|
||||
url(r"^cheque/", include((cheque.urls, 'cheque'), namespace="cheque")),
|
||||
url(r"^note_kfet/", include((note_kfet.urls, 'note_kfet'), namespace="note_kfet")),
|
||||
url(r"^comnpay/", include((comnpay.urls, "comnpay"), namespace="comnpay")),
|
||||
url(r"^cheque/", include((cheque.urls, "cheque"), namespace="cheque")),
|
||||
url(r"^note_kfet/", include((note_kfet.urls, "note_kfet"), namespace="note_kfet")),
|
||||
]
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from django.test import TestCase
|
||||
|
||||
import datetime
|
||||
from django.utils import timezone
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from users.models import User
|
||||
from .models import Vente, Facture, Cotisation, Paiement
|
||||
|
||||
from .models import Cotisation, Facture, Paiement, Vente
|
||||
|
||||
|
||||
class VenteModelTests(TestCase):
|
||||
|
@ -74,7 +75,7 @@ class VenteModelTests(TestCase):
|
|||
def test_one_month_and_one_week_cotisation(self):
|
||||
"""
|
||||
It should be possible to have one day membership.
|
||||
Add one mounth and one week of membership and one mounth
|
||||
Add one mounth and one week of membership and one mounth
|
||||
and one week of connection
|
||||
"""
|
||||
date = timezone.now()
|
||||
|
@ -111,12 +112,21 @@ class VenteModelTests(TestCase):
|
|||
duration_days_connection=1,
|
||||
duration_membership=0,
|
||||
duration_deys_membership=1,
|
||||
prix=0
|
||||
prix=0,
|
||||
)
|
||||
v.create_cotis(
|
||||
date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)),
|
||||
date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)),
|
||||
)
|
||||
v.create_cotis(date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)))
|
||||
v.save()
|
||||
self.assertEqual(v.cotisation.date_end_con, timezone.make_aware(datetime.datetime(1998, 10, 17)))
|
||||
self.assertEqual(v.cotisation.date_end_memb, timezone.make_aware(datetime.datetime(1998, 10, 17)))
|
||||
self.assertEqual(
|
||||
v.cotisation.date_end_con,
|
||||
timezone.make_aware(datetime.datetime(1998, 10, 17)),
|
||||
)
|
||||
self.assertEqual(
|
||||
v.cotisation.date_end_memb,
|
||||
timezone.make_aware(datetime.datetime(1998, 10, 17)),
|
||||
)
|
||||
|
||||
def test_one_day_cotisation_membership_only(self):
|
||||
"""
|
||||
|
@ -207,12 +217,21 @@ class VenteModelTests(TestCase):
|
|||
duration_days_connection=0,
|
||||
duration_membership=0,
|
||||
duration_days_membership=1,
|
||||
prix=0
|
||||
prix=0,
|
||||
)
|
||||
v.create_cotis(
|
||||
date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)),
|
||||
date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)),
|
||||
)
|
||||
v.create_cotis(date_start_con=timezone.make_aware(datetime.datetime(1998, 10, 16)), date_start_memb=timezone.make_aware(datetime.datetime(1998, 10, 16)))
|
||||
v.save()
|
||||
self.assertEqual(v.cotisation.date_end_con, timezone.make_aware(datetime.datetime(1998, 10, 17)))
|
||||
self.assertEqual(v.cotisation.date_end_memb, timezone.make_aware(datetime.datetime(1998, 10, 16)))
|
||||
self.assertEqual(
|
||||
v.cotisation.date_end_con,
|
||||
timezone.make_aware(datetime.datetime(1998, 10, 17)),
|
||||
)
|
||||
self.assertEqual(
|
||||
v.cotisation.date_end_memb,
|
||||
timezone.make_aware(datetime.datetime(1998, 10, 16)),
|
||||
)
|
||||
|
||||
def test_cotisation_membership_diff_connection(self):
|
||||
"""
|
||||
|
@ -252,9 +271,11 @@ class FactureModelTests(TestCase):
|
|||
def setUp(self):
|
||||
self.user = User.objects.create(pseudo="testUserPlop", email="test@example.org")
|
||||
self.paiement = Paiement.objects.create(moyen="test payment")
|
||||
|
||||
def tearDown(self):
|
||||
self.user.delete()
|
||||
self.paiement.delete()
|
||||
|
||||
def test_cotisations_prolongation(self):
|
||||
"""When user already have one valid cotisation, the new one should be
|
||||
added at the end of the existing one."""
|
||||
|
@ -300,4 +321,3 @@ class FactureModelTests(TestCase):
|
|||
raise e
|
||||
invoice1.delete()
|
||||
invoice2.delete()
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth.models import Permission
|
||||
|
||||
import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.utils import timezone
|
||||
|
||||
from users.models import Adherent
|
||||
from .models import Vente, Facture, Cotisation, Paiement, Article
|
||||
|
||||
from .models import Article, Cotisation, Facture, Paiement, Vente
|
||||
|
||||
|
||||
class NewFactureTests(TestCase):
|
||||
|
|
|
@ -26,20 +26,19 @@ Used to generated PDF invoice.
|
|||
"""
|
||||
|
||||
|
||||
import tempfile
|
||||
from subprocess import Popen, PIPE
|
||||
import os
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
from django.db import models
|
||||
from django.template.loader import get_template
|
||||
from django.http import HttpResponse
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.http import HttpResponse
|
||||
from django.template.loader import get_template
|
||||
from django.utils.text import slugify
|
||||
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
from preferences.models import CotisationsOption
|
||||
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
|
||||
TEMP_PREFIX = getattr(settings, "TEX_TEMP_PREFIX", "render_tex-")
|
||||
CACHE_PREFIX = getattr(settings, "TEX_CACHE_PREFIX", "render-tex")
|
||||
|
|
|
@ -27,23 +27,18 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.urls import path
|
||||
|
||||
from . import views, views_autocomplete
|
||||
from . import payment_methods
|
||||
from . import payment_methods, views, views_autocomplete
|
||||
|
||||
app_name ="cotisations"
|
||||
app_name = "cotisations"
|
||||
|
||||
urlpatterns = [
|
||||
path("new_facture/<int:userid>", views.new_facture, name="new-facture"),
|
||||
path(
|
||||
"edit_facture/<int:factureid>", views.edit_facture, name="edit-facture"
|
||||
),
|
||||
path("edit_facture/<int:factureid>", views.edit_facture, name="edit-facture"),
|
||||
path("del_facture/<int:factureid>", views.del_facture, name="del-facture"),
|
||||
path("facture_pdf/<int:factureid>", views.facture_pdf, name="facture-pdf"),
|
||||
path("voucher_pdf/<int:factureid>", views.voucher_pdf, name="voucher-pdf"),
|
||||
path("new_cost_estimate", views.new_cost_estimate, name="new-cost-estimate"),
|
||||
path(
|
||||
"index_cost_estimate", views.index_cost_estimate, name="index-cost-estimate"
|
||||
),
|
||||
path("index_cost_estimate", views.index_cost_estimate, name="index-cost-estimate"),
|
||||
path(
|
||||
"cost_estimate_pdf/<int:costestimateid>",
|
||||
views.cost_estimate_pdf,
|
||||
|
@ -87,9 +82,7 @@ urlpatterns = [
|
|||
),
|
||||
path("credit_solde/<int:userid>", views.credit_solde, name="credit-solde"),
|
||||
path("add_article", views.add_article, name="add-article"),
|
||||
path(
|
||||
"edit_article/<int:articleid>", views.edit_article, name="edit-article"
|
||||
),
|
||||
path("edit_article/<int:articleid>", views.edit_article, name="edit-article"),
|
||||
path("del_article", views.del_article, name="del-article"),
|
||||
path("add_paiement", views.add_paiement, name="add-paiement"),
|
||||
path(
|
||||
|
@ -107,5 +100,9 @@ urlpatterns = [
|
|||
path("control", views.control, name="control"),
|
||||
path("", views.index, name="index"),
|
||||
### Autocomplete Views
|
||||
path('banque-autocomplete', views_autocomplete.BanqueAutocomplete.as_view(), name='banque-autocomplete',),
|
||||
path(
|
||||
"banque-autocomplete",
|
||||
views_autocomplete.BanqueAutocomplete.as_view(),
|
||||
name="banque-autocomplete",
|
||||
),
|
||||
] + payment_methods.urls.urlpatterns
|
||||
|
|
|
@ -21,14 +21,16 @@
|
|||
|
||||
import os
|
||||
|
||||
from django.template.loader import get_template
|
||||
from django.core.mail import EmailMessage
|
||||
from django.template.loader import get_template
|
||||
|
||||
from preferences.models import (AssoOption, CotisationsOption, GeneralOption,
|
||||
Mandate)
|
||||
from re2o import settings
|
||||
from re2o.mail_utils import send_mail_object
|
||||
from re2o.settings import LOGO_PATH
|
||||
|
||||
from .tex import create_pdf
|
||||
from preferences.models import AssoOption, GeneralOption, CotisationsOption, Mandate
|
||||
from re2o.settings import LOGO_PATH
|
||||
from re2o import settings
|
||||
|
||||
|
||||
def find_payment_method(payment):
|
||||
|
@ -74,7 +76,9 @@ def send_mail_invoice(invoice, request=None):
|
|||
"tpl_path": os.path.join(settings.BASE_DIR, LOGO_PATH),
|
||||
}
|
||||
|
||||
template = CotisationsOption.get_cached_value("invoice_template").template.name.split("/")[-1]
|
||||
template = CotisationsOption.get_cached_value(
|
||||
"invoice_template"
|
||||
).template.name.split("/")[-1]
|
||||
pdf = create_pdf(template, ctx)
|
||||
template = get_template("cotisations/email_invoice")
|
||||
|
||||
|
@ -106,7 +110,9 @@ def send_mail_voucher(invoice, request=None):
|
|||
"email": invoice.user.email,
|
||||
"phone": invoice.user.telephone,
|
||||
"date_end": invoice.get_subscription().latest("date_end_memb").date_end_memb,
|
||||
"date_begin": invoice.get_subscription().earliest("date_start_memb").date_start_memb,
|
||||
"date_begin": invoice.get_subscription()
|
||||
.earliest("date_start_memb")
|
||||
.date_start_memb,
|
||||
}
|
||||
templatename = CotisationsOption.get_cached_value(
|
||||
"voucher_template"
|
||||
|
|
|
@ -29,62 +29,38 @@ The different views used in the Cotisations module
|
|||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.template.loader import render_to_string
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.db.models import ProtectedError
|
||||
from django.db.models import Q
|
||||
from django.forms import modelformset_factory, formset_factory
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import ProtectedError, Q
|
||||
from django.forms import formset_factory, modelformset_factory
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
# Import des models, forms et fonctions re2o
|
||||
from reversion import revisions as reversion
|
||||
from users.models import User
|
||||
from re2o.settings import LOGO_PATH
|
||||
from re2o import settings
|
||||
from re2o.views import form
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
from re2o.acl import (
|
||||
can_create,
|
||||
can_edit,
|
||||
can_delete,
|
||||
can_view,
|
||||
can_view_all,
|
||||
can_delete_set,
|
||||
can_change,
|
||||
)
|
||||
|
||||
from preferences.models import AssoOption, GeneralOption, Mandate
|
||||
from .models import (
|
||||
Facture,
|
||||
Article,
|
||||
Vente,
|
||||
Paiement,
|
||||
Banque,
|
||||
CustomInvoice,
|
||||
BaseInvoice,
|
||||
CostEstimate,
|
||||
)
|
||||
from .forms import (
|
||||
FactureForm,
|
||||
ArticleForm,
|
||||
DelArticleForm,
|
||||
PaiementForm,
|
||||
DelPaiementForm,
|
||||
BanqueForm,
|
||||
DelBanqueForm,
|
||||
SelectArticleForm,
|
||||
RechargeForm,
|
||||
CustomInvoiceForm,
|
||||
DiscountForm,
|
||||
CostEstimateForm,
|
||||
)
|
||||
from .tex import render_invoice, render_voucher, escape_chars
|
||||
from re2o import settings
|
||||
from re2o.acl import (can_change, can_create, can_delete, can_delete_set,
|
||||
can_edit, can_view, can_view_all)
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
from re2o.settings import LOGO_PATH
|
||||
from re2o.views import form
|
||||
from users.models import User
|
||||
|
||||
from .forms import (ArticleForm, BanqueForm, CostEstimateForm,
|
||||
CustomInvoiceForm, DelArticleForm, DelBanqueForm,
|
||||
DelPaiementForm, DiscountForm, FactureForm, PaiementForm,
|
||||
RechargeForm, SelectArticleForm)
|
||||
from .models import (Article, Banque, BaseInvoice, CostEstimate, CustomInvoice,
|
||||
Facture, Paiement, Vente)
|
||||
from .payment_methods.forms import payment_method_factory
|
||||
from .tex import escape_chars, render_invoice, render_voucher
|
||||
from .utils import find_payment_method
|
||||
|
||||
|
||||
|
@ -136,7 +112,7 @@ def new_facture(request, user, userid):
|
|||
duration_membership=article.duration_membership,
|
||||
duration_days_membership=article.duration_days_membership,
|
||||
number=quantity,
|
||||
)
|
||||
)
|
||||
purchases.append(new_purchase)
|
||||
p = find_payment_method(new_invoice_instance.paiement)
|
||||
if hasattr(p, "check_price"):
|
||||
|
@ -1057,12 +1033,15 @@ def voucher_pdf(request, invoice, **_kwargs):
|
|||
"lastname": invoice.user.surname,
|
||||
"email": invoice.user.email,
|
||||
"phone": invoice.user.telephone,
|
||||
"date_end": invoice.get_subscription().latest("date_end_memb").date_end_memb,
|
||||
"date_end": invoice.get_subscription()
|
||||
.latest("date_end_memb")
|
||||
.date_end_memb,
|
||||
"date_begin": invoice.date,
|
||||
},
|
||||
)
|
||||
|
||||
def aff_profil(request,user):
|
||||
|
||||
def aff_profil(request, user):
|
||||
"""View used to display the cotisations on a user's profil."""
|
||||
|
||||
factures = Facture.objects.filter(user=user)
|
||||
|
@ -1071,16 +1050,16 @@ def aff_profil(request,user):
|
|||
request.GET.get("col"),
|
||||
request.GET.get("order"),
|
||||
SortTable.COTISATIONS_INDEX,
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
pagination_large_number = GeneralOption.get_cached_value("pagination_large_number")
|
||||
factures = re2o_paginator(request, factures,pagination_large_number)
|
||||
factures = re2o_paginator(request, factures, pagination_large_number)
|
||||
|
||||
context = {
|
||||
"users":user,
|
||||
"users": user,
|
||||
"facture_list": factures,
|
||||
}
|
||||
}
|
||||
|
||||
return render_to_string(
|
||||
"cotisations/aff_profil.html",context=context,request=request,using=None
|
||||
)
|
||||
"cotisations/aff_profil.html", context=context, request=request, using=None
|
||||
)
|
||||
|
|
|
@ -31,20 +31,13 @@ Here are defined the autocomplete class based view.
|
|||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models import Q, Value, CharField
|
||||
|
||||
from .models import (
|
||||
Banque
|
||||
)
|
||||
from django.db.models import CharField, Q, Value
|
||||
|
||||
from re2o.acl import can_view_all
|
||||
from re2o.views import AutocompleteViewMixin
|
||||
|
||||
from re2o.acl import (
|
||||
can_view_all,
|
||||
)
|
||||
from .models import Banque
|
||||
|
||||
|
||||
class BanqueAutocomplete(AutocompleteViewMixin):
|
||||
obj_type = Banque
|
||||
|
||||
|
||||
|
|
|
@ -34,12 +34,12 @@ https://github.com/FreeRADIUS/freeradius-server/blob/master/src/modules/rlm_pyth
|
|||
Inspired by Daniel Stan in Crans
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
import radiusd # Magic module freeradius (radiusd.py is dummy)
|
||||
|
||||
import radiusd # Magic module freeradius (radiusd.py is dummy)
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.db.models import Q
|
||||
|
||||
|
@ -54,11 +54,10 @@ os.chdir(proj_path)
|
|||
# This is so models get loaded.
|
||||
application = get_wsgi_application()
|
||||
|
||||
from machines.models import Interface, IpList, Nas, Domain
|
||||
from machines.models import Domain, Interface, IpList, Nas
|
||||
from preferences.models import RadiusOption
|
||||
from topologie.models import Port, Switch
|
||||
from users.models import User
|
||||
from preferences.models import RadiusOption
|
||||
|
||||
|
||||
|
||||
# Logging
|
||||
|
@ -76,7 +75,7 @@ class RadiusdHandler(logging.Handler):
|
|||
radiusd.radlog(rad_sig, str(record.msg))
|
||||
|
||||
|
||||
# Init for logging
|
||||
# Init for logging
|
||||
logger = logging.getLogger("auth.py")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
|
||||
|
@ -132,10 +131,10 @@ def authorize(data):
|
|||
- If the nas is known, we apply the 802.1X if enabled,
|
||||
- It the nas is known AND nas auth is enabled with mac address, returns
|
||||
accept here"""
|
||||
# For proxified request, split
|
||||
# For proxified request, split
|
||||
nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None))
|
||||
nas_instance = find_nas_from_request(nas)
|
||||
# For none proxified requests
|
||||
# For none proxified requests
|
||||
nas_type = None
|
||||
if nas_instance:
|
||||
nas_type = Nas.objects.filter(nas_type=nas_instance.machine_type).first()
|
||||
|
@ -162,12 +161,11 @@ def authorize(data):
|
|||
|
||||
@radius_event
|
||||
def post_auth(data):
|
||||
""" Function called after the user is authenticated
|
||||
"""
|
||||
"""Function called after the user is authenticated"""
|
||||
|
||||
nas = data.get("NAS-IP-Address", data.get("NAS-Identifier", None))
|
||||
nas_instance = find_nas_from_request(nas)
|
||||
# All non proxified requests
|
||||
# All non proxified requests
|
||||
if not nas_instance:
|
||||
logger.info("Proxified request, nas unknown")
|
||||
return radiusd.RLM_MODULE_OK
|
||||
|
@ -309,7 +307,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address):
|
|||
- no room : Decision set in Re2o RadiusOption,
|
||||
- no user in this room : Reject,
|
||||
- user of this room is banned or disable : Reject,
|
||||
- user of this room non-contributor and not whitelisted:
|
||||
- user of this room non-contributor and not whitelisted:
|
||||
Decision set in Re2o RadiusOption
|
||||
- mode common :
|
||||
- mac-address already registered:
|
||||
|
@ -336,7 +334,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address):
|
|||
}
|
||||
# Get port from switch and port number
|
||||
extra_log = ""
|
||||
# If NAS is unknown, go to default vlan
|
||||
# If NAS is unknown, go to default vlan
|
||||
if not nas_machine:
|
||||
return (
|
||||
"?",
|
||||
|
@ -366,7 +364,7 @@ def decide_vlan_switch(nas_machine, nas_type, port_number, mac_address):
|
|||
RadiusOption.get_cached_value("unknown_port") != RadiusOption.REJECT,
|
||||
RadiusOption.get_attributes("unknown_port_attributes", attributes_kwargs),
|
||||
)
|
||||
|
||||
|
||||
# Retrieve port profile
|
||||
port_profile = port.get_port_profile
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import (
|
||||
LdapUser,
|
||||
LdapServiceUser,
|
||||
LdapServiceUserGroup,
|
||||
LdapUserGroup,
|
||||
)
|
||||
from .models import (LdapServiceUser, LdapServiceUserGroup, LdapUser,
|
||||
LdapUserGroup)
|
||||
|
||||
|
||||
class LdapUserAdmin(admin.ModelAdmin):
|
||||
"""LdapUser Admin view. Can't change password, manage
|
||||
|
@ -15,6 +12,7 @@ class LdapUserAdmin(admin.ModelAdmin):
|
|||
Django ModelAdmin: Apply on django ModelAdmin
|
||||
|
||||
"""
|
||||
|
||||
list_display = ("name", "uidNumber", "login_shell")
|
||||
exclude = ("user_password", "sambat_nt_password")
|
||||
search_fields = ("name",)
|
||||
|
|
|
@ -2,4 +2,4 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class LdapSyncConfig(AppConfig):
|
||||
name = 'ldap_sync'
|
||||
name = "ldap_sync"
|
||||
|
|
|
@ -18,11 +18,12 @@
|
|||
import subprocess
|
||||
from base64 import decodebytes
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from users.models import User, ListRight
|
||||
from ldap_sync.models import synchronise_user, synchronise_serviceuser, synchronise_usergroup
|
||||
from ldap_sync.models import (synchronise_serviceuser, synchronise_user,
|
||||
synchronise_usergroup)
|
||||
from users.models import ListRight, User
|
||||
|
||||
|
||||
def split_lines(lines):
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from users.models import User
|
||||
from ldap_sync.models import synchronise_user
|
||||
from users.models import User
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import sys
|
||||
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.dispatch import receiver
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
import ldapdb.models
|
||||
import ldapdb.models.fields
|
||||
|
||||
import users.signals
|
||||
import users.models
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import models
|
||||
from django.dispatch import receiver
|
||||
|
||||
import machines.models
|
||||
import users.models
|
||||
import users.signals
|
||||
|
||||
|
||||
class LdapUser(ldapdb.models.Model):
|
||||
"""A class representing a LdapUser in LDAP, its LDAP conterpart.
|
||||
|
@ -110,13 +108,13 @@ def synchronise_user(sender, **kwargs):
|
|||
* mac_refresh : Default `True`. When True, synchronise the list of mac addresses.
|
||||
* group_refresh: Default `False`. When `True` synchronise the groups of the instance.
|
||||
"""
|
||||
base=kwargs.get('base', True)
|
||||
access_refresh=kwargs.get('access_refresh', True)
|
||||
mac_refresh=kwargs.get('mac_refresh', True )
|
||||
group_refresh=kwargs.get('group_refresh', False)
|
||||
base = kwargs.get("base", True)
|
||||
access_refresh = kwargs.get("access_refresh", True)
|
||||
mac_refresh = kwargs.get("mac_refresh", True)
|
||||
group_refresh = kwargs.get("group_refresh", False)
|
||||
|
||||
user = kwargs["instance"]
|
||||
|
||||
user=kwargs["instance"]
|
||||
|
||||
if sys.version_info[0] >= 3 and (
|
||||
user.state == user.STATE_ACTIVE
|
||||
or user.state == user.STATE_ARCHIVE
|
||||
|
@ -136,9 +134,7 @@ def synchronise_user(sender, **kwargs):
|
|||
user_ldap.dialupAccess = str(user.has_access())
|
||||
user_ldap.home_directory = user.home_directory
|
||||
user_ldap.mail = user.get_mail
|
||||
user_ldap.given_name = (
|
||||
user.surname.lower() + "_" + user.name.lower()[:3]
|
||||
)
|
||||
user_ldap.given_name = user.surname.lower() + "_" + user.name.lower()[:3]
|
||||
user_ldap.gid = settings.LDAP["user_gid"]
|
||||
if "{SSHA}" in user.password or "{SMD5}" in user.password:
|
||||
# We remove the extra $ added at import from ldap
|
||||
|
@ -169,9 +165,12 @@ def synchronise_user(sender, **kwargs):
|
|||
# be part of the updated group (case of group removal)
|
||||
for group in Group.objects.all():
|
||||
if hasattr(group, "listright"):
|
||||
synchronise_usergroup(users.models.ListRight, instance=group.listright)
|
||||
synchronise_usergroup(
|
||||
users.models.ListRight, instance=group.listright
|
||||
)
|
||||
user_ldap.save()
|
||||
|
||||
|
||||
@receiver(users.signals.remove, sender=users.models.User)
|
||||
def remove_user(sender, **kwargs):
|
||||
user = kwargs["instance"]
|
||||
|
@ -181,6 +180,7 @@ def remove_user(sender, **kwargs):
|
|||
except LdapUser.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
||||
@receiver(users.signals.remove_mass, sender=users.models.User)
|
||||
def remove_users(sender, **kwargs):
|
||||
queryset_users = kwargs["queryset"]
|
||||
|
@ -217,6 +217,7 @@ class LdapUserGroup(ldapdb.models.Model):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
@receiver(users.signals.synchronise, sender=users.models.ListRight)
|
||||
def synchronise_usergroup(sender, **kwargs):
|
||||
group = kwargs["instance"]
|
||||
|
@ -228,6 +229,7 @@ def synchronise_usergroup(sender, **kwargs):
|
|||
group_ldap.members = [user.pseudo for user in group.user_set.all()]
|
||||
group_ldap.save()
|
||||
|
||||
|
||||
@receiver(users.signals.remove, sender=users.models.ListRight)
|
||||
def remove_usergroup(sender, **kwargs):
|
||||
group = kwargs["instance"]
|
||||
|
@ -238,7 +240,6 @@ def remove_usergroup(sender, **kwargs):
|
|||
pass
|
||||
|
||||
|
||||
|
||||
class LdapServiceUser(ldapdb.models.Model):
|
||||
"""A class representing a ServiceUser in LDAP, its LDAP conterpart.
|
||||
Synced from ServiceUser, with a copy of its attributes/fields into LDAP,
|
||||
|
@ -296,6 +297,7 @@ def synchronise_serviceuser(sender, **kwargs):
|
|||
user_ldap.save()
|
||||
synchronise_serviceuser_group(user)
|
||||
|
||||
|
||||
@receiver(users.signals.remove, sender=users.models.ServiceUser)
|
||||
def remove_serviceuser(sender, **kwargs):
|
||||
user = kwargs["instance"]
|
||||
|
@ -331,4 +333,3 @@ class LdapServiceUserGroup(ldapdb.models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.urls import path
|
||||
from .import views
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = "ldap_sync"
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class LogsConfig(AppConfig):
|
||||
"""Configuration of logs app."""
|
||||
|
||||
name = "logs"
|
||||
name = "logs"
|
||||
|
|
|
@ -21,13 +21,11 @@
|
|||
|
||||
"""The forms used by the machine search view"""
|
||||
|
||||
import inspect
|
||||
|
||||
from django import forms
|
||||
from django.forms import Form
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from re2o.base import get_input_formats_help_text
|
||||
from re2o.widgets import AutocompleteModelWidget
|
||||
|
||||
import inspect
|
||||
|
||||
# Import all models in which there are classes to be filtered on
|
||||
import cotisations.models
|
||||
|
@ -35,7 +33,8 @@ import machines.models
|
|||
import preferences.models
|
||||
import topologie.models
|
||||
import users.models
|
||||
|
||||
from re2o.base import get_input_formats_help_text
|
||||
from re2o.widgets import AutocompleteModelWidget
|
||||
|
||||
CHOICES_ACTION_TYPE = (
|
||||
("users", _("Users")),
|
||||
|
|
|
@ -21,23 +21,17 @@
|
|||
"""logs.models
|
||||
The models definitions for the logs app
|
||||
"""
|
||||
from reversion.models import Version, Revision
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.apps import apps
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models import Q
|
||||
from django.apps import apps
|
||||
from netaddr import EUI
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from macaddress.fields import default_dialect
|
||||
from netaddr import EUI
|
||||
from reversion.models import Revision, Version
|
||||
|
||||
from machines.models import IpList
|
||||
from machines.models import Interface
|
||||
from machines.models import Machine
|
||||
from machines.models import MachineType
|
||||
from users.models import User
|
||||
from users.models import Adherent
|
||||
from users.models import Club
|
||||
from topologie.models import Room
|
||||
from topologie.models import Port
|
||||
from machines.models import Interface, IpList, Machine, MachineType
|
||||
from topologie.models import Port, Room
|
||||
from users.models import Adherent, Club, User
|
||||
|
||||
from .forms import classes_for_action_type
|
||||
|
||||
|
@ -53,13 +47,12 @@ def make_version_filter(key, value):
|
|||
# The lookup is done in a json string, so it has to be formated
|
||||
# based on the value's type (to add " or not)
|
||||
if type(value) is str:
|
||||
formatted_value = "\"{}\"".format(value)
|
||||
formatted_value = '"{}"'.format(value)
|
||||
else:
|
||||
formatted_value = str(value)
|
||||
|
||||
return (
|
||||
Q(serialized_data__contains='\"{}\": {},'.format(key, formatted_value))
|
||||
| Q(serialized_data__contains='\"{}\": {}}}'.format(key, formatted_value))
|
||||
return Q(serialized_data__contains='"{}": {},'.format(key, formatted_value)) | Q(
|
||||
serialized_data__contains='"{}": {}}}'.format(key, formatted_value)
|
||||
)
|
||||
|
||||
|
||||
|
@ -67,6 +60,7 @@ def make_version_filter(key, value):
|
|||
# Machine history search #
|
||||
############################
|
||||
|
||||
|
||||
class MachineHistorySearchEvent:
|
||||
def __init__(self, user, machine, interface, start=None, end=None):
|
||||
"""Initialise an instance of MachineHistorySearchEvent.
|
||||
|
@ -113,7 +107,7 @@ class MachineHistorySearchEvent:
|
|||
self.ipv4,
|
||||
self.start_date,
|
||||
self.end_date,
|
||||
self.comment or "No comment"
|
||||
self.comment or "No comment",
|
||||
)
|
||||
|
||||
|
||||
|
@ -300,6 +294,7 @@ class MachineHistorySearch:
|
|||
# Generic history classes #
|
||||
############################
|
||||
|
||||
|
||||
class RelatedHistory:
|
||||
def __init__(self, version):
|
||||
"""Initialise an instance of RelatedHistory.
|
||||
|
@ -317,10 +312,7 @@ class RelatedHistory:
|
|||
self.name = "{}: {}".format(self.model_name.title(), self.name)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.model_name == other.model_name
|
||||
and self.object_id == other.object_id
|
||||
)
|
||||
return self.model_name == other.model_name and self.object_id == other.object_id
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.model_name, self.object_id))
|
||||
|
@ -382,15 +374,11 @@ class HistoryEvent:
|
|||
# Take into account keys that may exist in only one dict
|
||||
if field in self.previous_version.field_dict:
|
||||
old_value = self._repr(
|
||||
field,
|
||||
self.previous_version.field_dict[field]
|
||||
field, self.previous_version.field_dict[field]
|
||||
)
|
||||
|
||||
if field in self.version.field_dict:
|
||||
new_value = self._repr(
|
||||
field,
|
||||
self.version.field_dict[field]
|
||||
)
|
||||
new_value = self._repr(field, self.version.field_dict[field])
|
||||
|
||||
edits.append((field, old_value, new_value))
|
||||
|
||||
|
@ -487,6 +475,7 @@ class History:
|
|||
# Revision history #
|
||||
############################
|
||||
|
||||
|
||||
class VersionAction(HistoryEvent):
|
||||
def __init__(self, version):
|
||||
self.version = version
|
||||
|
@ -533,15 +522,14 @@ class VersionAction(HistoryEvent):
|
|||
"""
|
||||
model = self.object_type()
|
||||
try:
|
||||
query = (
|
||||
make_version_filter("pk", self.object_id())
|
||||
& Q(
|
||||
revision__date_created__lt=self.version.revision.date_created
|
||||
)
|
||||
query = make_version_filter("pk", self.object_id()) & Q(
|
||||
revision__date_created__lt=self.version.revision.date_created
|
||||
)
|
||||
return (
|
||||
Version.objects.get_for_model(model)
|
||||
.filter(query)
|
||||
.order_by("-revision__date_created")[0]
|
||||
)
|
||||
return (Version.objects.get_for_model(model)
|
||||
.filter(query)
|
||||
.order_by("-revision__date_created")[0])
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
@ -648,6 +636,7 @@ class ActionsSearch:
|
|||
# Class-specific history #
|
||||
############################
|
||||
|
||||
|
||||
class UserHistoryEvent(HistoryEvent):
|
||||
def _repr(self, name, value):
|
||||
"""Get the appropriate representation of the given field.
|
||||
|
@ -733,13 +722,15 @@ class UserHistoryEvent(HistoryEvent):
|
|||
)
|
||||
|
||||
def __hash__(self):
|
||||
return hash((frozenset(self.edited_fields), self.date, self.performed_by, self.comment))
|
||||
return hash(
|
||||
(frozenset(self.edited_fields), self.date, self.performed_by, self.comment)
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return "{} edited fields {} ({})".format(
|
||||
self.performed_by,
|
||||
self.edited_fields or "nothing",
|
||||
self.comment or "No comment"
|
||||
self.comment or "No comment",
|
||||
)
|
||||
|
||||
|
||||
|
@ -762,9 +753,8 @@ class UserHistory(History):
|
|||
|
||||
# Try to find an Adherent object
|
||||
# If it exists, its id will be the same as the user's
|
||||
adherents = (
|
||||
Version.objects.get_for_model(Adherent)
|
||||
.filter(make_version_filter("pk", user_id))
|
||||
adherents = Version.objects.get_for_model(Adherent).filter(
|
||||
make_version_filter("pk", user_id)
|
||||
)
|
||||
try:
|
||||
obj = adherents[0]
|
||||
|
@ -774,9 +764,8 @@ class UserHistory(History):
|
|||
|
||||
# Fallback on a Club
|
||||
if obj is None:
|
||||
clubs = (
|
||||
Version.objects.get_for_model(Club)
|
||||
.filter(make_version_filter("pk", user_id))
|
||||
clubs = Version.objects.get_for_model(Club).filter(
|
||||
make_version_filter("pk", user_id)
|
||||
)
|
||||
|
||||
try:
|
||||
|
@ -826,11 +815,7 @@ class UserHistory(History):
|
|||
|
||||
# Remove duplicates and sort
|
||||
self.events = list(dict.fromkeys(self.events))
|
||||
return sorted(
|
||||
self.events,
|
||||
key=lambda e: e.date,
|
||||
reverse=True
|
||||
)
|
||||
return sorted(self.events, key=lambda e: e.date, reverse=True)
|
||||
|
||||
def _add_revision(self, version):
|
||||
"""Add a new revision to the chronological order.
|
||||
|
@ -843,7 +828,7 @@ class UserHistory(History):
|
|||
diff = self._compute_diff(
|
||||
version,
|
||||
self._last_version,
|
||||
ignoring=["last_login", "pwd_ntlm", "email_change_date"]
|
||||
ignoring=["last_login", "pwd_ntlm", "email_change_date"],
|
||||
)
|
||||
|
||||
# Ignore "empty" events like login
|
||||
|
@ -973,7 +958,7 @@ HISTORY_CLASS_MAPPING = {
|
|||
User: UserHistory,
|
||||
Machine: MachineHistory,
|
||||
Interface: InterfaceHistory,
|
||||
"default": History
|
||||
"default": History,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,5 +47,9 @@ urlpatterns = [
|
|||
path("stats_models", views.stats_models, name="stats-models"),
|
||||
path("stats_users", views.stats_users, name="stats-users"),
|
||||
path("stats_actions", views.stats_actions, name="stats-actions"),
|
||||
path("stats_search_machine", views.stats_search_machine_history, name="stats-search-machine"),
|
||||
path(
|
||||
"stats_search_machine",
|
||||
views.stats_search_machine_history,
|
||||
name="stats-search-machine",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -38,84 +38,38 @@ objects for per model, number of actions per user etc.
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.apps import apps
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import Http404
|
||||
from django.db.models import Count
|
||||
from django.apps import apps
|
||||
from django.http import Http404
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from reversion.models import ContentType, Revision, Version
|
||||
|
||||
from reversion.models import Revision
|
||||
from reversion.models import Version, ContentType
|
||||
|
||||
from users.models import (
|
||||
User,
|
||||
ServiceUser,
|
||||
School,
|
||||
ListRight,
|
||||
ListShell,
|
||||
Ban,
|
||||
Whitelist,
|
||||
Adherent,
|
||||
Club,
|
||||
)
|
||||
from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation
|
||||
from machines.models import (
|
||||
Machine,
|
||||
MachineType,
|
||||
IpType,
|
||||
Extension,
|
||||
Interface,
|
||||
Domain,
|
||||
IpList,
|
||||
OuverturePortList,
|
||||
Service,
|
||||
Vlan,
|
||||
Nas,
|
||||
SOA,
|
||||
Mx,
|
||||
Ns,
|
||||
)
|
||||
from topologie.models import (
|
||||
Switch,
|
||||
Port,
|
||||
Room,
|
||||
Stack,
|
||||
ModelSwitch,
|
||||
ConstructorSwitch,
|
||||
AccessPoint,
|
||||
)
|
||||
from cotisations.models import (Article, Banque, Cotisation, Facture, Paiement,
|
||||
Vente)
|
||||
from machines.models import (SOA, Domain, Extension, Interface, IpList, IpType,
|
||||
Machine, MachineType, Mx, Nas, Ns,
|
||||
OuverturePortList, Service, Vlan)
|
||||
from preferences.models import GeneralOption
|
||||
from re2o.acl import (acl_error_message, can_edit_history, can_view,
|
||||
can_view_all, can_view_app)
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
from re2o.utils import (all_active_assigned_interfaces_count,
|
||||
all_active_interfaces_count, all_adherent, all_baned,
|
||||
all_has_access, all_whitelisted)
|
||||
from re2o.views import form
|
||||
from re2o.utils import (
|
||||
all_whitelisted,
|
||||
all_baned,
|
||||
all_has_access,
|
||||
all_adherent,
|
||||
all_active_assigned_interfaces_count,
|
||||
all_active_interfaces_count,
|
||||
)
|
||||
from re2o.base import re2o_paginator, SortTable
|
||||
from re2o.acl import (
|
||||
can_view_all,
|
||||
can_view_app,
|
||||
can_edit_history,
|
||||
can_view,
|
||||
acl_error_message,
|
||||
)
|
||||
|
||||
from .models import (
|
||||
ActionsSearch,
|
||||
RevisionAction,
|
||||
MachineHistorySearch,
|
||||
get_history_class,
|
||||
)
|
||||
|
||||
from .forms import ActionsSearchForm, MachineHistorySearchForm
|
||||
from topologie.models import (AccessPoint, ConstructorSwitch, ModelSwitch,
|
||||
Port, Room, Stack, Switch)
|
||||
from users.models import (Adherent, Ban, Club, ListRight, ListShell, School,
|
||||
ServiceUser, User, Whitelist)
|
||||
|
||||
from .acl import can_view as can_view_logs
|
||||
from .forms import ActionsSearchForm, MachineHistorySearchForm
|
||||
from .models import (ActionsSearch, MachineHistorySearch, RevisionAction,
|
||||
get_history_class)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -528,7 +482,11 @@ def stats_search_machine_history(request):
|
|||
max_result = GeneralOption.get_cached_value("pagination_number")
|
||||
events = re2o_paginator(request, events, max_result)
|
||||
|
||||
return render(request, "logs/machine_history.html", {"events": events},)
|
||||
return render(
|
||||
request,
|
||||
"logs/machine_history.html",
|
||||
{"events": events},
|
||||
)
|
||||
return render(
|
||||
request, "logs/search_machine_history.html", {"history_form": history_form}
|
||||
)
|
||||
|
|
|
@ -29,24 +29,10 @@ from __future__ import unicode_literals
|
|||
from django.contrib import admin
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
from .models import (
|
||||
Extension,
|
||||
SOA,
|
||||
Mx,
|
||||
Ns,
|
||||
Vlan,
|
||||
Txt,
|
||||
DName,
|
||||
Srv,
|
||||
SshFp,
|
||||
Nas,
|
||||
Service,
|
||||
Role,
|
||||
OuverturePort,
|
||||
Ipv6List,
|
||||
OuverturePortList,
|
||||
)
|
||||
from .models import IpType, Machine, MachineType, Domain, IpList, Interface
|
||||
from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType,
|
||||
Ipv6List, Machine, MachineType, Mx, Nas, Ns,
|
||||
OuverturePort, OuverturePortList, Role, Service, Srv,
|
||||
SshFp, Txt, Vlan)
|
||||
|
||||
|
||||
class MachineAdmin(VersionAdmin):
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
import machines.models as machines
|
||||
from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer
|
||||
from api.serializers import (NamespacedHIField, NamespacedHMSerializer,
|
||||
NamespacedHRField)
|
||||
|
||||
|
||||
class MachineSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Machine` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Machine` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Machine
|
||||
|
@ -35,8 +35,7 @@ class MachineSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class MachineTypeSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.MachineType` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.MachineType` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.MachineType
|
||||
|
@ -44,8 +43,7 @@ class MachineTypeSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class IpTypeSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.IpType` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.IpType` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.IpType
|
||||
|
@ -63,8 +61,7 @@ class IpTypeSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class VlanSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Vlan` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Vlan` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Vlan
|
||||
|
@ -82,8 +79,7 @@ class VlanSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class NasSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Nas` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Nas` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Nas
|
||||
|
@ -98,8 +94,7 @@ class NasSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class SOASerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.SOA` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.SOA` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.SOA
|
||||
|
@ -107,8 +102,7 @@ class SOASerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ExtensionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize machines.models.Extension objects.
|
||||
"""
|
||||
"""Serialize machines.models.Extension objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Extension
|
||||
|
@ -116,8 +110,7 @@ class ExtensionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class MxSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Mx` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Mx` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Mx
|
||||
|
@ -125,8 +118,7 @@ class MxSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class DNameSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.DName` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.DName` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.DName
|
||||
|
@ -134,8 +126,7 @@ class DNameSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class NsSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Ns` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Ns` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Ns
|
||||
|
@ -143,8 +134,7 @@ class NsSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class TxtSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Txt` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Txt` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Txt
|
||||
|
@ -152,8 +142,7 @@ class TxtSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class SrvSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Srv` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Srv` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Srv
|
||||
|
@ -171,8 +160,7 @@ class SrvSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class SshFpSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.SSHFP` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.SSHFP` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.SshFp
|
||||
|
@ -180,8 +168,7 @@ class SshFpSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class InterfaceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Interface` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Interface` objects."""
|
||||
|
||||
mac_address = serializers.CharField()
|
||||
active = serializers.BooleanField(source="is_active")
|
||||
|
@ -201,8 +188,7 @@ class InterfaceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class Ipv6ListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Ipv6List` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Ipv6List
|
||||
|
@ -210,8 +196,7 @@ class Ipv6ListSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class DomainSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Domain` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Domain` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Domain
|
||||
|
@ -219,8 +204,7 @@ class DomainSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class IpListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.IpList` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.IpList` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.IpList
|
||||
|
@ -228,8 +212,7 @@ class IpListSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Service` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Service` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Service
|
||||
|
@ -243,8 +226,7 @@ class ServiceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceLinkSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.Service_link` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.Service_link` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.Service_link
|
||||
|
@ -260,8 +242,7 @@ class ServiceLinkSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OuverturePortListSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePortList` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.OuverturePortList` objects."""
|
||||
|
||||
tcp_ports_in = NamespacedHRField(
|
||||
view_name="ouvertureport-detail", many=True, read_only=True
|
||||
|
@ -289,8 +270,7 @@ class OuverturePortListSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OuverturePortSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.OuverturePort` objects."""
|
||||
|
||||
class Meta:
|
||||
model = machines.OuverturePort
|
||||
|
@ -298,8 +278,7 @@ class OuverturePortSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class RoleSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
"""Serialize `machines.models.OuverturePort` objects."""
|
||||
|
||||
servers = InterfaceSerializer(read_only=True, many=True)
|
||||
|
||||
|
@ -309,8 +288,7 @@ class RoleSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class ServiceRegenSerializer(NamespacedHMSerializer):
|
||||
"""Serialize the data about the services to regen.
|
||||
"""
|
||||
"""Serialize the data about the services to regen."""
|
||||
|
||||
hostname = serializers.CharField(source="server.domain.name", read_only=True)
|
||||
service_name = serializers.CharField(source="service.service_type", read_only=True)
|
||||
|
@ -517,8 +495,7 @@ class DNAMERecordSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class DNSZonesSerializer(serializers.ModelSerializer):
|
||||
"""Serialize the data about DNS Zones.
|
||||
"""
|
||||
"""Serialize the data about DNS Zones."""
|
||||
|
||||
soa = SOARecordSerializer()
|
||||
ns_records = NSRecordSerializer(many=True, source="ns_set")
|
||||
|
@ -559,8 +536,7 @@ class DNSZonesSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class DNSReverseZonesSerializer(serializers.ModelSerializer):
|
||||
"""Serialize the data about DNS Zones.
|
||||
"""
|
||||
"""Serialize the data about DNS Zones."""
|
||||
|
||||
soa = SOARecordSerializer(source="extension.soa")
|
||||
extension = serializers.CharField(source="extension.name", read_only=True)
|
||||
|
|
|
@ -45,9 +45,8 @@ urls_viewset = [
|
|||
(r"machines/ouvertureport", views.OuverturePortViewSet, None),
|
||||
(r"machines/role", views.RoleViewSet, None),
|
||||
(r"machines/services-regen", views.ServiceRegenViewSet, "serviceregen"),
|
||||
|
||||
# Deprecated
|
||||
(r"services/regen", views.ServiceRegenViewSet, "serviceregen")
|
||||
(r"services/regen", views.ServiceRegenViewSet, "serviceregen"),
|
||||
]
|
||||
|
||||
urls_view = [
|
||||
|
@ -56,11 +55,10 @@ urls_view = [
|
|||
(r"machines/firewall-interface-ports", views.InterfacePortsOpenView),
|
||||
(r"machines/dns-zones", views.DNSZonesView),
|
||||
(r"machines/dns-reverse-zones", views.DNSReverseZonesView),
|
||||
|
||||
# Deprecated
|
||||
(r"dhcp/hostmacip", views.HostMacIpView),
|
||||
(r"firewall/subnet-ports", views.SubnetPortsOpenView),
|
||||
(r"firewall/interface-ports", views.InterfacePortsOpenView),
|
||||
(r"dns/zones", views.DNSZonesView),
|
||||
(r"dns/reverse-zones", views.DNSReverseZonesView),
|
||||
]
|
||||
]
|
||||
|
|
|
@ -19,159 +19,142 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from rest_framework import viewsets, generics
|
||||
from rest_framework import generics, viewsets
|
||||
|
||||
from . import serializers
|
||||
import machines.models as machines
|
||||
from re2o.utils import all_active_interfaces
|
||||
|
||||
from . import serializers
|
||||
|
||||
|
||||
class MachineViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Machine` objects."""
|
||||
|
||||
queryset = machines.Machine.objects.all()
|
||||
serializer_class = serializers.MachineSerializer
|
||||
|
||||
|
||||
class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.MachineType` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.MachineType` objects."""
|
||||
|
||||
queryset = machines.MachineType.objects.all()
|
||||
serializer_class = serializers.MachineTypeSerializer
|
||||
|
||||
|
||||
class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpType` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.IpType` objects."""
|
||||
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.IpTypeSerializer
|
||||
|
||||
|
||||
class VlanViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Vlan` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Vlan` objects."""
|
||||
|
||||
queryset = machines.Vlan.objects.all()
|
||||
serializer_class = serializers.VlanSerializer
|
||||
|
||||
|
||||
class NasViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Nas` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Nas` objects."""
|
||||
|
||||
queryset = machines.Nas.objects.all()
|
||||
serializer_class = serializers.NasSerializer
|
||||
|
||||
|
||||
class SOAViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.SOA` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.SOA` objects."""
|
||||
|
||||
queryset = machines.SOA.objects.all()
|
||||
serializer_class = serializers.SOASerializer
|
||||
|
||||
|
||||
class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Extension` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Extension` objects."""
|
||||
|
||||
queryset = machines.Extension.objects.all()
|
||||
serializer_class = serializers.ExtensionSerializer
|
||||
|
||||
|
||||
class MxViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Mx` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Mx` objects."""
|
||||
|
||||
queryset = machines.Mx.objects.all()
|
||||
serializer_class = serializers.MxSerializer
|
||||
|
||||
|
||||
class NsViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ns` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Ns` objects."""
|
||||
|
||||
queryset = machines.Ns.objects.all()
|
||||
serializer_class = serializers.NsSerializer
|
||||
|
||||
|
||||
class TxtViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Txt` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Txt` objects."""
|
||||
|
||||
queryset = machines.Txt.objects.all()
|
||||
serializer_class = serializers.TxtSerializer
|
||||
|
||||
|
||||
class DNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.DName` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.DName` objects."""
|
||||
|
||||
queryset = machines.DName.objects.all()
|
||||
serializer_class = serializers.DNameSerializer
|
||||
|
||||
|
||||
class SrvViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Srv` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Srv` objects."""
|
||||
|
||||
queryset = machines.Srv.objects.all()
|
||||
serializer_class = serializers.SrvSerializer
|
||||
|
||||
|
||||
class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.SshFp` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.SshFp` objects."""
|
||||
|
||||
queryset = machines.SshFp.objects.all()
|
||||
serializer_class = serializers.SshFpSerializer
|
||||
|
||||
|
||||
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Interface` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Interface` objects."""
|
||||
|
||||
queryset = machines.Interface.objects.all()
|
||||
serializer_class = serializers.InterfaceSerializer
|
||||
|
||||
|
||||
class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Ipv6List` objects."""
|
||||
|
||||
queryset = machines.Ipv6List.objects.all()
|
||||
serializer_class = serializers.Ipv6ListSerializer
|
||||
|
||||
|
||||
class DomainViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Domain` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Domain` objects."""
|
||||
|
||||
queryset = machines.Domain.objects.all()
|
||||
serializer_class = serializers.DomainSerializer
|
||||
|
||||
|
||||
class IpListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpList` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.IpList` objects."""
|
||||
|
||||
queryset = machines.IpList.objects.all()
|
||||
serializer_class = serializers.IpListSerializer
|
||||
|
||||
|
||||
class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Service` objects."""
|
||||
|
||||
queryset = machines.Service.objects.all()
|
||||
serializer_class = serializers.ServiceSerializer
|
||||
|
||||
|
||||
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service_link` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Service_link` objects."""
|
||||
|
||||
queryset = machines.Service_link.objects.all()
|
||||
serializer_class = serializers.ServiceLinkSerializer
|
||||
|
@ -187,24 +170,21 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
|
||||
|
||||
class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.OuverturePort` objects."""
|
||||
|
||||
queryset = machines.OuverturePort.objects.all()
|
||||
serializer_class = serializers.OuverturePortSerializer
|
||||
|
||||
|
||||
class RoleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
"""Exposes list and details of `machines.models.Machine` objects."""
|
||||
|
||||
queryset = machines.Role.objects.all()
|
||||
serializer_class = serializers.RoleSerializer
|
||||
|
||||
|
||||
class ServiceRegenViewSet(viewsets.ModelViewSet):
|
||||
"""Exposes list and details of the services to regen
|
||||
"""
|
||||
"""Exposes list and details of the services to regen"""
|
||||
|
||||
serializer_class = serializers.ServiceRegenSerializer
|
||||
|
||||
|
@ -238,6 +218,7 @@ class InterfacePortsOpenView(generics.ListAPIView):
|
|||
queryset = machines.Interface.objects.filter(port_lists__isnull=False).distinct()
|
||||
serializer_class = serializers.InterfacePortsOpenSerializer
|
||||
|
||||
|
||||
class DNSZonesView(generics.ListAPIView):
|
||||
"""Exposes the detailed information about each extension (hostnames,
|
||||
IPs, DNS records, etc.) in order to build the DNS zone files.
|
||||
|
@ -264,4 +245,4 @@ class DNSReverseZonesView(generics.ListAPIView):
|
|||
"""
|
||||
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.DNSReverseZonesSerializer
|
||||
serializer_class = serializers.DNSReverseZonesSerializer
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class MachinesConfig(AppConfig):
|
||||
"""Configuration of machines app."""
|
||||
|
||||
name = "machines"
|
||||
name = "machines"
|
||||
|
|
|
@ -36,37 +36,17 @@ Forms to create, edit and delete:
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.forms import ModelForm, Form
|
||||
from django.forms import Form, ModelForm
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.field_permissions import FieldPermissionFormMixin
|
||||
from re2o.mixins import FormRevMixin
|
||||
from re2o.widgets import (
|
||||
AutocompleteModelWidget,
|
||||
AutocompleteMultipleModelWidget,
|
||||
)
|
||||
from .models import (
|
||||
Domain,
|
||||
Machine,
|
||||
Interface,
|
||||
IpList,
|
||||
MachineType,
|
||||
Extension,
|
||||
SOA,
|
||||
Mx,
|
||||
Txt,
|
||||
DName,
|
||||
Ns,
|
||||
Role,
|
||||
Service,
|
||||
Vlan,
|
||||
Srv,
|
||||
SshFp,
|
||||
Nas,
|
||||
IpType,
|
||||
OuverturePortList,
|
||||
Ipv6List,
|
||||
)
|
||||
from re2o.widgets import (AutocompleteModelWidget,
|
||||
AutocompleteMultipleModelWidget)
|
||||
|
||||
from .models import (SOA, DName, Domain, Extension, Interface, IpList, IpType,
|
||||
Ipv6List, Machine, MachineType, Mx, Nas, Ns,
|
||||
OuverturePortList, Role, Service, Srv, SshFp, Txt, Vlan)
|
||||
|
||||
|
||||
class EditMachineForm(FormRevMixin, FieldPermissionFormMixin, ModelForm):
|
||||
|
@ -248,7 +228,9 @@ class IpTypeForm(FormRevMixin, ModelForm):
|
|||
fields = "__all__"
|
||||
widgets = {
|
||||
"vlan": AutocompleteModelWidget(url="/machines/vlan-autocomplete"),
|
||||
"extension": AutocompleteModelWidget(url="/machines/extension-autocomplete"),
|
||||
"extension": AutocompleteModelWidget(
|
||||
url="/machines/extension-autocomplete"
|
||||
),
|
||||
"ouverture_ports": AutocompleteModelWidget(
|
||||
url="/machines/ouvertureportlist-autocomplete"
|
||||
),
|
||||
|
@ -525,7 +507,9 @@ class SrvForm(FormRevMixin, ModelForm):
|
|||
model = Srv
|
||||
fields = "__all__"
|
||||
widgets = {
|
||||
"extension": AutocompleteModelWidget(url="/machines/extension-autocomplete"),
|
||||
"extension": AutocompleteModelWidget(
|
||||
url="/machines/extension-autocomplete"
|
||||
),
|
||||
"target": AutocompleteModelWidget(url="/machines/domain-autocomplete"),
|
||||
}
|
||||
|
||||
|
|
|
@ -35,26 +35,18 @@ from ipaddress import IPv6Address
|
|||
from itertools import chain
|
||||
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Q
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.dispatch import receiver
|
||||
from django.forms import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from reversion import revisions as reversion
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from macaddress.fields import MACAddressField, default_dialect
|
||||
from netaddr import (
|
||||
mac_bare,
|
||||
EUI,
|
||||
NotRegisteredError,
|
||||
IPSet,
|
||||
IPRange,
|
||||
IPNetwork,
|
||||
IPAddress,
|
||||
)
|
||||
from netaddr import (EUI, IPAddress, IPNetwork, IPRange, IPSet,
|
||||
NotRegisteredError, mac_bare)
|
||||
from reversion import revisions as reversion
|
||||
|
||||
import preferences.models
|
||||
import users.models
|
||||
|
@ -79,9 +71,7 @@ class Machine(RevMixin, FieldPermissionModelMixin, AclMixin, models.Model):
|
|||
active = models.BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("change_machine_user", _("Can change the user of a machine")),
|
||||
)
|
||||
permissions = (("change_machine_user", _("Can change the user of a machine")),)
|
||||
verbose_name = _("machine")
|
||||
verbose_name_plural = _("machines")
|
||||
|
||||
|
@ -342,9 +332,7 @@ class MachineType(RevMixin, AclMixin, models.Model):
|
|||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("use_all_machinetype", _("Can use all machine types")),
|
||||
)
|
||||
permissions = (("use_all_machinetype", _("Can use all machine types")),)
|
||||
verbose_name = _("machine type")
|
||||
verbose_name_plural = _("machine types")
|
||||
|
||||
|
@ -356,7 +344,9 @@ class MachineType(RevMixin, AclMixin, models.Model):
|
|||
"""Update domains extension with the extension of interface_parent. Called after update of an ip_type or a machine_type object. Exceptions are handled in the views.
|
||||
(Calling domain.clear() for all domains could take several minutes)
|
||||
"""
|
||||
Domain.objects.filter(interface_parent__machine_type=self).update(extension=self.ip_type.extension)
|
||||
Domain.objects.filter(interface_parent__machine_type=self).update(
|
||||
extension=self.ip_type.extension
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def can_use_all(user_request, *_args, **_kwargs):
|
||||
|
@ -379,7 +369,7 @@ class MachineType(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@classmethod
|
||||
def can_list(cls, user_request, *_args, **_kwargs):
|
||||
"""All users can list unprivileged machinetypes
|
||||
"""All users can list unprivileged machinetypes
|
||||
Only members of privileged groups can list all.
|
||||
|
||||
:param user_request: The user who wants to view the list.
|
||||
|
@ -389,20 +379,13 @@ class MachineType(RevMixin, AclMixin, models.Model):
|
|||
"""
|
||||
can, _message, _group = cls.can_use_all(user_request)
|
||||
if can:
|
||||
return (
|
||||
True,
|
||||
None,
|
||||
None,
|
||||
cls.objects.all()
|
||||
)
|
||||
return (True, None, None, cls.objects.all())
|
||||
else:
|
||||
return (
|
||||
True,
|
||||
_("You don't have the right to use all machine types."),
|
||||
("machines.use_all_machinetype",),
|
||||
cls.objects.filter(
|
||||
ip_type__in=IpType.objects.filter(need_infra=False)
|
||||
),
|
||||
cls.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -455,12 +438,12 @@ class IpType(RevMixin, AclMixin, models.Model):
|
|||
default=False, help_text=_("Enable reverse DNS for IPv6.")
|
||||
)
|
||||
vlan = models.ForeignKey("Vlan", on_delete=models.PROTECT, blank=True, null=True)
|
||||
ouverture_ports = models.ForeignKey("OuverturePortList", blank=True, null=True, on_delete=models.PROTECT)
|
||||
ouverture_ports = models.ForeignKey(
|
||||
"OuverturePortList", blank=True, null=True, on_delete=models.PROTECT
|
||||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("use_all_iptype", _("Can use all IP types")),
|
||||
)
|
||||
permissions = (("use_all_iptype", _("Can use all IP types")),)
|
||||
verbose_name = _("IP type")
|
||||
verbose_name_plural = _("IP types")
|
||||
|
||||
|
@ -897,9 +880,7 @@ class Extension(RevMixin, AclMixin, models.Model):
|
|||
)
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
("use_all_extension", _("Can use all extensions")),
|
||||
)
|
||||
permissions = (("use_all_extension", _("Can use all extensions")),)
|
||||
verbose_name = _("DNS extension")
|
||||
verbose_name_plural = _("DNS extensions")
|
||||
|
||||
|
@ -977,7 +958,7 @@ class Extension(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@classmethod
|
||||
def can_list(cls, user_request, *_args, **_kwargs):
|
||||
"""All users can list unprivileged extensions
|
||||
"""All users can list unprivileged extensions
|
||||
Only members of privileged groups can list all.
|
||||
|
||||
:param user_request: The user who wants to view the list.
|
||||
|
@ -987,12 +968,7 @@ class Extension(RevMixin, AclMixin, models.Model):
|
|||
"""
|
||||
can, _message, _group = cls.can_use_all(user_request)
|
||||
if can:
|
||||
return (
|
||||
True,
|
||||
None,
|
||||
None,
|
||||
cls.objects.all()
|
||||
)
|
||||
return (True, None, None, cls.objects.all())
|
||||
else:
|
||||
return (
|
||||
True,
|
||||
|
@ -1035,8 +1011,7 @@ class Mx(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Get the complete DNS entry of the MX record, to put in zone files.
|
||||
"""
|
||||
"""Get the complete DNS entry of the MX record, to put in zone files."""
|
||||
return "@ IN MX {prior} {name}".format(
|
||||
prior=str(self.priority).ljust(3), name=str(self.name)
|
||||
)
|
||||
|
@ -1066,8 +1041,7 @@ class Ns(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Get the complete DNS entry of the NS record, to put in zone files.
|
||||
"""
|
||||
"""Get the complete DNS entry of the NS record, to put in zone files."""
|
||||
return "@ IN NS " + str(self.ns)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -1100,8 +1074,7 @@ class Txt(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Get the complete DNS entry of the TXT record, to put in zone files.
|
||||
"""
|
||||
"""Get the complete DNS entry of the TXT record, to put in zone files."""
|
||||
return str(self.field1).ljust(15) + " IN TXT " + str(self.field2)
|
||||
|
||||
|
||||
|
@ -1129,8 +1102,7 @@ class DName(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Get the complete DNS entry of the TXT record, to put in zone files.
|
||||
"""
|
||||
"""Get the complete DNS entry of the TXT record, to put in zone files."""
|
||||
return str(self.alias).ljust(15) + " IN DNAME " + str(self.zone)
|
||||
|
||||
|
||||
|
@ -1204,8 +1176,7 @@ class Srv(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def dns_entry(self):
|
||||
"""Get the complete DNS entry of the SRV record, to put in zone files.
|
||||
"""
|
||||
"""Get the complete DNS entry of the SRV record, to put in zone files."""
|
||||
return (
|
||||
str(self.service)
|
||||
+ "._"
|
||||
|
@ -1387,8 +1358,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
return vendor
|
||||
|
||||
def sync_ipv6_dhcpv6(self):
|
||||
"""Assign an IPv6 address by DHCPv6, computed from the interface's ID.
|
||||
"""
|
||||
"""Assign an IPv6 address by DHCPv6, computed from the interface's ID."""
|
||||
ipv6_dhcpv6 = self.gen_ipv6_dhcpv6
|
||||
if not ipv6_dhcpv6:
|
||||
return
|
||||
|
@ -1414,8 +1384,7 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
ipv6_object.save()
|
||||
|
||||
def sync_ipv6(self):
|
||||
"""Create and update the IPv6 addresses according to the IPv6 mode set.
|
||||
"""
|
||||
"""Create and update the IPv6 addresses according to the IPv6 mode set."""
|
||||
if preferences.models.OptionalMachine.get_cached_value("ipv6_mode") == "SLAAC":
|
||||
self.sync_ipv6_slaac()
|
||||
elif (
|
||||
|
@ -1581,8 +1550,10 @@ class Interface(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
_("You don't have the right to add a machine."),
|
||||
("machines.add_interface",),
|
||||
)
|
||||
max_lambdauser_interfaces = preferences.models.OptionalMachine.get_cached_value(
|
||||
"max_lambdauser_interfaces"
|
||||
max_lambdauser_interfaces = (
|
||||
preferences.models.OptionalMachine.get_cached_value(
|
||||
"max_lambdauser_interfaces"
|
||||
)
|
||||
)
|
||||
if machine.user != user_request:
|
||||
return (
|
||||
|
@ -1721,8 +1692,7 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
)
|
||||
slaac_ip = models.BooleanField(default=False)
|
||||
active = models.BooleanField(
|
||||
default=True,
|
||||
help_text=_("If false,the DNS will not provide this ip.")
|
||||
default=True, help_text=_("If false,the DNS will not provide this ip.")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
@ -1856,8 +1826,9 @@ class Ipv6List(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
|
||||
def check_and_replace_prefix(self, prefix=None):
|
||||
"""Check if the IPv6 prefix is correct and update it if not."""
|
||||
prefix_v6 = prefix or self.interface.machine_type.ip_type.prefix_v6.encode().decode(
|
||||
"utf-8"
|
||||
prefix_v6 = (
|
||||
prefix
|
||||
or self.interface.machine_type.ip_type.prefix_v6.encode().decode("utf-8")
|
||||
)
|
||||
if not prefix_v6:
|
||||
return
|
||||
|
@ -1930,7 +1901,11 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
)
|
||||
extension = models.ForeignKey("Extension", on_delete=models.PROTECT)
|
||||
cname = models.ForeignKey(
|
||||
"self", null=True, blank=True, related_name="related_domain", on_delete=models.PROTECT
|
||||
"self",
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="related_domain",
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
ttl = models.PositiveIntegerField(
|
||||
verbose_name=_("Time To Live (TTL)"),
|
||||
|
@ -1940,9 +1915,7 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
|
||||
class Meta:
|
||||
unique_together = (("name", "extension"),)
|
||||
permissions = (
|
||||
("change_ttl", _("Can change the TTL of a domain object")),
|
||||
)
|
||||
permissions = (("change_ttl", _("Can change the TTL of a domain object")),)
|
||||
verbose_name = _("domain")
|
||||
verbose_name_plural = _("domains")
|
||||
|
||||
|
@ -2037,8 +2010,10 @@ class Domain(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
|
|||
except Interface.DoesNotExist:
|
||||
return False, _("Nonexistent interface."), None
|
||||
if not user_request.has_perm("machines.add_domain"):
|
||||
max_lambdauser_aliases = preferences.models.OptionalMachine.get_cached_value(
|
||||
"max_lambdauser_aliases"
|
||||
max_lambdauser_aliases = (
|
||||
preferences.models.OptionalMachine.get_cached_value(
|
||||
"max_lambdauser_aliases"
|
||||
)
|
||||
)
|
||||
if interface.machine.user != user_request:
|
||||
return (
|
||||
|
@ -2173,8 +2148,7 @@ class IpList(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@cached_property
|
||||
def need_infra(self):
|
||||
"""Check if the 'infra' right is required to assign this IP address.
|
||||
"""
|
||||
"""Check if the 'infra' right is required to assign this IP address."""
|
||||
return self.ip_type.need_infra
|
||||
|
||||
def clean(self):
|
||||
|
@ -2206,20 +2180,13 @@ class IpList(RevMixin, AclMixin, models.Model):
|
|||
"""
|
||||
can, _message, _group = IpType.can_use_all(user_request)
|
||||
if can:
|
||||
return (
|
||||
True,
|
||||
None,
|
||||
None,
|
||||
cls.objects.all()
|
||||
)
|
||||
return (True, None, None, cls.objects.all())
|
||||
else:
|
||||
return (
|
||||
True,
|
||||
_("You don't have the right to use all machine types."),
|
||||
("machines.use_all_machinetype",),
|
||||
cls.objects.filter(
|
||||
ip_type__in=IpType.objects.filter(need_infra=False)
|
||||
),
|
||||
cls.objects.filter(ip_type__in=IpType.objects.filter(need_infra=False)),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -2517,7 +2484,13 @@ class OuverturePort(RevMixin, AclMixin, models.Model):
|
|||
def machine_post_save(**kwargs):
|
||||
"""Synchronise LDAP and regen firewall/DHCP after a machine is edited."""
|
||||
user = kwargs["instance"].user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=False,
|
||||
mac_refresh=True,
|
||||
)
|
||||
regen("dhcp")
|
||||
regen("mac_ip_list")
|
||||
|
||||
|
@ -2527,7 +2500,13 @@ def machine_post_delete(**kwargs):
|
|||
"""Synchronise LDAP and regen firewall/DHCP after a machine is deleted."""
|
||||
machine = kwargs["instance"]
|
||||
user = machine.user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=False,
|
||||
mac_refresh=True,
|
||||
)
|
||||
regen("dhcp")
|
||||
regen("mac_ip_list")
|
||||
|
||||
|
@ -2540,7 +2519,13 @@ def interface_post_save(**kwargs):
|
|||
interface = kwargs["instance"]
|
||||
interface.sync_ipv6()
|
||||
user = interface.machine.user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=False,
|
||||
mac_refresh=True,
|
||||
)
|
||||
# Regen services
|
||||
regen("dhcp")
|
||||
regen("mac_ip_list")
|
||||
|
@ -2552,11 +2537,16 @@ def interface_post_save(**kwargs):
|
|||
|
||||
@receiver(post_delete, sender=Interface)
|
||||
def interface_post_delete(**kwargs):
|
||||
"""Synchronise LDAP and regen firewall/DHCP after an interface is deleted.
|
||||
"""
|
||||
"""Synchronise LDAP and regen firewall/DHCP after an interface is deleted."""
|
||||
interface = kwargs["instance"]
|
||||
user = interface.machine.user
|
||||
users.signals.synchronise.send(sender=users.models.User, instance=user, base=False, access_refresh=False, mac_refresh=True)
|
||||
users.signals.synchronise.send(
|
||||
sender=users.models.User,
|
||||
instance=user,
|
||||
base=False,
|
||||
access_refresh=False,
|
||||
mac_refresh=True,
|
||||
)
|
||||
|
||||
|
||||
@receiver(post_save, sender=IpType)
|
||||
|
|
|
@ -28,8 +28,7 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
from . import views_autocomplete
|
||||
from . import views, views_autocomplete
|
||||
|
||||
app_name = "machines"
|
||||
|
||||
|
@ -96,9 +95,7 @@ urlpatterns = [
|
|||
path("add_alias/<int:interfaceid>", views.add_alias, name="add-alias"),
|
||||
path("edit_alias/<int:domainid>", views.edit_alias, name="edit-alias"),
|
||||
path("del_alias/<int:interfaceid>", views.del_alias, name="del-alias"),
|
||||
path(
|
||||
"index_alias/<int:interfaceid>", views.index_alias, name="index-alias"
|
||||
),
|
||||
path("index_alias/<int:interfaceid>", views.index_alias, name="index-alias"),
|
||||
path(
|
||||
"new_ipv6list/<int:interfaceid>",
|
||||
views.new_ipv6list,
|
||||
|
@ -116,9 +113,7 @@ urlpatterns = [
|
|||
),
|
||||
path("index_ipv6/<int:interfaceid>", views.index_ipv6, name="index-ipv6"),
|
||||
path("add_service", views.add_service, name="add-service"),
|
||||
path(
|
||||
"edit_service/<int:serviceid>", views.edit_service, name="edit-service"
|
||||
),
|
||||
path("edit_service/<int:serviceid>", views.edit_service, name="edit-service"),
|
||||
path("del_service", views.del_service, name="del-service"),
|
||||
path(
|
||||
"regen_service/<int:serviceid>",
|
||||
|
@ -157,13 +152,49 @@ urlpatterns = [
|
|||
name="port-config",
|
||||
),
|
||||
### Autocomplete Views
|
||||
path('vlan-autocomplete', views_autocomplete.VlanAutocomplete.as_view(), name='vlan-autocomplete',),
|
||||
path('interface-autocomplete', views_autocomplete.InterfaceAutocomplete.as_view(), name='interface-autocomplete',),
|
||||
path('machine-autocomplete', views_autocomplete.MachineAutocomplete.as_view(), name='machine-autocomplete',),
|
||||
path('machinetype-autocomplete', views_autocomplete.MachineTypeAutocomplete.as_view(), name='machinetype-autocomplete',),
|
||||
path('iptype-autocomplete', views_autocomplete.IpTypeAutocomplete.as_view(), name='iptype-autocomplete',),
|
||||
path('extension-autocomplete', views_autocomplete.ExtensionAutocomplete.as_view(), name='extension-autocomplete',),
|
||||
path('domain-autocomplete', views_autocomplete.DomainAutocomplete.as_view(), name='domain-autocomplete',),
|
||||
path('ouvertureportlist-autocomplete', views_autocomplete.OuverturePortListAutocomplete.as_view(), name='ouvertureportlist-autocomplete',),
|
||||
path('iplist-autocomplete', views_autocomplete.IpListAutocomplete.as_view(), name='iplist-autocomplete',),
|
||||
path(
|
||||
"vlan-autocomplete",
|
||||
views_autocomplete.VlanAutocomplete.as_view(),
|
||||
name="vlan-autocomplete",
|
||||
),
|
||||
path(
|
||||
"interface-autocomplete",
|
||||
views_autocomplete.InterfaceAutocomplete.as_view(),
|
||||
name="interface-autocomplete",
|
||||
),
|
||||
path(
|
||||
"machine-autocomplete",
|
||||
views_autocomplete.MachineAutocomplete.as_view(),
|
||||
name="machine-autocomplete",
|
||||
),
|
||||
path(
|
||||
"machinetype-autocomplete",
|
||||
views_autocomplete.MachineTypeAutocomplete.as_view(),
|
||||
name="machinetype-autocomplete",
|
||||
),
|
||||
path(
|
||||
"iptype-autocomplete",
|
||||
views_autocomplete.IpTypeAutocomplete.as_view(),
|
||||
name="iptype-autocomplete",
|
||||
),
|
||||
path(
|
||||
"extension-autocomplete",
|
||||
views_autocomplete.ExtensionAutocomplete.as_view(),
|
||||
name="extension-autocomplete",
|
||||
),
|
||||
path(
|
||||
"domain-autocomplete",
|
||||
views_autocomplete.DomainAutocomplete.as_view(),
|
||||
name="domain-autocomplete",
|
||||
),
|
||||
path(
|
||||
"ouvertureportlist-autocomplete",
|
||||
views_autocomplete.OuverturePortListAutocomplete.as_view(),
|
||||
name="ouvertureportlist-autocomplete",
|
||||
),
|
||||
path(
|
||||
"iplist-autocomplete",
|
||||
views_autocomplete.IpListAutocomplete.as_view(),
|
||||
name="iplist-autocomplete",
|
||||
),
|
||||
]
|
||||
|
|
|
@ -34,11 +34,11 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.db.models import ProtectedError, F
|
||||
from django.db import IntegrityError
|
||||
from django.db.models import F, ProtectedError
|
||||
from django.forms import modelformset_factory
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
@ -46,82 +46,28 @@ from django.views.decorators.csrf import csrf_exempt
|
|||
from rest_framework.renderers import JSONRenderer
|
||||
|
||||
from preferences.models import GeneralOption
|
||||
from re2o.acl import (
|
||||
can_create,
|
||||
can_edit,
|
||||
can_view,
|
||||
can_delete,
|
||||
can_view_all,
|
||||
can_delete_set,
|
||||
)
|
||||
from re2o.utils import all_active_assigned_interfaces, filter_active_interfaces
|
||||
from re2o.acl import (can_create, can_delete, can_delete_set, can_edit,
|
||||
can_view, can_view_all)
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
from re2o.utils import all_active_assigned_interfaces, filter_active_interfaces
|
||||
from re2o.views import form
|
||||
from users.models import User
|
||||
from .forms import (
|
||||
NewMachineForm,
|
||||
EditMachineForm,
|
||||
EditInterfaceForm,
|
||||
AddInterfaceForm,
|
||||
MachineTypeForm,
|
||||
DelMachineTypeForm,
|
||||
ExtensionForm,
|
||||
DelExtensionForm,
|
||||
EditIpTypeForm,
|
||||
IpTypeForm,
|
||||
DelIpTypeForm,
|
||||
DomainForm,
|
||||
AliasForm,
|
||||
DelAliasForm,
|
||||
SOAForm,
|
||||
DelSOAForm,
|
||||
NsForm,
|
||||
DelNsForm,
|
||||
TxtForm,
|
||||
DelTxtForm,
|
||||
DNameForm,
|
||||
DelDNameForm,
|
||||
MxForm,
|
||||
DelMxForm,
|
||||
VlanForm,
|
||||
DelVlanForm,
|
||||
RoleForm,
|
||||
DelRoleForm,
|
||||
ServiceForm,
|
||||
DelServiceForm,
|
||||
SshFpForm,
|
||||
NasForm,
|
||||
DelNasForm,
|
||||
SrvForm,
|
||||
DelSrvForm,
|
||||
Ipv6ListForm,
|
||||
EditOuverturePortListForm,
|
||||
EditOuverturePortConfigForm,
|
||||
)
|
||||
from .models import (
|
||||
IpType,
|
||||
Machine,
|
||||
Interface,
|
||||
MachineType,
|
||||
Extension,
|
||||
SOA,
|
||||
Mx,
|
||||
Ns,
|
||||
Domain,
|
||||
Role,
|
||||
Service,
|
||||
Service_link,
|
||||
regen,
|
||||
Vlan,
|
||||
Nas,
|
||||
Txt,
|
||||
DName,
|
||||
Srv,
|
||||
SshFp,
|
||||
OuverturePortList,
|
||||
OuverturePort,
|
||||
Ipv6List,
|
||||
)
|
||||
|
||||
from .forms import (AddInterfaceForm, AliasForm, DelAliasForm, DelDNameForm,
|
||||
DelExtensionForm, DelIpTypeForm, DelMachineTypeForm,
|
||||
DelMxForm, DelNasForm, DelNsForm, DelRoleForm,
|
||||
DelServiceForm, DelSOAForm, DelSrvForm, DelTxtForm,
|
||||
DelVlanForm, DNameForm, DomainForm, EditInterfaceForm,
|
||||
EditIpTypeForm, EditMachineForm,
|
||||
EditOuverturePortConfigForm, EditOuverturePortListForm,
|
||||
ExtensionForm, IpTypeForm, Ipv6ListForm, MachineTypeForm,
|
||||
MxForm, NasForm, NewMachineForm, NsForm, RoleForm,
|
||||
ServiceForm, SOAForm, SrvForm, SshFpForm, TxtForm,
|
||||
VlanForm)
|
||||
from .models import (SOA, DName, Domain, Extension, Interface, IpType,
|
||||
Ipv6List, Machine, MachineType, Mx, Nas, Ns,
|
||||
OuverturePort, OuverturePortList, Role, Service,
|
||||
Service_link, Srv, SshFp, Txt, Vlan, regen)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -135,7 +81,9 @@ def new_machine(request, user, **_kwargs):
|
|||
"""
|
||||
machine = NewMachineForm(request.POST or None, user=request.user)
|
||||
interface = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain = DomainForm(request.POST or None, user=user, initial={'name': user.get_next_domain_name()})
|
||||
domain = DomainForm(
|
||||
request.POST or None, user=user, initial={"name": user.get_next_domain_name()}
|
||||
)
|
||||
if machine.is_valid() and interface.is_valid():
|
||||
new_machine_obj = machine.save(commit=False)
|
||||
new_machine_obj.user = user
|
||||
|
@ -229,7 +177,11 @@ def new_interface(request, machine, **_kwargs):
|
|||
machine.
|
||||
"""
|
||||
interface_form = AddInterfaceForm(request.POST or None, user=request.user)
|
||||
domain_form = DomainForm(request.POST or None, user=request.user, initial={'name': machine.user.get_next_domain_name()})
|
||||
domain_form = DomainForm(
|
||||
request.POST or None,
|
||||
user=request.user,
|
||||
initial={"name": machine.user.get_next_domain_name()},
|
||||
)
|
||||
if interface_form.is_valid():
|
||||
new_interface_obj = interface_form.save(commit=False)
|
||||
domain_form.instance.interface_parent = new_interface_obj
|
||||
|
@ -268,7 +220,9 @@ def del_interface(request, interface, **_kwargs):
|
|||
reverse("users:profil", kwargs={"userid": str(request.user.id)})
|
||||
)
|
||||
return form(
|
||||
{"objet": interface, "objet_name": _("interface")}, "machines/delete.html", request
|
||||
{"objet": interface, "objet_name": _("interface")},
|
||||
"machines/delete.html",
|
||||
request,
|
||||
)
|
||||
|
||||
|
||||
|
@ -328,7 +282,9 @@ def del_ipv6list(request, ipv6list, **_kwargs):
|
|||
reverse("machines:index-ipv6", kwargs={"interfaceid": str(interfaceid)})
|
||||
)
|
||||
return form(
|
||||
{"objet": ipv6list, "objet_name": _("IPv6 addresses list")}, "machines/delete.html", request
|
||||
{"objet": ipv6list, "objet_name": _("IPv6 addresses list")},
|
||||
"machines/delete.html",
|
||||
request,
|
||||
)
|
||||
|
||||
|
||||
|
@ -384,7 +340,9 @@ def del_sshfp(request, sshfp, **_kwargs):
|
|||
reverse("machines:index-sshfp", kwargs={"machineid": str(machineid)})
|
||||
)
|
||||
return form(
|
||||
{"objet": sshfp, "objet_name": _("SSHFP record")}, "machines/delete.html", request
|
||||
{"objet": sshfp, "objet_name": _("SSHFP record")},
|
||||
"machines/delete.html",
|
||||
request,
|
||||
)
|
||||
|
||||
|
||||
|
@ -421,7 +379,9 @@ def edit_iptype(request, iptype_instance, **_kwargs):
|
|||
iptype.save()
|
||||
messages.success(request, _("The IP type was edited."))
|
||||
except IntegrityError as e:
|
||||
messages.success(request, _("This IP type change would create duplicated domains"))
|
||||
messages.success(
|
||||
request, _("This IP type change would create duplicated domains")
|
||||
)
|
||||
return redirect(reverse("machines:index-iptype"))
|
||||
return form(
|
||||
{"iptypeform": iptype, "action_name": _("Edit")},
|
||||
|
@ -490,7 +450,10 @@ def edit_machinetype(request, machinetype_instance, **_kwargs):
|
|||
machinetype.save()
|
||||
messages.success(request, _("The machine type was edited."))
|
||||
except IntegrityError as e:
|
||||
messages.error(request, _("This machine type change would create duplicated domains"))
|
||||
messages.error(
|
||||
request,
|
||||
_("This machine type change would create duplicated domains"),
|
||||
)
|
||||
return redirect(reverse("machines:index-machinetype"))
|
||||
return form(
|
||||
{"machinetypeform": machinetype, "action_name": _("Edit")},
|
||||
|
@ -580,10 +543,16 @@ def del_extension(request, instances):
|
|||
_(
|
||||
"The extension %s is assigned to following %s : %s"
|
||||
", you can't delete it."
|
||||
) % (
|
||||
)
|
||||
% (
|
||||
extension_del,
|
||||
str(e.protected_objects.model._meta.verbose_name_plural),
|
||||
",".join(map(lambda x: str(x['name']), e.protected_objects.values('name').iterator()))
|
||||
",".join(
|
||||
map(
|
||||
lambda x: str(x["name"]),
|
||||
e.protected_objects.values("name").iterator(),
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
@ -1221,17 +1190,18 @@ def index(request):
|
|||
machines_list = re2o_paginator(request, machines_list, pagination_large_number)
|
||||
return render(request, "machines/index.html", {"machines_list": machines_list})
|
||||
|
||||
|
||||
# Canonic view for displaying machines in users's profil
|
||||
def aff_profil(request, user):
|
||||
"""View used to display the machines on a user's profile."""
|
||||
machines = (
|
||||
Machine.objects.filter(user=user)
|
||||
Machine.objects.filter(user=user)
|
||||
.select_related("user")
|
||||
.prefetch_related("interface_set__domain__extension")
|
||||
.prefetch_related("interface_set__ipv4__ip_type__extension")
|
||||
.prefetch_related("interface_set__machine_type")
|
||||
.prefetch_related("interface_set__domain__related_domain__extension")
|
||||
)
|
||||
)
|
||||
machines = SortTable.sort(
|
||||
machines,
|
||||
request.GET.get("col"),
|
||||
|
@ -1243,19 +1213,16 @@ def aff_profil(request, user):
|
|||
machines = re2o_paginator(request, machines, pagination_large_number)
|
||||
|
||||
context = {
|
||||
"users":user,
|
||||
"machines_list": machines,
|
||||
"nb_machines":nb_machines,
|
||||
"users": user,
|
||||
"machines_list": machines,
|
||||
"nb_machines": nb_machines,
|
||||
}
|
||||
|
||||
return render_to_string(
|
||||
"machines/aff_profil.html",context=context,request=request,using=None
|
||||
"machines/aff_profil.html", context=context, request=request, using=None
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@can_view_all(IpType)
|
||||
def index_iptype(request):
|
||||
|
@ -1531,4 +1498,3 @@ def configure_ports(request, interface_instance, **_kwargs):
|
|||
"machines/machine.html",
|
||||
request,
|
||||
)
|
||||
|
||||
|
|
|
@ -31,23 +31,14 @@ Here are defined the autocomplete class based view.
|
|||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models import Q, Value, CharField
|
||||
from django.db.models import CharField, Q, Value
|
||||
from django.db.models.functions import Concat
|
||||
|
||||
from .models import (
|
||||
Interface,
|
||||
Machine,
|
||||
Vlan,
|
||||
MachineType,
|
||||
IpType,
|
||||
Extension,
|
||||
Domain,
|
||||
OuverturePortList,
|
||||
IpList,
|
||||
)
|
||||
|
||||
from re2o.views import AutocompleteViewMixin
|
||||
|
||||
from .models import (Domain, Extension, Interface, IpList, IpType, Machine,
|
||||
MachineType, OuverturePortList, Vlan)
|
||||
|
||||
|
||||
class VlanAutocomplete(AutocompleteViewMixin):
|
||||
obj_type = Vlan
|
||||
|
|
|
@ -27,11 +27,11 @@ Select a dorm
|
|||
|
||||
|
||||
from django import forms
|
||||
from django.forms import ModelForm, Form
|
||||
from re2o.field_permissions import FieldPermissionFormMixin
|
||||
from re2o.mixins import FormRevMixin
|
||||
from django.forms import Form, ModelForm
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.field_permissions import FieldPermissionFormMixin
|
||||
from re2o.mixins import FormRevMixin
|
||||
from topologie.models import Dormitory
|
||||
|
||||
from .preferences.models import MultiopOption
|
||||
|
@ -49,4 +49,6 @@ class DormitoryForm(FormRevMixin, Form):
|
|||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DormitoryForm, self).__init__(*args, **kwargs)
|
||||
self.fields["dormitory"].queryset = MultiopOption.get_cached_value("enabled_dorm").all()
|
||||
self.fields["dormitory"].queryset = MultiopOption.get_cached_value(
|
||||
"enabled_dorm"
|
||||
).all()
|
||||
|
|
|
@ -25,21 +25,18 @@ Multi_op model
|
|||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.core.mail import EmailMessage
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.template import loader
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.template import loader
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from reversion.models import Version
|
||||
|
||||
from re2o.mixins import AclMixin
|
||||
from re2o.mail_utils import send_mail_object
|
||||
from django.core.mail import EmailMessage
|
||||
|
||||
from preferences.models import GeneralOption
|
||||
|
||||
import users.models
|
||||
from preferences.models import GeneralOption
|
||||
from re2o.mail_utils import send_mail_object
|
||||
from re2o.mixins import AclMixin
|
||||
|
||||
from .preferences.models import MultiopOption
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2020 Gabriel Détraz
|
||||
# Copyright © 2019 Arthur Grisel-Davy
|
||||
# Copyright © 2019 Arthur Grisel-Davy
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -27,8 +27,9 @@ each.
|
|||
|
||||
|
||||
from django import forms
|
||||
from django.forms import ModelForm, Form
|
||||
from django.forms import Form, ModelForm
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.widgets import AutocompleteMultipleModelWidget
|
||||
|
||||
from .models import MultiopOption
|
||||
|
|
|
@ -27,8 +27,8 @@ with multiple operators.
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
from preferences.models import PreferencesModel
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
|
||||
|
||||
class MultiopOption(AclMixin, PreferencesModel):
|
||||
|
|
|
@ -26,20 +26,16 @@
|
|||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.urls import reverse
|
||||
|
||||
from re2o.base import re2o_paginator
|
||||
|
||||
from re2o.acl import can_view, can_view_all, can_edit, can_create
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from preferences.views import edit_options_template_function
|
||||
from re2o.acl import can_create, can_edit, can_view, can_view_all
|
||||
from re2o.base import re2o_paginator
|
||||
|
||||
from . import forms
|
||||
from . import models
|
||||
|
||||
from . import forms, models
|
||||
|
||||
|
||||
def aff_preferences(request):
|
||||
|
|
|
@ -27,28 +27,24 @@
|
|||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.urls import reverse
|
||||
from django.forms import modelformset_factory
|
||||
from django.db.models import Q
|
||||
from django.forms import modelformset_factory
|
||||
from django.shortcuts import redirect, render
|
||||
from django.template.loader import render_to_string
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.cache import cache_page
|
||||
|
||||
from preferences.models import AssoOption, GeneralOption
|
||||
from re2o.acl import can_create, can_edit, can_view, can_view_all
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
from re2o.utils import all_adherent, all_has_access
|
||||
from re2o.views import form
|
||||
from re2o.utils import all_has_access, all_adherent
|
||||
|
||||
from re2o.base import re2o_paginator, SortTable
|
||||
|
||||
from re2o.acl import can_view, can_view_all, can_edit, can_create
|
||||
|
||||
from preferences.models import GeneralOption, AssoOption
|
||||
from topologie.models import Dormitory, Room
|
||||
|
||||
from .forms import DormitoryForm
|
||||
|
||||
from .preferences.models import MultiopOption
|
||||
|
||||
from topologie.models import Room, Dormitory
|
||||
|
||||
|
||||
def display_rooms_connection(request, dormitory=None):
|
||||
"""View used to display an overview of the rooms' connection state.
|
||||
|
@ -58,9 +54,13 @@ def display_rooms_connection(request, dormitory=None):
|
|||
dormitory: Dormitory, the dormitory used to filter rooms. If no
|
||||
dormitory is given, all rooms are displayed (default: None).
|
||||
"""
|
||||
room_list = Room.objects.select_related("building__dormitory").filter(
|
||||
building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()
|
||||
).order_by("building_dormitory", "port")
|
||||
room_list = (
|
||||
Room.objects.select_related("building__dormitory")
|
||||
.filter(
|
||||
building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()
|
||||
)
|
||||
.order_by("building_dormitory", "port")
|
||||
)
|
||||
if dormitory:
|
||||
room_list = room_list.filter(building__dormitory=dormitory)
|
||||
room_list = SortTable.sort(
|
||||
|
@ -113,7 +113,9 @@ def aff_pending_connection(request):
|
|||
Room.objects.select_related("building__dormitory")
|
||||
.filter(port__isnull=True)
|
||||
.filter(adherent__in=all_has_access())
|
||||
.filter(building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all())
|
||||
.filter(
|
||||
building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()
|
||||
)
|
||||
.order_by("building_dormitory", "port")
|
||||
)
|
||||
dormitory_form = DormitoryForm(request.POST or None)
|
||||
|
@ -151,7 +153,9 @@ def aff_pending_disconnection(request):
|
|||
Room.objects.select_related("building__dormitory")
|
||||
.filter(port__isnull=False)
|
||||
.exclude(Q(adherent__in=all_has_access()) | Q(adherent__in=all_adherent()))
|
||||
.filter(building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all())
|
||||
.filter(
|
||||
building__dormitory__in=MultiopOption.get_cached_value("enabled_dorm").all()
|
||||
)
|
||||
.order_by("building_dormitory", "port")
|
||||
)
|
||||
dormitory_form = DormitoryForm(request.POST or None)
|
||||
|
|
|
@ -28,21 +28,10 @@ from __future__ import unicode_literals
|
|||
from django.contrib import admin
|
||||
from reversion.admin import VersionAdmin
|
||||
|
||||
from .models import (
|
||||
OptionalUser,
|
||||
OptionalMachine,
|
||||
OptionalTopologie,
|
||||
GeneralOption,
|
||||
Service,
|
||||
MailContact,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
HomeOption,
|
||||
RadiusKey,
|
||||
SwitchManagementCred,
|
||||
Reminder,
|
||||
DocumentTemplate,
|
||||
)
|
||||
from .models import (AssoOption, DocumentTemplate, GeneralOption, HomeOption,
|
||||
MailContact, MailMessageOption, OptionalMachine,
|
||||
OptionalTopologie, OptionalUser, RadiusKey, Reminder,
|
||||
Service, SwitchManagementCred)
|
||||
|
||||
|
||||
class OptionalUserAdmin(VersionAdmin):
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
import preferences.models as preferences
|
||||
from api.serializers import NamespacedHRField, NamespacedHIField, NamespacedHMSerializer
|
||||
from api.serializers import (NamespacedHIField, NamespacedHMSerializer,
|
||||
NamespacedHRField)
|
||||
|
||||
|
||||
class OptionalUserSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalUser` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.OptionalUser` objects."""
|
||||
|
||||
tel_mandatory = serializers.BooleanField(source="is_tel_mandatory")
|
||||
shell_default = serializers.StringRelatedField()
|
||||
|
@ -47,8 +48,7 @@ class OptionalUserSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class OptionalMachineSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalMachine` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.OptionalMachine` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.OptionalMachine
|
||||
|
@ -59,13 +59,12 @@ class OptionalMachineSerializer(NamespacedHMSerializer):
|
|||
"ipv6_mode",
|
||||
"create_machine",
|
||||
"ipv6",
|
||||
"default_dns_ttl"
|
||||
"default_dns_ttl",
|
||||
)
|
||||
|
||||
|
||||
class OptionalTopologieSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.OptionalTopologie` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.OptionalTopologie` objects."""
|
||||
|
||||
switchs_management_interface_ip = serializers.CharField()
|
||||
|
||||
|
@ -85,8 +84,7 @@ class OptionalTopologieSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class RadiusOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.RadiusOption` objects
|
||||
"""
|
||||
"""Serialize `preferences.models.RadiusOption` objects"""
|
||||
|
||||
class Meta:
|
||||
model = preferences.RadiusOption
|
||||
|
@ -107,8 +105,7 @@ class RadiusOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class GeneralOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.GeneralOption` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.GeneralOption` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.GeneralOption
|
||||
|
@ -128,8 +125,7 @@ class GeneralOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class HomeServiceSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.Service` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.Service` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.Service
|
||||
|
@ -138,8 +134,7 @@ class HomeServiceSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class AssoOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.AssoOption` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.AssoOption` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.AssoOption
|
||||
|
@ -157,8 +152,7 @@ class AssoOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class HomeOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.HomeOption` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.HomeOption` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.HomeOption
|
||||
|
@ -166,8 +160,7 @@ class HomeOptionSerializer(NamespacedHMSerializer):
|
|||
|
||||
|
||||
class MailMessageOptionSerializer(NamespacedHMSerializer):
|
||||
"""Serialize `preferences.models.MailMessageOption` objects.
|
||||
"""
|
||||
"""Serialize `preferences.models.MailMessageOption` objects."""
|
||||
|
||||
class Meta:
|
||||
model = preferences.MailMessageOption
|
||||
|
|
|
@ -21,9 +21,7 @@
|
|||
|
||||
from . import views
|
||||
|
||||
urls_viewset = [
|
||||
(r"preferences/service", views.HomeServiceViewSet, "homeservice")
|
||||
]
|
||||
urls_viewset = [(r"preferences/service", views.HomeServiceViewSet, "homeservice")]
|
||||
|
||||
urls_view = [
|
||||
(r"preferences/optionaluser", views.OptionalUserView),
|
||||
|
@ -33,5 +31,5 @@ urls_view = [
|
|||
(r"preferences/generaloption", views.GeneralOptionView),
|
||||
(r"preferences/assooption", views.AssoOptionView),
|
||||
(r"preferences/homeoption", views.HomeOptionView),
|
||||
(r"preferences/mailmessageoption", views.MailMessageOptionView)
|
||||
]
|
||||
(r"preferences/mailmessageoption", views.MailMessageOptionView),
|
||||
]
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from rest_framework import viewsets, generics
|
||||
from rest_framework import generics, viewsets
|
||||
|
||||
from . import serializers
|
||||
import preferences.models as preferences
|
||||
from api.permissions import ACLPermission
|
||||
|
||||
from . import serializers
|
||||
|
||||
|
||||
class OptionalUserView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.OptionalUser.can_view_all]}
|
||||
|
@ -39,8 +39,7 @@ class OptionalUserView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class OptionalMachineView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalMachine` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.OptionalMachine` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.OptionalMachine.can_view_all]}
|
||||
|
@ -51,8 +50,7 @@ class OptionalMachineView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class OptionalTopologieView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.OptionalTopologie.can_view_all]}
|
||||
|
@ -63,8 +61,7 @@ class OptionalTopologieView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class RadiusOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.RadiusOption.can_view_all]}
|
||||
|
@ -75,8 +72,7 @@ class RadiusOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class GeneralOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.GeneralOption` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.GeneralOption` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.GeneralOption.can_view_all]}
|
||||
|
@ -87,16 +83,14 @@ class GeneralOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `preferences.models.Service` objects.
|
||||
"""
|
||||
"""Exposes list and details of `preferences.models.Service` objects."""
|
||||
|
||||
queryset = preferences.Service.objects.all()
|
||||
serializer_class = serializers.HomeServiceSerializer
|
||||
|
||||
|
||||
class AssoOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.AssoOption` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.AssoOption` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.AssoOption.can_view_all]}
|
||||
|
@ -107,8 +101,7 @@ class AssoOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class HomeOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.HomeOption` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.HomeOption` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.HomeOption.can_view_all]}
|
||||
|
@ -119,12 +112,11 @@ class HomeOptionView(generics.RetrieveAPIView):
|
|||
|
||||
|
||||
class MailMessageOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.MailMessageOption` settings.
|
||||
"""
|
||||
"""Exposes details of `preferences.models.MailMessageOption` settings."""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {"GET": [preferences.MailMessageOption.can_view_all]}
|
||||
serializer_class = serializers.MailMessageOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
return preferences.MailMessageOption.objects.first()
|
||||
return preferences.MailMessageOption.objects.first()
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class PreferencesConfig(AppConfig):
|
||||
"""Configuration of preferences app."""
|
||||
|
||||
name = "preferences"
|
||||
name = "preferences"
|
||||
|
|
|
@ -25,36 +25,22 @@ Forms to edit preferences: users, machines, topology, organisation etc.
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.forms import ModelForm, Form
|
||||
from django.db.models import Q
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.forms import Form, ModelForm
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.mixins import FormRevMixin
|
||||
from re2o.widgets import (
|
||||
AutocompleteModelWidget,
|
||||
AutocompleteMultipleModelWidget
|
||||
)
|
||||
from .models import (
|
||||
OptionalUser,
|
||||
OptionalMachine,
|
||||
OptionalTopologie,
|
||||
GeneralOption,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
HomeOption,
|
||||
Service,
|
||||
MailContact,
|
||||
Reminder,
|
||||
RadiusKey,
|
||||
SwitchManagementCred,
|
||||
RadiusOption,
|
||||
CotisationsOption,
|
||||
DocumentTemplate,
|
||||
RadiusAttribute,
|
||||
Mandate,
|
||||
)
|
||||
from re2o.widgets import (AutocompleteModelWidget,
|
||||
AutocompleteMultipleModelWidget)
|
||||
from topologie.models import Switch
|
||||
|
||||
from .models import (AssoOption, CotisationsOption, DocumentTemplate,
|
||||
GeneralOption, HomeOption, MailContact, MailMessageOption,
|
||||
Mandate, OptionalMachine, OptionalTopologie, OptionalUser,
|
||||
RadiusAttribute, RadiusKey, RadiusOption, Reminder,
|
||||
Service, SwitchManagementCred)
|
||||
|
||||
|
||||
class EditOptionalUserForm(ModelForm):
|
||||
"""Form used to edit user preferences."""
|
||||
|
@ -74,14 +60,22 @@ class EditOptionalUserForm(ModelForm):
|
|||
self.fields["self_change_shell"].label = _("Self change shell")
|
||||
self.fields["self_change_pseudo"].label = _("Self change pseudo")
|
||||
self.fields["self_room_policy"].label = _("Self room policy")
|
||||
self.fields["local_email_accounts_enabled"].label = _("Local email accounts enabled")
|
||||
self.fields["local_email_accounts_enabled"].label = _(
|
||||
"Local email accounts enabled"
|
||||
)
|
||||
self.fields["local_email_domain"].label = _("Local email domain")
|
||||
self.fields["max_email_address"].label = _("Max local email address")
|
||||
self.fields["delete_notyetactive"].label = _("Delete not yet active users")
|
||||
self.fields["disable_emailnotyetconfirmed"].label = _("Disabled email not yet confirmed")
|
||||
self.fields["disable_emailnotyetconfirmed"].label = _(
|
||||
"Disabled email not yet confirmed"
|
||||
)
|
||||
self.fields["self_adhesion"].label = _("Self registration")
|
||||
self.fields["all_users_active"].label = _("All users are state active by default")
|
||||
self.fields["allow_set_password_during_user_creation"].label = _("Allow set password during user creation")
|
||||
self.fields["all_users_active"].label = _(
|
||||
"All users are state active by default"
|
||||
)
|
||||
self.fields["allow_set_password_during_user_creation"].label = _(
|
||||
"Allow set password during user creation"
|
||||
)
|
||||
self.fields["allow_archived_connexion"].label = _("Allow archived connexion")
|
||||
|
||||
|
||||
|
@ -211,9 +205,7 @@ class EditMailMessageOptionForm(ModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
self.fields["welcome_mail_fr"].label = _(
|
||||
"Message for the French welcome email"
|
||||
)
|
||||
self.fields["welcome_mail_fr"].label = _("Message for the French welcome email")
|
||||
self.fields["welcome_mail_en"].label = _(
|
||||
"Message for the English welcome email"
|
||||
)
|
||||
|
@ -355,8 +347,7 @@ class ServiceForm(ModelForm):
|
|||
|
||||
|
||||
class DelServiceForm(Form):
|
||||
"""Form used to delete one or several services displayed on the home page.
|
||||
"""
|
||||
"""Form used to delete one or several services displayed on the home page."""
|
||||
|
||||
services = forms.ModelMultipleChoiceField(
|
||||
queryset=Service.objects.none(),
|
||||
|
|
|
@ -25,23 +25,22 @@ Models defining the preferences for users, machines, emails, general settings
|
|||
etc.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
import os
|
||||
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils import timezone
|
||||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.core.cache import cache
|
||||
from django.forms import ValidationError
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import machines.models
|
||||
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
from re2o.aes_field import AESEncryptedField
|
||||
|
||||
from datetime import timedelta
|
||||
from re2o.mixins import AclMixin, RevMixin
|
||||
|
||||
|
||||
class PreferencesModel(models.Model):
|
||||
|
@ -328,7 +327,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
configuration.
|
||||
"""
|
||||
if self.switchs_ip_type:
|
||||
from machines.models import Role, Interface
|
||||
from machines.models import Interface, Role
|
||||
|
||||
return (
|
||||
Interface.objects.filter(
|
||||
|
@ -364,14 +363,14 @@ class OptionalTopologie(AclMixin, PreferencesModel):
|
|||
"""Get the dictionary of IP addresses for the configuration of
|
||||
switches.
|
||||
"""
|
||||
from machines.models import Role, Ipv6List, Interface
|
||||
from machines.models import Interface, Ipv6List, Role
|
||||
|
||||
def return_ips_dict(interfaces):
|
||||
return {
|
||||
"ipv4": [str(interface.ipv4) for interface in interfaces],
|
||||
"ipv6": Ipv6List.objects.filter(interface__in=interfaces).filter(active=True).values_list(
|
||||
"ipv6", flat=True
|
||||
),
|
||||
"ipv6": Ipv6List.objects.filter(interface__in=interfaces)
|
||||
.filter(active=True)
|
||||
.values_list("ipv6", flat=True),
|
||||
}
|
||||
|
||||
ntp_servers = Role.all_interfaces_for_roletype("ntp-server").filter(
|
||||
|
@ -660,7 +659,7 @@ class Mandate(RevMixin, AclMixin, models.Model):
|
|||
|
||||
@classmethod
|
||||
def get_mandate(cls, date=timezone.now):
|
||||
""""Get the mandate taking place at the given date.
|
||||
""" "Get the mandate taking place at the given date.
|
||||
|
||||
Args:
|
||||
date: the date used to find the mandate (default: timezone.now).
|
||||
|
|
|
@ -79,9 +79,7 @@ urlpatterns = [
|
|||
name="edit-options",
|
||||
),
|
||||
path("add_service", views.add_service, name="add-service"),
|
||||
path(
|
||||
"edit_service/<int:serviceid>", views.edit_service, name="edit-service"
|
||||
),
|
||||
path("edit_service/<int:serviceid>", views.edit_service, name="edit-service"),
|
||||
path("del_service/<int:serviceid>", views.del_service, name="del-service"),
|
||||
path("add_mailcontact", views.add_mailcontact, name="add-mailcontact"),
|
||||
path(
|
||||
|
@ -143,13 +141,9 @@ urlpatterns = [
|
|||
name="del-document-template",
|
||||
),
|
||||
path("add_mandate", views.add_mandate, name="add-mandate"),
|
||||
path(
|
||||
"edit_mandate/<int:mandateid>", views.edit_mandate, name="edit-mandate"
|
||||
),
|
||||
path("edit_mandate/<int:mandateid>", views.edit_mandate, name="edit-mandate"),
|
||||
path("del_mandate/<int:mandateid>", views.del_mandate, name="del-mandate"),
|
||||
path(
|
||||
"add_radiusattribute", views.add_radiusattribute, name="add-radiusattribute"
|
||||
),
|
||||
path("add_radiusattribute", views.add_radiusattribute, name="add-radiusattribute"),
|
||||
path(
|
||||
"edit_radiusattribute/<int:radiusattributeid>",
|
||||
views.edit_radiusattribute,
|
||||
|
|
|
@ -30,61 +30,33 @@ services etc.)
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect
|
||||
from importlib import import_module
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.db.models import ProtectedError
|
||||
from django.db import transaction
|
||||
from django.db.models import ProtectedError
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from reversion import revisions as reversion
|
||||
|
||||
from importlib import import_module
|
||||
from re2o.acl import (acl_error_message, can_create, can_delete,
|
||||
can_delete_set, can_edit, can_view_all)
|
||||
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||
from re2o.views import form
|
||||
from re2o.acl import (
|
||||
can_create,
|
||||
can_edit,
|
||||
can_delete_set,
|
||||
can_view_all,
|
||||
can_delete,
|
||||
acl_error_message,
|
||||
)
|
||||
|
||||
from .forms import MailContactForm, DelMailContactForm
|
||||
from .forms import (
|
||||
ServiceForm,
|
||||
ReminderForm,
|
||||
RadiusKeyForm,
|
||||
SwitchManagementCredForm,
|
||||
DocumentTemplateForm,
|
||||
DelDocumentTemplateForm,
|
||||
RadiusAttributeForm,
|
||||
DelRadiusAttributeForm,
|
||||
MandateForm,
|
||||
)
|
||||
from .models import (
|
||||
Service,
|
||||
MailContact,
|
||||
OptionalUser,
|
||||
OptionalMachine,
|
||||
AssoOption,
|
||||
MailMessageOption,
|
||||
GeneralOption,
|
||||
OptionalTopologie,
|
||||
HomeOption,
|
||||
Reminder,
|
||||
RadiusKey,
|
||||
SwitchManagementCred,
|
||||
RadiusOption,
|
||||
CotisationsOption,
|
||||
DocumentTemplate,
|
||||
RadiusAttribute,
|
||||
Mandate,
|
||||
)
|
||||
from . import models
|
||||
from . import forms
|
||||
from . import forms, models
|
||||
from .forms import (DelDocumentTemplateForm, DelMailContactForm,
|
||||
DelRadiusAttributeForm, DocumentTemplateForm,
|
||||
MailContactForm, MandateForm, RadiusAttributeForm,
|
||||
RadiusKeyForm, ReminderForm, ServiceForm,
|
||||
SwitchManagementCredForm)
|
||||
from .models import (AssoOption, CotisationsOption, DocumentTemplate,
|
||||
GeneralOption, HomeOption, MailContact, MailMessageOption,
|
||||
Mandate, OptionalMachine, OptionalTopologie, OptionalUser,
|
||||
RadiusAttribute, RadiusKey, RadiusOption, Reminder,
|
||||
Service, SwitchManagementCred)
|
||||
|
||||
|
||||
def edit_options_template_function(request, section, forms, models):
|
||||
|
|
|
@ -30,8 +30,8 @@ from __future__ import unicode_literals
|
|||
import sys
|
||||
from itertools import chain
|
||||
|
||||
from django.db.models import Model
|
||||
from django.contrib import messages
|
||||
from django.db.models import Model
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
|
|
@ -28,22 +28,22 @@ Module defining a AESEncryptedField object that can be used in forms
|
|||
to handle the use of properly encrypting and decrypting AES keys
|
||||
"""
|
||||
|
||||
import string
|
||||
import binascii
|
||||
import string
|
||||
from random import choice
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
from django.db import models
|
||||
from Crypto.Cipher import AES
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
EOD_asbyte = b"`%EofD%`" # This should be something that will not occur in strings
|
||||
EOD = EOD_asbyte.decode("utf-8")
|
||||
|
||||
|
||||
def genstring(length=16, chars=string.printable):
|
||||
""" Generate a random string of length `length` and composed of
|
||||
the characters in `chars` """
|
||||
"""Generate a random string of length `length` and composed of
|
||||
the characters in `chars`"""
|
||||
return "".join([choice(chars) for i in range(length)])
|
||||
|
||||
|
||||
|
@ -71,8 +71,8 @@ class AESEncryptedFormField(forms.CharField):
|
|||
|
||||
|
||||
class AESEncryptedField(models.CharField):
|
||||
""" A Field that can be used in forms for adding the support
|
||||
of AES ecnrypted fields """
|
||||
"""A Field that can be used in forms for adding the support
|
||||
of AES ecnrypted fields"""
|
||||
|
||||
def save_form_data(self, instance, data):
|
||||
setattr(
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class Re2oConfig(AppConfig):
|
||||
"""Configuration of re2o app."""
|
||||
|
||||
name = "re2o"
|
||||
name = "re2o"
|
||||
|
|
13
re2o/base.py
13
re2o/base.py
|
@ -26,12 +26,11 @@ Global independant usefull functions
|
|||
|
||||
import smtplib
|
||||
|
||||
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
|
||||
from re2o.settings import EMAIL_HOST
|
||||
|
||||
|
||||
# Mapping of srtftime format for better understanding
|
||||
# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior
|
||||
datetime_mapping = {
|
||||
|
@ -64,7 +63,7 @@ datetime_mapping = {
|
|||
|
||||
def smtp_check(local_part):
|
||||
"""Return True if the local_part is already taken
|
||||
False if available"""
|
||||
False if available"""
|
||||
try:
|
||||
srv = smtplib.SMTP(EMAIL_HOST)
|
||||
srv.putcmd("vrfy", local_part)
|
||||
|
@ -108,9 +107,9 @@ def get_input_formats_help_text(input_formats):
|
|||
|
||||
|
||||
class SortTable:
|
||||
""" Class gathering uselful stuff to sort the colums of a table, according
|
||||
"""Class gathering uselful stuff to sort the colums of a table, according
|
||||
to the column and order requested. It's used with a dict of possible
|
||||
values and associated model_fields """
|
||||
values and associated model_fields"""
|
||||
|
||||
# All the possible possible values
|
||||
# The naming convention is based on the URL or the views function
|
||||
|
@ -228,8 +227,8 @@ class SortTable:
|
|||
|
||||
@staticmethod
|
||||
def sort(request, col, order, values):
|
||||
""" Check if the given values are possible and add .order_by() and
|
||||
a .reverse() as specified according to those values """
|
||||
"""Check if the given values are possible and add .order_by() and
|
||||
a .reverse() as specified according to those values"""
|
||||
fields = values.get(col, None)
|
||||
if not fields:
|
||||
fields = values.get("default", [])
|
||||
|
|
|
@ -24,21 +24,22 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from importlib import import_module
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.messages import get_messages
|
||||
from django.http import HttpRequest
|
||||
from preferences.models import GeneralOption, OptionalMachine
|
||||
from django.utils.translation import get_language
|
||||
from importlib import import_module
|
||||
|
||||
from preferences.models import GeneralOption, OptionalMachine
|
||||
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||
|
||||
|
||||
def context_user(request):
|
||||
"""Global Context function
|
||||
|
||||
Returns:
|
||||
dict:Containing user's interfaces and himself if logged, else None
|
||||
Returns:
|
||||
dict:Containing user's interfaces and himself if logged, else None
|
||||
|
||||
"""
|
||||
user = request.user
|
||||
|
@ -51,7 +52,9 @@ def context_user(request):
|
|||
if global_message not in [msg.message for msg in get_messages(request)]:
|
||||
messages.warning(request, global_message)
|
||||
else:
|
||||
if global_message not in [msg.message for msg in get_messages(request._request)]:
|
||||
if global_message not in [
|
||||
msg.message for msg in get_messages(request._request)
|
||||
]:
|
||||
messages.warning(request._request, global_message)
|
||||
if user.is_authenticated:
|
||||
interfaces = user.user_interfaces()
|
||||
|
@ -70,9 +73,9 @@ def context_user(request):
|
|||
def context_optionnal_apps(request):
|
||||
"""Context functions. Called to add optionnal apps buttons in navbari
|
||||
|
||||
Returns:
|
||||
dict:Containing optionnal template list of functions for navbar found
|
||||
in optional apps
|
||||
Returns:
|
||||
dict:Containing optionnal template list of functions for navbar found
|
||||
in optional apps
|
||||
|
||||
"""
|
||||
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
|
||||
|
|
|
@ -4,44 +4,44 @@ A list of the proud contributors to Re2o
|
|||
"""
|
||||
|
||||
CONTRIBUTORS = [
|
||||
'Gabriel Detraz',
|
||||
'Hugo Levy-falk',
|
||||
'Maël Kervella',
|
||||
'Jean-romain Garnier',
|
||||
'Arthur Grisel-davy',
|
||||
'Laouen Fernet',
|
||||
'Augustin Lemesle',
|
||||
'Lara Kermarec',
|
||||
'Root `root` Root',
|
||||
'Alexandre Iooss',
|
||||
'Yoann Piétri',
|
||||
'Charlie Jacomme',
|
||||
'Corentin Canebier',
|
||||
'Bombar Maxime',
|
||||
'Guillaume Goessel',
|
||||
'Matthieu Michelet',
|
||||
'Edpibu',
|
||||
'Fardale',
|
||||
'Jean-marie Mineau',
|
||||
'David Sinquin',
|
||||
'Gabriel Le Bouder',
|
||||
'Simon Brélivet',
|
||||
'~anonymised~',
|
||||
'Benjamin Graillot',
|
||||
'Leïla Bekaddour',
|
||||
'Éloi Alain',
|
||||
'Pierre Cadart',
|
||||
'Antoine Vintache',
|
||||
'Thibault De Boutray',
|
||||
'Delphine Salvy',
|
||||
'Joanne Steiner',
|
||||
'Krokmou',
|
||||
'B',
|
||||
'Daniel Stan',
|
||||
'Gwenael Le Hir',
|
||||
'Hugo Hervieux',
|
||||
'Mikachu',
|
||||
'Nymous',
|
||||
'Pierre-antoine Comby',
|
||||
'Vincent Le Gallic',
|
||||
]
|
||||
"Gabriel Detraz",
|
||||
"Hugo Levy-falk",
|
||||
"Maël Kervella",
|
||||
"Jean-romain Garnier",
|
||||
"Arthur Grisel-davy",
|
||||
"Laouen Fernet",
|
||||
"Augustin Lemesle",
|
||||
"Lara Kermarec",
|
||||
"Root `root` Root",
|
||||
"Alexandre Iooss",
|
||||
"Yoann Piétri",
|
||||
"Charlie Jacomme",
|
||||
"Corentin Canebier",
|
||||
"Bombar Maxime",
|
||||
"Guillaume Goessel",
|
||||
"Matthieu Michelet",
|
||||
"Edpibu",
|
||||
"Fardale",
|
||||
"Jean-marie Mineau",
|
||||
"David Sinquin",
|
||||
"Gabriel Le Bouder",
|
||||
"Simon Brélivet",
|
||||
"~anonymised~",
|
||||
"Benjamin Graillot",
|
||||
"Leïla Bekaddour",
|
||||
"Éloi Alain",
|
||||
"Pierre Cadart",
|
||||
"Antoine Vintache",
|
||||
"Thibault De Boutray",
|
||||
"Delphine Salvy",
|
||||
"Joanne Steiner",
|
||||
"Krokmou",
|
||||
"B",
|
||||
"Daniel Stan",
|
||||
"Gwenael Le Hir",
|
||||
"Hugo Hervieux",
|
||||
"Mikachu",
|
||||
"Nymous",
|
||||
"Pierre-antoine Comby",
|
||||
"Vincent Le Gallic",
|
||||
]
|
||||
|
|
|
@ -40,8 +40,8 @@ class FieldPermissionModelMixin:
|
|||
FIELD_PERMISSION_MISSING_DEFAULT = True
|
||||
|
||||
def has_field_perm(self, user, field):
|
||||
""" Checks if a `user` has the right to edit the `field`
|
||||
of this model """
|
||||
"""Checks if a `user` has the right to edit the `field`
|
||||
of this model"""
|
||||
if field in self.field_permissions:
|
||||
checks = self.field_permissions[field]
|
||||
if not isinstance(checks, (list, tuple)):
|
||||
|
|
|
@ -32,12 +32,12 @@ import binascii
|
|||
import crypt
|
||||
import hashlib
|
||||
import os
|
||||
from base64 import encodestring, decodestring, b64encode, b64decode
|
||||
from base64 import b64decode, b64encode, decodestring, encodestring
|
||||
from collections import OrderedDict
|
||||
from django.contrib.auth import hashers
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from hmac import compare_digest as constant_time_compare
|
||||
|
||||
from django.contrib.auth import hashers
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
|
||||
ALGO_NAME = "{SSHA}"
|
||||
ALGO_LEN = len(ALGO_NAME + "$")
|
||||
|
@ -45,7 +45,7 @@ DIGEST_LEN = 20
|
|||
|
||||
|
||||
def makeSecret(password):
|
||||
""" Build a hashed and salted version of the password with SSHA
|
||||
"""Build a hashed and salted version of the password with SSHA
|
||||
|
||||
Parameters:
|
||||
password (string): Password to hash
|
||||
|
@ -60,7 +60,7 @@ def makeSecret(password):
|
|||
|
||||
|
||||
def hashNT(password):
|
||||
""" Build a md4 hash of the password to use as the NT-password
|
||||
"""Build a md4 hash of the password to use as the NT-password
|
||||
|
||||
Parameters:
|
||||
password (string): Password to hash
|
||||
|
@ -78,7 +78,7 @@ def checkPassword(challenge_password, password):
|
|||
|
||||
Parameters:
|
||||
challenge_password (string): Password to verify with hash
|
||||
password (string): Hashed password to verify
|
||||
password (string): Hashed password to verify
|
||||
|
||||
Returns:
|
||||
boolean: True if challenge_password and password match
|
||||
|
@ -93,7 +93,7 @@ def checkPassword(challenge_password, password):
|
|||
|
||||
|
||||
def hash_password_salt(hashed_password):
|
||||
""" Extract the salt from a given hashed password
|
||||
"""Extract the salt from a given hashed password
|
||||
|
||||
Parameters:
|
||||
hashed_password (string): Hashed password to extract salt
|
||||
|
@ -277,15 +277,17 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher):
|
|||
class RecryptBackend(ModelBackend):
|
||||
"""Function for legacy users. During auth, if their hash password is different from SSHA or ntlm
|
||||
password is empty, rehash in SSHA or NTLM
|
||||
|
||||
|
||||
Returns:
|
||||
model user instance: Instance of the user logged
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def authenticate(self, request, username=None, password=None, **kwargs):
|
||||
# we obtain from the classical auth backend the user
|
||||
user = super(RecryptBackend, self).authenticate(request, username, password, **kwargs)
|
||||
user = super(RecryptBackend, self).authenticate(
|
||||
request, username, password, **kwargs
|
||||
)
|
||||
if user:
|
||||
if not (user.pwd_ntlm):
|
||||
# if we dont have NT hash, we create it
|
||||
|
|
|
@ -25,11 +25,13 @@
|
|||
All functions linked with emails here. Non model or app dependant
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.mail import send_mail as django_send_mail
|
||||
from django.contrib import messages
|
||||
from smtplib import SMTPException
|
||||
from socket import herror, gaierror
|
||||
from socket import gaierror, herror
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.mail import send_mail as django_send_mail
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
def send_mail(request, *args, **kwargs):
|
||||
"""Wrapper for Django's send_mail which handles errors"""
|
||||
|
@ -39,7 +41,8 @@ def send_mail(request, *args, **kwargs):
|
|||
except (SMTPException, ConnectionError, herror, gaierror) as e:
|
||||
messages.error(
|
||||
request,
|
||||
_("Failed to send email: %(error)s.") % {
|
||||
_("Failed to send email: %(error)s.")
|
||||
% {
|
||||
"error": e,
|
||||
},
|
||||
)
|
||||
|
@ -53,7 +56,8 @@ def send_mail_object(mail, request):
|
|||
if request:
|
||||
messages.error(
|
||||
request,
|
||||
_("Failed to send email: %(error)s.") % {
|
||||
_("Failed to send email: %(error)s.")
|
||||
% {
|
||||
"error": e,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -25,6 +25,7 @@ commits. This list is extracted from the current gitlab repository.
|
|||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
A set of mixins used all over the project to avoid duplicating code
|
||||
"""
|
||||
|
||||
from reversion import revisions as reversion
|
||||
from django.db import transaction
|
||||
from django.utils.translation import ugettext as _
|
||||
from reversion import revisions as reversion
|
||||
|
||||
|
||||
class RevMixin(object):
|
||||
|
@ -252,4 +252,3 @@ class AclMixin(object):
|
|||
else None,
|
||||
(permission,),
|
||||
)
|
||||
|
||||
|
|
|
@ -24,17 +24,16 @@ with Re2o throught the CLI
|
|||
"""
|
||||
|
||||
import os
|
||||
from os.path import dirname
|
||||
import sys
|
||||
import pwd
|
||||
|
||||
import sys
|
||||
from getpass import getpass
|
||||
from reversion import revisions as reversion
|
||||
from os.path import dirname
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.core.management.base import CommandError
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
from django.db import transaction
|
||||
from django.utils.html import strip_tags
|
||||
from reversion import revisions as reversion
|
||||
|
||||
from users.models import User
|
||||
|
||||
|
@ -48,27 +47,24 @@ application = get_wsgi_application()
|
|||
|
||||
def get_user(pseudo):
|
||||
"""Find a user from its pseudo
|
||||
|
||||
|
||||
Parameters:
|
||||
pseudo (string): pseudo of this user
|
||||
|
||||
Returns:
|
||||
user instance:Instance of user
|
||||
|
||||
|
||||
"""
|
||||
user = User.objects.filter(pseudo=pseudo)
|
||||
if len(user) == 0:
|
||||
raise CommandError("Invalid user.")
|
||||
if len(user) > 1:
|
||||
raise CommandError(
|
||||
"Several users match this username. This SHOULD NOT happen."
|
||||
)
|
||||
raise CommandError("Several users match this username. This SHOULD NOT happen.")
|
||||
return user[0]
|
||||
|
||||
|
||||
def get_system_user():
|
||||
"""Find the system user login who used the command
|
||||
"""
|
||||
"""Find the system user login who used the command"""
|
||||
return pwd.getpwuid(int(os.getenv("SUDO_UID") or os.getuid())).pw_name
|
||||
|
||||
|
||||
|
@ -80,7 +76,7 @@ def form_cli(Form, user, action, *args, **kwargs):
|
|||
Form : a django class form to fill-in
|
||||
user : a re2o user doign the modification
|
||||
action: the action done with that form, for logs purpose
|
||||
|
||||
|
||||
"""
|
||||
data = {}
|
||||
dumb_form = Form(user=user, *args, **kwargs)
|
||||
|
@ -105,6 +101,4 @@ def form_cli(Form, user, action, *args, **kwargs):
|
|||
reversion.set_user(user)
|
||||
reversion.set_comment(action)
|
||||
|
||||
sys.stdout.write(
|
||||
"%s: done. The edit may take several minutes to apply.\n" % action
|
||||
)
|
||||
sys.stdout.write("%s: done. The edit may take several minutes to apply.\n" % action)
|
||||
|
|
|
@ -36,7 +36,9 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from .settings_default import *
|
||||
|
||||
try:
|
||||
from .settings_local import *
|
||||
except ImportError:
|
||||
|
@ -60,7 +62,11 @@ LOGIN_REDIRECT_URL = "/" # The URL for redirecting after login
|
|||
|
||||
# Application definition
|
||||
# dal_legacy_static only needed for Django < 2.0 (https://django-autocomplete-light.readthedocs.io/en/master/install.html#django-versions-earlier-than-2-0)
|
||||
EARLY_EXTERNAL_CONTRIB_APPS = ("dal", "dal_select2", "dal_legacy_static") # Need to be added before django.contrib.admin (https://django-autocomplete-light.readthedocs.io/en/master/install.html#configuration)
|
||||
EARLY_EXTERNAL_CONTRIB_APPS = (
|
||||
"dal",
|
||||
"dal_select2",
|
||||
"dal_legacy_static",
|
||||
) # Need to be added before django.contrib.admin (https://django-autocomplete-light.readthedocs.io/en/master/install.html#configuration)
|
||||
DJANGO_CONTRIB_APPS = (
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
|
@ -82,7 +88,11 @@ LOCAL_APPS = (
|
|||
"logs",
|
||||
)
|
||||
INSTALLED_APPS = (
|
||||
EARLY_EXTERNAL_CONTRIB_APPS + DJANGO_CONTRIB_APPS + EXTERNAL_CONTRIB_APPS + LOCAL_APPS + OPTIONNAL_APPS
|
||||
EARLY_EXTERNAL_CONTRIB_APPS
|
||||
+ DJANGO_CONTRIB_APPS
|
||||
+ EXTERNAL_CONTRIB_APPS
|
||||
+ LOCAL_APPS
|
||||
+ OPTIONNAL_APPS
|
||||
)
|
||||
MIDDLEWARE = (
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
|
@ -196,18 +206,18 @@ EMAIL_TIMEOUT = 10
|
|||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
]
|
||||
|
||||
# Activate API
|
||||
if "api" in INSTALLED_APPS:
|
||||
|
|
|
@ -56,7 +56,7 @@ GID_RANGES = {"posix": [501, 600]}
|
|||
|
||||
# If you want to add a database routers, please fill in above and add your databse.
|
||||
# Then, add a file "local_routers.py" in folder app re2o, and add your router path in
|
||||
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
|
||||
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
|
||||
LOCAL_ROUTERS = []
|
||||
|
||||
# Some optionnal Re2o Apps
|
||||
|
@ -65,24 +65,24 @@ OPTIONNAL_APPS_RE2O = ()
|
|||
# Some Django apps you want to add in you local project
|
||||
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
|
||||
|
||||
#Set auth password validator
|
||||
# Set auth password validator
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
'OPTIONS': {
|
||||
'user_attributes': ['surname', 'pseudo', 'name', 'email'],
|
||||
}
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
"OPTIONS": {
|
||||
"user_attributes": ["surname", "pseudo", "name", "email"],
|
||||
},
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'OPTIONS': {
|
||||
'min_length': 8,
|
||||
}
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
"OPTIONS": {
|
||||
"min_length": 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -105,7 +105,7 @@ GID_RANGES = {"posix": [501, 600]}
|
|||
|
||||
# If you want to add a database routers, please fill in above and add your databse.
|
||||
# Then, add a file "local_routers.py" in folder app re2o, and add your router path in
|
||||
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
|
||||
# the LOCAL_ROUTERS var as "re2o.local_routers.DbRouter". You can also add extra routers.
|
||||
LOCAL_ROUTERS = []
|
||||
|
||||
# Some optionnal Re2o Apps
|
||||
|
@ -114,24 +114,24 @@ OPTIONNAL_APPS_RE2O = ()
|
|||
# Some Django apps you want to add in you local project
|
||||
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
|
||||
|
||||
#Set auth password validator
|
||||
# Set auth password validator
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
'OPTIONS': {
|
||||
'user_attributes': ['surname', 'pseudo', 'name', 'email'],
|
||||
}
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
"OPTIONS": {
|
||||
"user_attributes": ["surname", "pseudo", "name", "email"],
|
||||
},
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'OPTIONS': {
|
||||
'min_length': 8,
|
||||
}
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
"OPTIONS": {
|
||||
"min_length": 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -73,9 +73,8 @@ an instance of a model (either Model.can_xxx or instance.can_xxx)
|
|||
import sys
|
||||
|
||||
from django import template
|
||||
from django.template.base import Node, NodeList
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from django.template.base import Node, NodeList
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
@ -202,7 +201,7 @@ def acl_fct(callback, reverse):
|
|||
@register.tag("cannot_edit_history")
|
||||
def acl_history_filter(parser, token):
|
||||
"""Templatetag for acl checking on history."""
|
||||
tag_name, = token.split_contents()
|
||||
(tag_name,) = token.split_contents()
|
||||
|
||||
callback = get_callback(tag_name)
|
||||
oknodes = parser.parse(("acl_else", "acl_end"))
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from django import template
|
||||
|
||||
from .url_insert_param import url_insert_param
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def pagination_insert_page_and_id(url, page=1, id=None, **kwargs):
|
||||
"""
|
||||
|
@ -77,10 +79,14 @@ def pagination_insert_page_and_id(url, page=1, id=None, **kwargs):
|
|||
"""
|
||||
|
||||
page_arg = "page"
|
||||
if "page_arg" in kwargs and kwargs["page_arg"] is not None and len(kwargs["page_arg"]) > 0:
|
||||
if (
|
||||
"page_arg" in kwargs
|
||||
and kwargs["page_arg"] is not None
|
||||
and len(kwargs["page_arg"]) > 0
|
||||
):
|
||||
page_arg = kwargs["page_arg"]
|
||||
|
||||
args = { "url": url, page_arg: page}
|
||||
args = {"url": url, page_arg: page}
|
||||
new_url = url_insert_param(**args)
|
||||
|
||||
if id != None:
|
||||
|
|
|
@ -26,8 +26,8 @@ which indicated if a user can creates an account by himself
|
|||
"""
|
||||
|
||||
from django import template
|
||||
from preferences.models import OptionalUser
|
||||
|
||||
from preferences.models import OptionalUser
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
|
|
@ -24,14 +24,13 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import include, path
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
from .settings_local import OPTIONNAL_APPS_RE2O
|
||||
|
||||
from .views import index, about_page, contact_page, handler404, handler500
|
||||
from .views import about_page, contact_page, handler404, handler500, index
|
||||
|
||||
# Admin site configuration
|
||||
admin.site.index_title = _("Homepage")
|
||||
|
|
|
@ -36,14 +36,14 @@ Functions:
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
from django.db.models import Q
|
||||
from django.contrib.auth.models import Permission, Group
|
||||
from django.utils import timezone
|
||||
|
||||
from cotisations.models import Cotisation, Facture, Vente
|
||||
from machines.models import Interface, Machine
|
||||
from users.models import Adherent, User, Ban, Whitelist
|
||||
from preferences.models import AssoOption
|
||||
from users.models import Adherent, Ban, User, Whitelist
|
||||
|
||||
|
||||
def get_group_having_permission(*permission_name):
|
||||
|
@ -83,7 +83,9 @@ def filter_results(query_filter, dormitory, user_type):
|
|||
- on user_type (adherent or club) is specified
|
||||
Returns the filter"""
|
||||
if dormitory:
|
||||
query_filter &= (Q(adherent__room__building__dormitory=dormitory) | Q(club__room__building__dormitory=dormitory))
|
||||
query_filter &= Q(adherent__room__building__dormitory=dormitory) | Q(
|
||||
club__room__building__dormitory=dormitory
|
||||
)
|
||||
if user_type == "adherent":
|
||||
query_filter &= Q(adherent__isnull=False)
|
||||
if user_type == "club":
|
||||
|
@ -91,18 +93,20 @@ def filter_results(query_filter, dormitory, user_type):
|
|||
return query_filter
|
||||
|
||||
|
||||
def all_adherent(search_time=None, including_asso=True, dormitory=None, user_type="all"):
|
||||
def all_adherent(
|
||||
search_time=None, including_asso=True, dormitory=None, user_type="all"
|
||||
):
|
||||
"""Return all people who have a valid membership at org. Optimised to make only one
|
||||
sql query. Build a filter and then apply it to User. Check for each user if a valid
|
||||
membership is registered at the desired search_time.
|
||||
|
||||
|
||||
Parameters:
|
||||
search_time (django datetime): Datetime to perform this search,
|
||||
if not provided, search_time will be set à timezone.now()
|
||||
including_asso (boolean): Decide if org itself is included in results
|
||||
|
||||
Returns:
|
||||
django queryset: Django queryset containing all users with valid membership
|
||||
django queryset: Django queryset containing all users with valid membership
|
||||
|
||||
"""
|
||||
if search_time is None:
|
||||
|
@ -110,9 +114,9 @@ def all_adherent(search_time=None, including_asso=True, dormitory=None, user_typ
|
|||
filter_user = Q(
|
||||
facture__in=Facture.objects.filter(
|
||||
vente__cotisation__in=Cotisation.objects.filter(
|
||||
Q(vente__facture__facture__valid=True) &
|
||||
Q(date_start_memb__lt=search_time) &
|
||||
Q(date_end_memb__gt=search_time)
|
||||
Q(vente__facture__facture__valid=True)
|
||||
& Q(date_start_memb__lt=search_time)
|
||||
& Q(date_end_memb__gt=search_time)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -126,15 +130,15 @@ def all_adherent(search_time=None, including_asso=True, dormitory=None, user_typ
|
|||
|
||||
def all_baned(search_time=None, dormitory=None, user_type="all"):
|
||||
"""Return all people who are banned at org. Optimised to make only one
|
||||
sql query. Build a filter and then apply it to User. Check for each user
|
||||
sql query. Build a filter and then apply it to User. Check for each user
|
||||
banned at the desired search_time.
|
||||
|
||||
|
||||
Parameters:
|
||||
search_time (django datetime): Datetime to perform this search,
|
||||
if not provided, search_time will be set à timezone.now()
|
||||
|
||||
Returns:
|
||||
django queryset: Django queryset containing all users banned
|
||||
django queryset: Django queryset containing all users banned
|
||||
|
||||
"""
|
||||
if search_time is None:
|
||||
|
@ -152,13 +156,13 @@ def all_whitelisted(search_time=None, dormitory=None, user_type="all"):
|
|||
"""Return all people who have a free access at org. Optimised to make only one
|
||||
sql query. Build a filter and then apply it to User. Check for each user with a
|
||||
whitelisted free access at the desired search_time.
|
||||
|
||||
|
||||
Parameters:
|
||||
search_time (django datetime): Datetime to perform this search,
|
||||
if not provided, search_time will be set à timezone.now()
|
||||
|
||||
Returns:
|
||||
django queryset: Django queryset containing all users whitelisted
|
||||
django queryset: Django queryset containing all users whitelisted
|
||||
|
||||
"""
|
||||
if search_time is None:
|
||||
|
@ -191,9 +195,9 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a
|
|||
filter_user = Q(
|
||||
facture__in=Facture.objects.filter(
|
||||
vente__cotisation__in=Cotisation.objects.filter(
|
||||
Q(vente__facture__facture__valid=True) &
|
||||
Q(date_start_con__lt=search_time) &
|
||||
Q(date_end_con__gt=search_time)
|
||||
Q(vente__facture__facture__valid=True)
|
||||
& Q(date_start_con__lt=search_time)
|
||||
& Q(date_end_con__gt=search_time)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -205,9 +209,11 @@ def all_conn(search_time=None, including_asso=True, dormitory=None, user_type="a
|
|||
return User.objects.filter(filter_user).distinct()
|
||||
|
||||
|
||||
def all_has_access(search_time=None, including_asso=True, dormitory=None, user_type="all"):
|
||||
def all_has_access(
|
||||
search_time=None, including_asso=True, dormitory=None, user_type="all"
|
||||
):
|
||||
"""Return all people who have an valid internet access at org. Call previously buid filters.
|
||||
Can't do that in one sql query unfortunatly. Apply each filters, and return users
|
||||
Can't do that in one sql query unfortunatly. Apply each filters, and return users
|
||||
with a whitelist, or a valid paid access, except banned users.
|
||||
|
||||
Parameters:
|
||||
|
@ -216,14 +222,13 @@ def all_has_access(search_time=None, including_asso=True, dormitory=None, user_t
|
|||
including_asso (boolean): Decide if org itself is included in results
|
||||
|
||||
Returns:
|
||||
django queryset: Django queryset containing all valid connection users
|
||||
django queryset: Django queryset containing all valid connection users
|
||||
|
||||
"""
|
||||
if search_time is None:
|
||||
search_time = timezone.now()
|
||||
filter_user = (
|
||||
Q(state=User.STATE_ACTIVE)
|
||||
& ~Q(email_state=User.EMAIL_STATE_UNVERIFIED)
|
||||
filter_user = Q(state=User.STATE_ACTIVE) & ~Q(
|
||||
email_state=User.EMAIL_STATE_UNVERIFIED
|
||||
)
|
||||
if including_asso:
|
||||
asso_user = AssoOption.get_cached_value("utilisateur_asso")
|
||||
|
@ -231,18 +236,36 @@ def all_has_access(search_time=None, including_asso=True, dormitory=None, user_t
|
|||
filter_user |= Q(id=asso_user.id)
|
||||
filter_user = filter_results(filter_user, dormitory, user_type)
|
||||
return User.objects.filter(
|
||||
Q(filter_user) & (
|
||||
Q(filter_user)
|
||||
& (
|
||||
Q(
|
||||
id__in=all_whitelisted(search_time=search_time, dormitory=dormitory, user_type=user_type)
|
||||
) | (
|
||||
Q(
|
||||
id__in=all_adherent(search_time=search_time, including_asso=including_asso, dormitory=dormitory, user_type=user_type)
|
||||
) & Q(
|
||||
id__in=all_conn(search_time=search_time, including_asso=including_asso, dormitory=dormitory, user_type=user_type)
|
||||
id__in=all_whitelisted(
|
||||
search_time=search_time, dormitory=dormitory, user_type=user_type
|
||||
)
|
||||
)
|
||||
) & ~Q(
|
||||
id__in=all_baned(search_time=search_time, dormitory=dormitory, user_type=user_type)
|
||||
| (
|
||||
Q(
|
||||
id__in=all_adherent(
|
||||
search_time=search_time,
|
||||
including_asso=including_asso,
|
||||
dormitory=dormitory,
|
||||
user_type=user_type,
|
||||
)
|
||||
)
|
||||
& Q(
|
||||
id__in=all_conn(
|
||||
search_time=search_time,
|
||||
including_asso=including_asso,
|
||||
dormitory=dormitory,
|
||||
user_type=user_type,
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
& ~Q(
|
||||
id__in=all_baned(
|
||||
search_time=search_time, dormitory=dormitory, user_type=user_type
|
||||
)
|
||||
)
|
||||
).distinct()
|
||||
|
||||
|
@ -257,7 +280,7 @@ def filter_active_interfaces(interface_set):
|
|||
interface_set (django queryset): A queryset of interfaces to perform filter
|
||||
|
||||
Returns:
|
||||
django filter: Django filter to apply to an interfaces queryset,
|
||||
django filter: Django filter to apply to an interfaces queryset,
|
||||
will return when applied all active interfaces, related with
|
||||
a user with valid membership
|
||||
|
||||
|
@ -289,7 +312,7 @@ def filter_complete_interfaces(interface_set):
|
|||
interface_set (django queryset): A queryset of interfaces to perform filter
|
||||
|
||||
Returns:
|
||||
django filter: Django filter to apply to an interfaces queryset,
|
||||
django filter: Django filter to apply to an interfaces queryset,
|
||||
will return when applied all active interfaces, related with
|
||||
a user with valid membership
|
||||
|
||||
|
|
|
@ -26,34 +26,28 @@ Welcom main page view, and several template widely used in re2o views
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import git
|
||||
from importlib import import_module
|
||||
|
||||
import git
|
||||
from dal import autocomplete
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.shortcuts import render
|
||||
from django.template.context_processors import csrf
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.utils.decorators import method_decorator
|
||||
from dal import autocomplete
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from preferences.models import (
|
||||
Service,
|
||||
MailContact,
|
||||
AssoOption,
|
||||
HomeOption,
|
||||
GeneralOption,
|
||||
Mandate,
|
||||
)
|
||||
from preferences.models import (AssoOption, GeneralOption, HomeOption,
|
||||
MailContact, Mandate, Service)
|
||||
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||
|
||||
from .contributors import CONTRIBUTORS
|
||||
from importlib import import_module
|
||||
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||
|
||||
|
||||
def form(ctx, template, request):
|
||||
"""Global template function, used in all re2o views, for building a render with context,
|
||||
template and request. Adding csrf.
|
||||
|
||||
|
||||
Parameters:
|
||||
ctx (dict): Dict of values to transfer to template
|
||||
template (django template): The django template of this view
|
||||
|
@ -70,8 +64,8 @@ def form(ctx, template, request):
|
|||
def index(request):
|
||||
"""Display all services provided on main page
|
||||
|
||||
Returns: a form with all services linked and description, and social media
|
||||
link if provided.
|
||||
Returns: a form with all services linked and description, and social media
|
||||
link if provided.
|
||||
|
||||
"""
|
||||
services = [[], [], []]
|
||||
|
@ -95,9 +89,9 @@ def index(request):
|
|||
|
||||
|
||||
def about_page(request):
|
||||
""" The view for the about page.
|
||||
"""The view for the about page.
|
||||
Fetch some info about the configuration of the project. If it can't
|
||||
get the info from the Git repository, fallback to default string """
|
||||
get the info from the Git repository, fallback to default string"""
|
||||
option = AssoOption.objects.get()
|
||||
general = GeneralOption.objects.get()
|
||||
git_info_contributors = CONTRIBUTORS
|
||||
|
@ -197,4 +191,3 @@ class AutocompleteLoggedOutViewMixin(autocomplete.Select2QuerySetView):
|
|||
|
||||
class AutocompleteViewMixin(LoginRequiredMixin, AutocompleteLoggedOutViewMixin):
|
||||
pass
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2021 Gabriel Détraz
|
||||
# Copyright © 2021 Jean-Romain Garnier
|
||||
# Copyright © 2021 Jean-Romain Garnier
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,12 +25,12 @@ Re2o Forms and ModelForms Widgets.
|
|||
Used in others forms for using autocomplete engine.
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from dal import autocomplete
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
||||
class AutocompleteModelWidget(autocomplete.ModelSelect2):
|
||||
""" A mixin subclassing django-autocomplete-light's Select2 model to pass default options
|
||||
"""A mixin subclassing django-autocomplete-light's Select2 model to pass default options
|
||||
See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2
|
||||
"""
|
||||
|
||||
|
@ -54,7 +54,7 @@ class AutocompleteModelWidget(autocomplete.ModelSelect2):
|
|||
|
||||
|
||||
class AutocompleteMultipleModelWidget(autocomplete.ModelSelect2Multiple):
|
||||
""" A mixin subclassing django-autocomplete-light's Select2 model to pass default options
|
||||
"""A mixin subclassing django-autocomplete-light's Select2 model to pass default options
|
||||
See https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#passing-options-to-select2
|
||||
"""
|
||||
|
||||
|
|
|
@ -32,12 +32,11 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from os.path import dirname
|
||||
import sys
|
||||
from os.path import dirname
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
|
||||
sys.path.append(dirname(dirname(__file__)))
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
|
||||
|
||||
|
|
|
@ -8,4 +8,4 @@ from django.apps import AppConfig
|
|||
class SearchConfig(AppConfig):
|
||||
"""Configuration of search app."""
|
||||
|
||||
name = "search"
|
||||
name = "search"
|
||||
|
|
|
@ -28,19 +28,16 @@ Gplv2"""
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models import Q, Value
|
||||
from django.db.models.functions import Concat
|
||||
from netaddr import EUI, AddrFormatError
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db.models import Value
|
||||
from django.db.models.functions import Concat
|
||||
|
||||
from users.models import User, Adherent, Club, Ban, Whitelist
|
||||
from machines.models import Machine
|
||||
from topologie.models import Port, Switch, Room
|
||||
from cotisations.models import Facture
|
||||
from machines.models import Machine
|
||||
from preferences.models import GeneralOption
|
||||
from re2o.base import SortTable, re2o_paginator
|
||||
|
||||
from topologie.models import Port, Room, Switch
|
||||
from users.models import Adherent, Ban, Club, User, Whitelist
|
||||
|
||||
# List of fields the search applies to
|
||||
FILTER_FIELDS = [
|
||||
|
|
|
@ -27,6 +27,7 @@ from __future__ import unicode_literals
|
|||
from django import forms
|
||||
from django.forms import Form
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from re2o.base import get_input_formats_help_text
|
||||
|
||||
CHOICES_USER = (
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue