Commit e690292e authored by Gabriel Detraz's avatar Gabriel Detraz Committed by chirac

Merge branch 'master' into graph_topo

parents a975efd7 05bc645a
......@@ -43,11 +43,6 @@ import radiusd # Module magique freeradius (radiusd.py is dummy)
from django.core.wsgi import get_wsgi_application
from django.db.models import Q
from machines.models import Interface, IpList, Nas, Domain
from topologie.models import Port, Switch
from users.models import User
from preferences.models import OptionalTopologie
proj_path = "/var/www/re2o/"
# This is so Django knows where to find stuff.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
......@@ -59,6 +54,12 @@ os.chdir(proj_path)
# This is so models get loaded.
application = get_wsgi_application()
from machines.models import Interface, IpList, Nas, Domain
from topologie.models import Port, Switch
from users.models import User
from preferences.models import OptionalTopologie
options, created = OptionalTopologie.objects.get_or_create()
VLAN_NOK = options.vlan_decision_nok.vlan_id
VLAN_OK = options.vlan_decision_ok.vlan_id
......
......@@ -66,7 +66,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td><p class="text-success">{{utilisateur.last}}</p></td>
{% endif %}
<td>
{% if droit != 'Superuser' %}
<a href="{% url 'users:del-group' utilisateur.id droit.id %}">
{% else %}
<a href="{% url 'users:del-superuser' utilisateur.id %}">
{% endif %}
<button type="button" class="btn btn-danger" aria-label="Left Align">
<span class="fa fa-user-times" aria-hidden="true"></span>
</button>
......@@ -79,4 +83,4 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div>
</div>
</div>
{% endfor %}
\ No newline at end of file
{% endfor %}
......@@ -41,7 +41,7 @@ from django.urls import reverse
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Count, Max
from django.db.models import Count, Max, F
from reversion.models import Revision
from reversion.models import Version, ContentType
......@@ -195,9 +195,7 @@ def revert_action(request, revision_id):
@login_required
@can_view_all(IpList)
@can_view_all(Interface)
@can_view_all(User)
@can_view_all(IpList, Interface, User)
def stats_general(request):
"""Statistiques générales affinées sur les ip, activées, utilisées par
range, et les statistiques générales sur les users : users actifs,
......@@ -313,10 +311,7 @@ def stats_general(request):
@login_required
@can_view_app('users')
@can_view_app('cotisations')
@can_view_app('machines')
@can_view_app('topologie')
@can_view_app('users', 'cotisations', 'machines', 'topologie')
def stats_models(request):
"""Statistiques générales, affiche les comptages par models:
nombre d'users, d'écoles, de droits, de bannissements,
......@@ -469,9 +464,14 @@ def stats_droits(request):
for droit in ListRight.objects.all().select_related('group_ptr'):
stats_list[droit] = droit.user_set.all().annotate(
num=Count('revision'),
last=Max('revision__date_created')
last=Max('revision__date_created'),
)
stats_list['Superuser'] = User.objects.filter(is_superuser=True).annotate(
num=Count('revision'),
last=Max('revision__date_created'),
)
return render(
request,
'logs/stats_droits.html',
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-05-03 04:34
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('machines', '0079_auto_20180416_0107'),
]
operations = [
migrations.AlterField(
model_name='ns',
name='ns',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='machines.Domain'),
),
]
......@@ -613,7 +613,7 @@ class Ns(RevMixin, AclMixin, models.Model):
PRETTY_NAME = "Enregistrements NS"
zone = models.ForeignKey('Extension', on_delete=models.PROTECT)
ns = models.OneToOneField('Domain', on_delete=models.PROTECT)
ns = models.ForeignKey('Domain', on_delete=models.PROTECT)
class Meta:
permissions = (
......
......@@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% include "pagination.html" with list=machines_list %}
{% endif %}
<table class="table" id="machines_table">
<colgroup>
<col>
......
......@@ -1272,12 +1272,7 @@ def index_nas(request):
@login_required
@can_view_all(SOA)
@can_view_all(Mx)
@can_view_all(Ns)
@can_view_all(Txt)
@can_view_all(Srv)
@can_view_all(Extension)
@can_view_all(SOA, Mx, Ns, Txt, Srv, Extension)
def index_extension(request):
""" View displaying the list of existing extensions, the list of
existing SOA records, the list of existing MX records , the list of
......
# coding:utf-8
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
......
......@@ -58,13 +58,8 @@ from . import forms
@login_required
@can_view_all(OptionalUser)
@can_view_all(OptionalMachine)
@can_view_all(OptionalTopologie)
@can_view_all(GeneralOption)
@can_view_all(AssoOption)
@can_view_all(MailMessageOption)
@can_view_all(HomeOption)
@can_view_all(OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption,
AssoOption, MailMessageOption, HomeOption)
def display_options(request):
"""Vue pour affichage des options (en vrac) classé selon les models
correspondants dans un tableau"""
......@@ -149,7 +144,11 @@ def add_service(request):
@can_edit(Service)
def edit_service(request, service_instance, **_kwargs):
"""Edition des services affichés sur la page d'accueil"""
service = ServiceForm(request.POST or None, request.FILES or None,instance=service_instance)
service = ServiceForm(
request.POST or None,
request.FILES or None,
instance=service_instance
)
if service.is_valid():
with transaction.atomic(), reversion.create_revision():
service.save()
......
This diff is collapsed.
......@@ -30,6 +30,14 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: settings.py:140
msgid "English"
msgstr "Anglais"
#: settings.py:141
msgid "French"
msgstr "Français"
#: templates/re2o/about.html:29 templates/re2o/about.html:35
msgid "About Re2o"
msgstr "A propos de Re2o"
......@@ -147,6 +155,10 @@ msgstr ""
msgid "Dependencies"
msgstr "Dépendances"
#: templates/re2o/buttons/setlang.html:34
msgid "Translation in development"
msgstr "Traduction en développement"
#: views.py:172
msgid "No Git repository configured"
msgstr "Aucun repository git configuré"
......
......@@ -37,6 +37,7 @@ from __future__ import unicode_literals
import os
from .settings_local import *
from django.utils.translation import ugettext_lazy as _
# The root directory for the project
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
......@@ -135,6 +136,10 @@ LOCALE_PATHS = [
# For translations outside of apps
os.path.join(BASE_DIR, 'templates', 'locale').replace('\\', '/')
]
LANGUAGES = [
('en', _('English')),
('fr', _('French'))
]
# Should use time zone ?
USE_TZ = True
......
......@@ -55,6 +55,7 @@ urlpatterns = [
url(r'^about/$', about_page, name='about'),
url('^logout/', auth_views.logout, {'next_page': '/'}),
url('^', include('django.contrib.auth.urls')),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^admin/', include(admin.site.urls)),
url(r'^users/', include('users.urls', namespace='users')),
url(r'^search/', include('search.urls', namespace='search')),
......
......@@ -44,6 +44,49 @@ from cotisations.models import Cotisation, Facture, Vente
from machines.models import Interface, Machine
from users.models import Adherent, User, Ban, Whitelist
# Mapping of srtftime format for better understanding
# https://docs.python.org/3.6/library/datetime.html#strftime-strptime-behavior
datetime_mapping={
'%a': '%a',
'%A': '%A',
'%w': '%w',
'%d': 'dd',
'%b': '%b',
'%B': '%B',
'%m': 'mm',
'%y': 'yy',
'%Y': 'yyyy',
'%H': 'HH',
'%I': 'HH(12h)',
'%p': 'AMPM',
'%M': 'MM',
'%S': 'SS',
'%f': 'µµ',
'%z': 'UTC(+/-HHMM)',
'%Z': 'UTC(TZ)',
'%j': '%j',
'%U': 'ww',
'%W': 'ww',
'%c': '%c',
'%x': '%x',
'%X': '%X',
'%%': '%%',
}
def convert_datetime_format(format):
i=0
new_format = ""
while i < len(format):
if format[i] == '%':
char = format[i:i+2]
new_format += datetime_mapping.get(char, char)
i += 2
else:
new_format += format[i]
i += 1
return new_format
def all_adherent(search_time=None):
""" Fonction renvoyant tous les users adherents. Optimisee pour n'est
......@@ -318,3 +361,19 @@ def remove_user_room(room):
return
user.room = None
user.save()
def get_input_formats_help_text(input_formats):
"""Returns a help text about the possible input formats"""
if len(input_formats) > 1:
help_text_template="Format: {main} {more}"
else:
help_text_template="Format: {main}"
more_text_template="<i class=\"fa fa-question-circle\" title=\"{}\"></i>"
help_text = help_text_template.format(
main=convert_datetime_format(input_formats[0]),
more=more_text_template.format(
'\n'.join(map(convert_datetime_format, input_formats))
)
)
return help_text
......@@ -26,6 +26,7 @@ from __future__ import unicode_literals
from django import forms
from django.forms import Form
from re2o.utils import get_input_formats_help_text
CHOICES_USER = (
('0', 'Actifs'),
......@@ -91,12 +92,17 @@ class SearchFormPlus(Form):
s = forms.DateField(
required=False,
label="Date de début",
help_text='DD/MM/YYYY',
input_formats=['%d/%m/%Y']
)
e = forms.DateField(
required=False,
help_text='DD/MM/YYYY',
input_formats=['%d/%m/%Y'],
label="Date de fin"
)
def __init__(self, *args, **kwargs):
super(SearchFormPlus, self).__init__(*args, **kwargs)
self.fields['s'].help_text = get_input_formats_help_text(
self.fields['s'].input_formats
)
self.fields['e'].help_text = get_input_formats_help_text(
self.fields['e'].input_formats
)
......@@ -35,6 +35,26 @@ footer a {
border-radius: 0;
}
/* Add right colors for buttons in dropdown in navbar-inverse (else it is light
* gray on white bg and white when hovered */
.navbar-inverse .dropdown-menu .btn-link {
text-decoration: none;
color: #262626;
padding: 0;
}
.navbar-inverse .dropdown-menu .btn-link:hover {
background-color: #f5f5f5;
}
@media screen and (max-width: 767px) {
.navbar-inverse .dropdown-menu .btn-link {
color: #9d9d9d;
}
.navbar-inverse .dropdown-menu .btn-link:hover {
color: #fff;
background-color: transparent;
}
}
/* Set height of the grid so .sidenav can be 100% (adjust as needed) */
.row.content {
height: 100%;
......
......@@ -118,7 +118,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</li>
{% acl_end %}
<li>
<a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a>
<a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a>
</li>
{% if not request.user.is_authenticated %}
{% if var_sa %}
......@@ -145,48 +145,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div>
</form>
</li>
{% endif %}
</ul>
</ul>
{% comment %}
<div class="navbar-right">
<form action="{% url "search:search"%}" class="navbar-form" role="search">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search" name="q" id="search-term" {% if search_term %}value="{{ search_term }}"{% endif %}>
<div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
<a href="{% url "search:searchp" %}" class="btn btn-default" role="button"><i class="fa fa-plus"></i></a>
</div>
</div>
</form>
</div>
<ul class="nav navbar-nav navbar-right">
{% if not request.user.is_authenticated %}
{% if var_sa %}
<li>
<a href="{% url 'users:new-user' %}">
<i class="fa fa-user-plus"></i> Créer un compte
</a>
</li>
{% endif %}
<li>
<a href="{% url 'login' %}">
<i class="fa fa-sign-in-alt"></i> Login
</a>
</li>
{% endif %}
{% can_view_app preferences %}
<li>
<a href="{% url 'preferences:display-options' %}">
<i class="fa fa-cogs"></i> Preferences
</a>
</li>
{% acl_end %}
{% endif %}
<li>
<a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> A propos</a>
{% include 'buttons/setlang.html' %}
</li>
</ul>
{% endcomment %}
</div>
</div>
</nav>
......
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2018 Maël Kervella
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.
{% endcomment %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<a class="dropdown" type="button" role="button" id="setlang"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-globe"></i> <span class="caret"></span>
</a>
<div class="dropdown-menu" aria-labelledby="setlang">
<p style="text-align: center"><small><i class="fa fa-exclamation-triangle"></i> {% trans "Translation in development" %}</small></p>
<hr>
<form method="post" action="{% url 'set_language' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.path }}">
{% for language in languages %}
<button type="submit" name="language" value="{{ language.code }}"
class="btn btn-link btn-block
{% if language.code == LANGUAGE_CODE %}disabled{% endif %}">
{% if language.code == LANGUAGE_CODE %}
<i class="fa fa-check"></i>
{% endif %}
{{ language.name_local | title }} ({{ language.code }})
</button>
{% endfor %}
</form>
</div>
......@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load url_insert_param %}
{% if list.paginator.num_pages > 1 %}
<ul class="pagination nav navbar-nav">
{% if list.has_previous %}
<li><a href="{% url_insert_param request.get_full_path page=1 %}"> << </a></li>
......@@ -39,5 +40,5 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<li><a href="{% url_insert_param request.get_full_path page=list.next_page_number %}"> > </a></li>
<li><a href="{% url_insert_param request.get_full_path page=list.paginator.page_range|length %}"> >> </a></li>
{% endif %}
</ul>
</ul>
{% endif %}
......@@ -24,69 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load acl %}
<div class="table-responsive" style="font-size: 12px">
<table class="table table-bordered text-center text-nowrap">
<thead>
<tr>
{% for port in port_list|slice:"::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"::2" %}
{% if port.room %}
<td class="p-3 mb-2 bg-success text-dark">
{{ port.room }}
{% elif port.machine_interface %}
<td class="p-3 mb-2 bg-warning text-dark">
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">{{ port.machine_interface }}</a>
{% elif port.related%}
<td class="p-3 mb-2 bg-danger text-dark">
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">{{ port.related }}</a>
{% else %}
<td class="p-3 mb-2 bg-info text-dark">
Vide
{% endif %}
</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
{% if port.room %}
<td class="p-3 mb-2 bg-success text-dark">
{{ port.room }}
{% elif port.machine_interface %}
<td class="p-3 mb-2 bg-warning text-dark">
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">{{ port.machine_interface }}</a>
{% elif port.related%}
<td class="p-3 mb-2 bg-danger text-dark">
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">{{ port.related }}</a>
{% else %}
<td class="p-3 mb-2 bg-info text-dark">
Vide
{% endif %}
</td>
{% endfor %}
</tr>
</table>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
......@@ -105,37 +42,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<tr>
<td>{{ port.port }}</td>
<td>
{% if port.room %}
{{ port.room }}
{% endif %}
{% if port.room %}{{ port.room }}{% endif %}
</td>
<td>
{% if port.machine_interface %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">{{ port.machine_interface }}</a>
{% endif %}
{% if port.machine_interface %}
{% can_view port.machine_interface.machine.user %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">
{{ port.machine_interface }}
</a>
{% acl_else %}
{{ port.machine_interface }}
{% acl_end %}
{% endif %}
</td>
<td>
{% if port.related %}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">{{ port.related }}</a>
{% endif %}
{% if port.related %}
{% can_view port.related.switch %}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">
{{ port.related }}
</a>
{% acl_else %}
{{ port.related }}
{% acl_end %}
{% endif %}
</td>
<td>{{ port.radius }}</td>
<td>{% if not port.vlan_force %} Aucun{%else %}{{ port.vlan_force }}{% endif %}</td>
<td>{% if not port.vlan_force %}Aucun{% else %}{{ port.vlan_force }}{% endif %}</td>
<td>{{ port.details }}</td>
<td class="text-right">
<a class="btn btn-info btn-sm" role="button" title="Historique" href="{% url 'topologie:history' 'port' port.pk %}">
<i class="fa fa-history"></i>
</a>
{% can_edit port %}
{% can_edit port %}
<a class="btn btn-primary btn-sm" role="button" title="Éditer" href="{% url 'topologie:edit-port' port.id %}">
<i class="fa fa-edit"></i>
</a>
{% acl_end %}
{% can_delete port %}
{% acl_end %}
{% can_delete port %}
<a class="btn btn-danger btn-sm" role="button" title="Supprimer" href="{% url 'topologie:del-port' port.pk %}">
<i class="fa fa-trash"></i>
</a>
{% acl_end %}
{% acl_end %}
</td>
</tr>
{% endfor %}
......
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
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.
{% endcomment %}
{% load acl %}
<div class="table-responsive" style="font-size: 12px">
<table class="table table-bordered text-center text-nowrap">
<thead>
<tr>
{% for port in port_list|slice:"::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"::2" %}
{% if port.room %}
<td class="p-3 mb-2 bg-success text-dark">
{{ port.room }}
</td>
{% elif port.machine_interface %}
<td class="p-3 mb-2 bg-warning text-dark">
{% can_view port.machine_interface.machine.user %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">
{{ port.machine_interface }}
</a>
{% acl_else %}
{{ port.machine_interface }}
{% acl_end %}
</td>
{% elif port.related%}
<td class="p-3 mb-2 bg-danger text-dark">
{% can_view port.related.switch %}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">
{{ port.related }}
</a>
{% acl_else %}
{{ port.related }}
{% acl_end %}
</td>
{% else %}
<td class="p-3 mb-2 bg-info text-dark">
Vide
</td>
{% endif %}
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
<td class="bg-primary text-white">{{ port.port }}</td>
{% endfor %}
</tr>
<tr>
{% for port in port_list|slice:"1::2" %}
{% if port.room %}
<td class="p-3 mb-2 bg-success text-dark">
{{ port.room }}
</td>
{% elif port.machine_interface %}
<td class="p-3 mb-2 bg-warning text-dark">
{% can_view port.machine_interface.machine.user %}
<a href="{% url 'users:profil' userid=port.machine_interface.machine.user.id %}">
{{ port.machine_interface }}
</a>
{% acl_else %}
{{ port.machine_interface }}
{% acl_end %}
</td>
{% elif port.related%}
<td class="p-3 mb-2 bg-danger text-dark">
{% can_view port.related.switch %}
<a href="{% url 'topologie:index-port' switchid=port.related.switch.id %}">
{{ port.related }}
</a>
{% acl_else %}
{{ port.related }}
{% acl_end %}
</td>
{% else %}
<td class="p-3 mb-2 bg-info text-dark">
Vide
</td>
{% endif %}
{% endfor %}