Browse Source

Merge branch 'master' into polymorphic_configuration

Conflicts:
	coin/members/templates/members/subscriptions.html
	coin/vpn/urls.py
	coin/vpn/views.py
Fabs 10 years ago
parent
commit
7a7011295f

+ 4 - 2
coin/members/templates/members/subscriptions.html

@@ -9,6 +9,7 @@
             <th width="60">Type</th>
             <th>Identification</th>
             <th>Date d'activation</th>
+            <th>Commentaire</th>
             <th>Configuration</th>
         </tr>
     </thead>
@@ -18,8 +19,9 @@
             <td>{{ subscription.offer.type }}</td>
             <td>{{ subscription.offer.name }}</td>
             <td>{{ subscription.subscription_date }}</td>
-            <td>{% if subscription.configuration %}<a href="{% url subscription.configuration.get_url_namespace|add:":details" id=subscription.configuration.id %}">Show/edit configuration</a>{% endif %}</td>
-            <!-- <td><a href="{% url 'subscription:configuration-redirect' subscription.pk %}">Show/edit configuration</a></td> -->
+            <td>{{ subscription.configuration.comment }}</td>
+            <td>{% if subscription.configuration %}<a class="cfglink" href="{% url subscription.configuration.get_url_namespace|add:":details" id=subscription.configuration.id %}">Configuration</a>{% endif %}</td>
+            
         </tr>
         {% endfor %}
     </tbody>

+ 1 - 0
coin/settings.py

@@ -251,6 +251,7 @@ AUTH_LDAP_USER_FLAGS_BY_GROUP = {
     "is_superuser": "cn=coin_admin,ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
 }
 
+GRAPHITE_SERVER = "http://graphite-dev.illyse.org"
 
 # Surcharge les paramètres en utilisant le fichier settings-local.py
 try:

+ 53 - 0
coin/static/css/illyse.css

@@ -185,3 +185,56 @@ span.italic {
     color: #FF0000;
     content: "✗ ";
 }
+.pass {
+    font-weight: bold;
+}
+.warning {
+    background-color: #FF7777;
+    border-radius: 5px;
+    font-style: italic;
+}
+.warning:before {
+    content: "⚠ ";
+    font-weight: bold;
+}
+.flatfield input {
+	margin-bottom: 0;
+	border: 0 none transparent;
+	background-color: transparent;
+	text-overflow: ellipsis;
+	box-shadow: none;
+	font-size: 1.1em;
+	color: #222222;
+}
+.flatfield input::-moz-placeholder {
+	font-style: italic;
+}
+.flatfield input:-ms-input-placeholder {
+	font-style: italic;
+}
+.flatfield input::-webkit-input-placeholder {
+	font-style: italic;
+}
+.flatfield input:focus {
+	background-color: #FFFFFF;
+	border: 1px solid #C0C0C0;
+}
+
+h3.graphtitle select {
+	display: inline;
+	background-color: transparent;
+	border: 0 none transparent;
+	font-family: inherit;
+	box-shadow: none;
+	font-size: 0.9em;
+	width: auto;
+	margin: 0;
+	padding: 0;
+}
+h3.graphtitle select option {
+	font-size: 0.6em;
+}
+
+a.cfglink:before {
+	content: "⎘ ";
+}

BIN
coin/static/img/coin.ajax.gif


+ 45 - 0
coin/static/js/illyse.js

@@ -0,0 +1,45 @@
+window.onload = function() {
+	var field = document.getElementById("passgen");
+	if (field != undefined) field.onclick = function() {
+		var cell = field.parentNode;
+		cell.removeChild(field);
+		cell.appendChild(document.createElement("img"));
+		cell.lastChild.src = "/static/img/coin.ajax.gif";
+		cell.appendChild(document.createTextNode(" Génération en cours…"));
+		var xhr = new XMLHttpRequest();
+		xhr.onreadystatechange = function() {
+			if (xhr.readyState != 4) return;
+			var table = cell.parentNode.parentNode;
+			if (xhr.responseXML == null)
+				var pass = (new DOMParser().parseFromString(xhr.responseText, "text/html")).getElementById("password");
+			else var pass = xhr.responseXML.getElementById("password");
+			table.insertBefore(pass.cloneNode(true), cell.parentNode);
+			do pass = pass.nextSibling; while (pass.nodeType == 3);
+			table.insertBefore(pass.cloneNode(true), cell.parentNode);
+			table.removeChild(cell.parentNode);
+		};
+		xhr.open("GET", field.href, false);
+		xhr.send(null);
+		return false;
+	};
+	
+	var field = document.getElementById("trafic_zoom");
+	if (field != undefined) {
+		var select = document.createElement("select");
+		var options = {"hourly": "une heure", "daily": "24 heures", "weekly": "7 jours", "monthly": "un mois", "yearly": "un an"};
+		for (var i in options) {
+			var opt = document.createElement("option");
+			opt.appendChild(document.createTextNode(options[i]));
+			opt.value = i;
+			select.appendChild(opt);
+		}
+		select.childNodes[1].selected = "selected";
+		var graph = document.getElementById("trafic_graph");
+		var href = graph.src+"/";
+		select.onchange = function() {
+			graph.src = href+select.value;
+		};
+		field.parentNode.insertBefore(select, field);
+		field.parentNode.removeChild(field);
+	}
+};

+ 1 - 0
coin/templates/base.html

@@ -9,6 +9,7 @@
     <link rel="stylesheet" href="{% static "css/illyse.css" %}" />
     <link rel="stylesheet" href="{% static "css/offcanvas.css" %}">
     <script src="{% static "js/vendor/modernizr.js" %}"></script>
+    <script src="{% static "js/illyse.js" %}"></script>
     <link rel="icon" type="image/png" href="{% static "img/coinitem.png" %}"/>
     <link rel="icon" type="image/x-icon" href="{% static "img/favicon.ico" %}" />
   </head>

+ 9 - 6
coin/vpn/templates/vpn/password.html

@@ -1,8 +1,11 @@
-{% extends "base.html" %}
+{% extends "vpn/vpn.html" %}
 
-{% block content %}
-<h2>VPN password generation</h2>
-<p>Generated password for VPN <strong>{{ vpn.login }}</strong>:</p>
-<p><strong>{{ password }}</strong></p>
-<p>Don't forget it, it will only be displayed once (we don't store it in clear text).  If you forget this password, you will have to generate a new one.</p>
+{% block password %}
+                <tr id="password">
+                    <td class="center"><span class="label">Mot de passe</span></td>
+                    <td><span class="pass">{{ password }}</span></td>
+                </tr>
+                <tr>
+                    <td class="warning" colspan="2">Ce mot de passe ne sera affiché qu'une seule fois. Si vous le perdez, il faudra en générer un nouveau.</td>
+                </tr>
 {% endblock %}

+ 20 - 16
coin/vpn/templates/vpn/vpn.html

@@ -11,20 +11,20 @@
                 <tr>
                     <td class="center"><span class="label">Identifiant</span></td>
                     <td>{{object.login}}</td>
-                </tr>
+                </tr>{% block password %}
                 <tr>
                     <td class="center" colspan="2">
-                        <a class="button" href="{% url 'vpn:generate_password' object.pk %}">Générer un nouveau mot de passe</a>
+                        <a class="button" id="passgen" href="{% url 'vpn:generate_password' object.pk %}">Générer un nouveau mot de passe</a>
                     </td>
                 </tr>
-                {% if object.comment %}<tr>
-                    {% if object.comment|length < 24 %}<td class="center"><span class="label">Commentaire</span></td>
-                    <td>{% else %}<td colspan="2">{% endif %}{{object.comment}}</td>
-                </tr>{% endif %}
+                {% endblock %}<tr class="flatfield">
+                    <td class="center"><span class="label">Commentaire</span></td>
+                    <td><input type="text" value="{{object.comment}}" /></td>
+                </tr>
                 <tr>
                     <td class="center boolviewer" colspan="2">
                         <input type="checkbox" disabled="disabled"{% if object.activated %} checked="checked"{% endif %} />
-                        <span>{% if object.activated %}Ce VPN est actif{% else %}Ce VPN est inactif{% endif %}</span>
+                        <span>Ce VPN est {% if object.activated %}activé{% else %}désactivé{% endif %}</span>
                     </td>
                 </tr>
             </table>
@@ -35,6 +35,14 @@
         <div class="panel">
             <h3>Adresses IP</h3>
             <table class="full-width">
+                <tr class="flatfield">
+                    <td class="center"><span class="label">IPv4</span></td>
+                    <td><input type="text" name="endpoint4" {% if object.ipv4_endpoint %}value="{{ object.ipv4_endpoint }}" {% endif %} placeholder="Aucune adresse"/></td>
+                </tr>
+                <tr class="flatfield">
+                    <td class="center"><span class="label">IPv6</span></td>
+                    <td><input type="text" name="endpoint6" {% if object.ipv6_endpoint %}value="{{ object.ipv6_endpoint }}" {% endif %} placeholder="Aucune adresse"/></td>
+                </tr>
                 <tr>
                     <td class="center"><span class="label">Sous-réseaux</span></td>
                     <td>
@@ -43,18 +51,14 @@
                         </ul>{% else %}<span class="italic">Aucune adresse</span>{% endif %}
                     </td>
                 </tr>
-                <tr>
-                    <td class="center"><span class="label">Sorties</span></td>
-                    <td>
-                        {% if object.ipv4_endpoint or object.ipv6_endpoint %}<ul>
-                            {% if object.ipv4_endpoint %}<li>{{ object.ipv4_endpoint }}</li>{% endif %}
-                            {% if object.ipv6_endpoint %}<li>{{ object.ipv6_endpoint }}</li>{% endif %}
-                        </ul>{% else %}<span class="italic">Aucune adresse</span>{% endif %}
-                    </td>
-                </tr>
             </table>
         </div>
     </div>
 </div>
 
+<div class="row">
+    <h3 class="graphtitle">Graphe de trafic sur <span id="trafic_zoom">24 heures</span> :</h3>
+    <img id="trafic_graph" src="{% url 'vpn:get_graph' vpn_id=object.pk %}" alt="Graphe de trafic {{ object.login }}" />
+</div>
+
 {% endblock %}

+ 4 - 2
coin/vpn/urls.py

@@ -1,10 +1,12 @@
 from django.conf.urls import patterns, url
-from coin.vpn.views import VPNView, generate_password
+from coin.vpn.views import VPNView, VPNGeneratePasswordView, get_graph
 
 urlpatterns = patterns(
     '',
     # This is part of the generic configuration interface (the "name" is
     # the same as the "backend_name" of the model).
     url(r'^(?P<id>\d+)$', VPNView.as_view(template_name="vpn/vpn.html"), name="details"),
-    url(r'^password/(?P<id>\d+)$', generate_password, name="generate_password"),
+    url(r'^password/(?P<id>\d+)$', VPNGeneratePasswordView.as_view(template_name="vpn/password.html"), name="generate_password"),
+    url(r'^graph/(?P<vpn_id>[0-9]+)/(?P<period>[a-z]+)$', get_graph, name="get_graph"),
+    url(r'^graph/(?P<vpn_id>[0-9]+)$', get_graph, name="get_graph"),
 )

+ 42 - 0
coin/vpn/views.py

@@ -1,11 +1,17 @@
+import os
+from urllib2 import urlopen
+
 from django.contrib.auth.models import User
+from django.http import StreamingHttpResponse
 from django.shortcuts import render_to_response, get_object_or_404
 from django.views.generic.detail import DetailView
+from django.conf import settings
 
 from coin.vpn.models import VPNConfiguration
 
 
 class VPNView(DetailView):
+
     def get_object(self):
         return get_object_or_404(VPNConfiguration, pk=self.kwargs.get("id"),
                                  offersubscription__member__user=self.request.user)
@@ -24,3 +30,39 @@ def generate_password(request, id):
     vpn.save()
     return render_to_response('vpn/password.html', {"vpn": vpn,
                                                     "password": password})
+
+
+class VPNGeneratePasswordView(VPNView):
+    """This generates a random password, saves it in hashed form, and returns
+    it to the user in cleartext.
+    """
+
+    def get_context_data(self, **kwargs):
+        context = super(VPNGeneratePasswordView, self).get_context_data(**kwargs)
+        # Generate a new random password and save it
+        password = User.objects.make_random_password()
+        self.object.password = password
+        # This will hash the password automatically
+        self.object.full_clean()
+        self.object.save()
+        context['password'] = password
+        return context
+
+
+def get_graph(request, vpn_id, period="daily"):
+    """ This get the graph for the associated vpn_id and time period
+    """
+    vpn = get_object_or_404(VPNConfiguration, pk=vpn_id,
+                            offersubscription__member__user=request.user.id)
+    
+    time_periods = { 'hourly': '-1hour', 'daily': '-24hours', 'weekly': '-8days', 'monthly': '-32days', 'yearly': '-13months', }
+    if period not in time_periods:
+        period = 'daily'
+
+    graph_url = os.path.join(settings.GRAPHITE_SERVER,
+                "render/?width=586&height=308&from=%(period)s&" \
+                "target=alias%%28scaleToSeconds%%28vpn1.%(login)s.downrxbytes%%2C1%%29%%2C%%20%%22Download%%22%%29&" \
+                "target=alias%%28scaleToSeconds%%28vpn1.%(login)s.uptxbytes%%2C1%%29%%2C%%20%%22Upload%%22%%29&" \
+                "title=VPN%%20Usage%%20%(login)s" % \
+                    { 'period': time_periods[period], 'login': vpn.login })
+    return StreamingHttpResponse(urlopen(graph_url), content_type="image/png")