Commit 8b83f3de authored by Vincent Le gallic's avatar Vincent Le gallic

Merge branch 'devel_vo' of git+ssh://git.crans.org/git/intranet into devel_vo

parents 468a4f0f 7f631aaa
*.pyc
*~
default_db.sqlite
Pour faire marcher l'intranet :
* passer DEV à True dans settings.py
* changer la ligne MAIN_PATH = '/home/toto/Crans/' dans settings.py
* exécuter ./manage.py syncdb
# On ne veut pas giter le fichier de stockage temporaire du csv
ended_jobs.csv
#!/usr/bin/python
# -*- encoding: utf-8 -*-
# Codé par 20-100
# Pour récupérer et parser les jobs dans le journal de l'imprimante
import urllib2
import printLib
import os, os.path
import time
import settings
ROOT_PAGE = "https://imprimante.adm.crans.org"
STORE_FILE = settings.ROOT_PATH + "apps/impressions/ended_jobs.csv"
store_timeout = 2*60
def get_cookie():
"""Récupère le cookie"""
page = urllib2.urlopen(ROOT_PAGE)
return page.headers["set-cookie"]
def get_csv(cookie):
"""Récupère le fichier csv des jobs.
Utilise un fichier local s'il est assez récent"""
fetch = True
try:
mdate = os.path.getmtime(STORE_FILE)
if mdate + store_timeout > time.time():
fetch = False
except Exception as e:
pass
if fetch:
opener = urllib2.build_opener()
opener.addheaders.append(('Cookie', cookie))
fichier = opener.open("https://imprimante.adm.crans.org/pprint.csv?Flag=Csv_Data&LogType=0")
text = fichier.read()
store = open(STORE_FILE, "w")
store.write(text)
store.close()
else:
store = open(STORE_FILE)
text = store.read()
return text
def parse_csv(csv_text):
"""Parse le fichier texte et renvoie une liste d'objets EndedJob"""
liste = []
for ligne in csv_text.split("\n")[1:-1]:
ligne = ligne.split(',')
if len(ligne) == 13:
_, result, jobname, util, _, starttime, endtime, _, _, _, _, _, _ = [i.strip('"') for i in ligne]
if util != "DIRECT PRINT":
try:
liste.append(printLib.EndedJob(jobname, result, starttime, endtime))
except NotImplementedError:
pass
return liste
def get_jobs_ended():
cook = get_cookie()
f = get_csv(cook)
return parse_csv(f)
if __name__ == "__main__":
print get_jobs_ended()
from django.db import models
# Create your models here.
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import cups
import datetime
import time
import re
import sys
sys.path.append('/usr/scripts/gestion/')
import ldap_crans
sys.path.append('/etc/crans/secrets/')
import secrets
cldap = ldap_crans.CransLdap()
cups.setUser('lp')
cups.setPasswordCB(lambda _: secrets.lp_pass)
cups.setServer('10.231.136.1')
ccups = cups.Connection()
class Job:
def __init__(self, jobname):
self.jobname = jobname
tab = jobname.split(':')
self.jid = int(tab[0])
self.login = tab[1].lower()
if self.login.startswith("club-"):
raise NotImplementedError
self.file = ":".join(tab[2:])
self.message = "N/A"
self.ordre = None
def getPrix(self):
# On récupère ceux qui n'ont pas payé cette année
adh = cldap.search('login=' + self.login)['adherent']
if len(adh) == 0:
raise ValueError('Impression introuvable')
assert(len(adh) < 2)
adh = adh[0]
for l in adh.historique():
# On récupère la date du dernier changement de chambre
# (l'historique est enregistré par ordre chronologique)
x = re.match('^(.*),.*: debit (\d+\.\d+) Euros \[impression\(%d\):.*\]' % self.jid,l)
if x <> None:
date = x.group(1)
prix = float(x.group(2))
return prix
def recreditDate(self):
adh = cldap.search('login=' + self.login)['adherent']
if len(adh) == 0:
raise ValueError('Impression introuvable: %s,%d' % (self.login,self.jid) )
assert(len(adh) < 2)
adh = adh[0]
date = None
for l in adh.historique():
# On récupère la date du dernier changement de chambre
# (l'historique est enregistré par ordre chronologique)
x = re.match('^(.*),.*: credit (\d+\.\d+) Euros \[remboursement\(%d\).*\]' % self.jid,l)
if x <> None:
date = x.group(1)
return date
def cancel(self):
raise NotImplementedError
def __repr__(self):
return repr((self.jid, self.login, self.file, self.message, self.recreditDate()))
def __str__(self):
return "%s (%d, %s)" % (self.login, self.jid, self.file)
def recrediter(self):
if self.recreditDate():
print "Déjà recrédité"
return
prix = self.getPrix()
adh = cldap.search('login=' + self.login, mode='w')['adherent'][0]
adh.solde(prix, 'remboursement(%d)' % self.jid)
adh.save()
class CupsJob(Job):
def __init__(self, state, ordre=None):
Job.__init__(self, state['job-name'])
self.state = state
self.message = state.get('job-printer-state-message','N/A')
self.ordre = ordre
def cancel(self):
ccups.cancelJob(self.state['job-id'])
def getJobs():
jobs = []
count = 1
for trying in range(3):
# La connexion avec le serveur cup a tendance à planter, du coup on essaye plusieurs fois
try:
cupsjobs = ccups.getJobs()
break
except:
pass
for cupsId in cupsjobs.iterkeys():
attr = ccups.getJobAttributes(cupsId)
if attr['job-state'] == cups.IPP_JOB_CANCELED:
continue
jobs.append(CupsJob(attr, count))
count += 1
return jobs
class EndedJob(Job):
def __init__(self, jobname, result, starttime, endtime):
Job.__init__(self, jobname)
self.result = result
self.starttime = time.strftime("%F %T",
time.strptime(starttime, "%d/%m %Y %H:%M:%S"))
self.endtime = time.strftime("%F %T",
time.strptime(endtime, "%d/%m %Y %H:%M:%S"))
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}
from django.conf.urls.defaults import patterns, url
import views
urlpatterns = patterns('',
url('^$', views.view, name="view"),
url('^gestion/$', views.gestion, name="gestion"),
url('^gestion/delete/(?P<jid>[^/]*)/$', views.delete_job, name="delete"),
)
# -*- encoding: utf-8 -*-
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
# Pour stocker des messages dans la session courante
from django.contrib import messages
# Récupération des tâches de l'imprimante
from get_jobs_ended import get_jobs_ended
import printLib
def get_login(request):
"""Renvoie le login de l'utilisateur connecté"""
# Attention, un intranet dirty hack fait que les users LDAP sont en login@crans.org
login = request.user.username
login = login.split("@")[0]
return login
def is_imprimeur(request):
"""Renvoie True si l'utilisateur connecté à les droits imprimeurs"""
li = request.user.groups.filter(name="crans_imprimeur")
return len(li)!=0
@login_required
def view(request):
try:
return render_to_response("impressions/impressions.html",\
{'random_variable': "rien du tout"},\
context_instance=RequestContext(request))
except ValueError:
raise Http404
@login_required
def gestion(request):
try:
login = get_login(request)
lpq_jobs = printLib.getJobs()
ended_jobs = get_jobs_ended()
if not is_imprimeur(request):
# Si on n'est pas imprimeur, on ne garde que les taches de l'utilisateur courant
ended_jobs = [i for i in ended_jobs if i.login == login]
lpq_jobs = [i for i in lpq_jobs if i.login == login]
imprimante_jobs = []
return render_to_response("impressions/liste.html",
{"ended_jobs" : ended_jobs,
"lpq_jobs" : lpq_jobs,
"imprimante_jobs" : imprimante_jobs},
context_instance=RequestContext(request))
except ValueError:
raise Http404
@login_required
def delete_job(request, jid=-1):
lpq_jobs = printLib.getJobs()
# On récupère le job
try:
jid = int(jid)
except:
pass
lpq_jobs = [job for job in lpq_jobs if job.jid == jid]
if lpq_jobs == []:
messages.error(request, u"Cette tâche n'est plus dans la file d'attente du serveur.")
else:
job = lpq_jobs[0]
if job.login == get_login(request) or is_imprimeur(request):
job.cancel()
job.recrediter()
messages.success(request, u"La tâche %s a été annulée." % (job.file))
else:
messages.error(request, u"Vous n'êtes pas le propriétaire de cette tâche, vous ne pouvez pas l'annuler.")
return HttpResponseRedirect("/impressions/gestion/")
......@@ -6,6 +6,7 @@ import sys
sys.path.append("/etc/crans/secrets")
DEBUG = True
DEV = False
TEMPLATE_DEBUG = DEBUG
EMAIL_SUBJECT_PREFIX = "[Intranet2 Cr@ns] "
......@@ -19,14 +20,20 @@ ADMINS = (
MANAGERS = ADMINS
ROOT_PATH='/localhome/django/intranet/'
DB_PATH='/localhome/django/local_db/'
if DEV:
MAIN_PATH = '/home/toto/Crans/'
DB_PATH = MAIN_PATH + 'intranet/default_db.sqlite'
else:
MAIN_PATH = '/localhome/django/'
DB_PATH = MAIN_PATH + 'local_dl/default'
ROOT_PATH = MAIN_PATH + 'intranet/'
FIXTURE_DIRS=(ROOT_PATH + 'fixtures/',)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': DB_PATH + 'default',
'NAME': DB_PATH,
},
}
......@@ -130,6 +137,11 @@ INTRANET_APPS = (
'category': 'Services',
'test': (lambda u: u.groups.filter(name='crans_nounou') or u.groups.filter(name='crans_apprenti')),
},
{
'name':'impressions',
'category': 'Services',
'test': (lambda u: True),
},
{
'name':'wifimap',
'category': 'Services',
......
......@@ -147,3 +147,36 @@ ul.icones li ul li {
clear: both;
margin: 15px 0 0;
}
/* Les messages d'erreur */
.errors li.error {
color: red;
font-weight: bold;
}
.errors li.success {
color: green;
font-weight: bold;
}
/* ******************************************************************** */
/* IMPRESSIONS */
table.liste_impression {
background-color: white;
border: 1px solid black;
padding-bottom: 5px;
border-radius: 12px;
}
table.liste_impression tr.pair td {
background-color: #dad6ef;
}
table.liste_impression tr.impair td {
background-color: transparent;
}
table.liste_impression td.centre {
text-align: center;
}
{% extends "template.html" %}
{% load full_name %}
{% block title %}Impressions Cr@ns{% endblock %}
{% block head %}{% endblock %}
{% block h1 %}<h1>Interface d'impression</h1>{% endblock %}
{% extends "impressions/base.html" %}
{% block precontent %}<a href="gestion/">Liste des tâches</a>{% endblock %}
{% block content %}Y U NO PRINT ?!{% endblock %}
{% extends "impressions/base.html" %}
{% block title %}{{ block.super }} : Liste des tâches{% endblock %}
{% block h1 %}{{block.super}}<h2> Liste des tâches </h2>{% endblock %}
{% block content %}
{% if lpq_jobs %}
<table class="liste_impression">
<caption>Listes des tâches dans la file d'attente du serveur</caption>
<tr><th>Rang</th> <th>Login</th> <th>Fichier</th> <th>Annuler</th></tr>
{% for job in lpq_jobs %}
<tr class="{% cycle 'pair' 'impair' %}">
<td class="centre">{{ job.ordre }}</td>
<td>{{ job.login }}</td>
<td>{{ job.file }}</td>
<td class="centre"><a href="/impressions/gestion/delete/{{ job.jid }}">X</a></td>
</tr>
{% endfor %}
</table>
{% else %}
<p>Pas de tâche dans la file d'attente du serveur.</p>
{% endif %}
{% if ended_jobs %}
<table class="liste_impression">
<caption>Listes des tâches terminées</caption>
<tr><th>Login</th> <th>Fichier</th> <th>Commencé</th> <th>Terminé</th></tr>
{% for job in ended_jobs %}
<tr class="{% cycle 'pair' 'impair' %}">
<td>{{ job.login }}</td>
<td>{{ job.file }}</td>
<td>{{ job.starttime }}</td>
<td>{{ job.endtime }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>Pas de tâche terminée en mémoire.</p>
{% endif %}
{% endblock %}
......@@ -8,6 +8,16 @@
</head>
<body>
<div id="mainTitle">{% block h1 %}<h1>Crans Intranet</h1>{% endblock %}</div>
{% block precontent %}{% endblock %}
<div class="errors">
{% if messages %}
<ul>
{% for mess in messages %}
<li class="{{mess.tags}}">{{ mess|linebreaksbr }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="main_div">
{% block content %}{% endblock %}
</div>
......
......@@ -9,15 +9,21 @@ from utils.protectpost import protect
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Les pages existantes
url('^$', 'intranet.accueil.view'),
# Pages de login
url('^login', protect(django.contrib.auth.views.login), {'template_name': 'login.html'}, name="login"),
url('^logout', 'django.contrib.auth.views.logout_then_login', name ="logout"),
(r'^admin/', include(admin.site.urls)),
)
)
if settings.DEV:
# Quand on utilise le serveur de DEV, on veut que Django serve les static files
urlpatterns += patterns('', url('^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root':'static/'}),
)
for app in settings.INTRANET_APPS:
app = app["name"]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment