Commit f61e5158 authored by Vincent Le gallic's avatar Vincent Le gallic

Création de l'app impression*s*

 Pour l'instant, ne permet pas d'imprimer quoi que ce soit.
 Permet de lister les impressions dans la lpq et les impressions déjà terminées.
 À terme, permettra également de voir celles en cours sur l'imprimante
  et d'annuler ses propres impressions (voire celle des autres pour les imprimeurs)
  avec recrédit automatique.
parent 470d8f0c
*.pyc
*~
default_db.sqlite
# 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 cupsId in ccups.getJobs().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"),
)
# -*- encoding: utf-8 -*-
from django.http import HttpResponse, Http404
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response
# Récupération des tâches de l'imprimante
from get_jobs_ended import get_jobs_ended
import printLib
@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:
# Attention, un intranet dirty hack fait que les users LDAP sont en login@crans.org
login = request.user.username
login = login.split("@")[0]
lpq_jobs = printLib.getJobs()
ended_jobs = get_jobs_ended()
if request.user.groups.filter(name="crans_imprimeur")==[]:
# 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 = []
# Si on est imprimeur…
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
......@@ -135,6 +135,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,23 @@ ul.icones li ul li {
clear: both;
margin: 15px 0 0;
}
/* ******************************************************************** */
/* 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;
}
{% 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 liste d'impressions de zamok</caption>
<tr><th>Rang</th> <th>Login</th> <th>Fichier</th></tr>
{% for job in lpq_jobs %}
<tr class="{% cycle 'pair' 'impair' %}">
<td>{{ job.ordre }}</td>
<td>{{ job.login }}</td>
<td>{{ job.file }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<p>Pas de tâche en attente dans la liste d'impressions sur zamok.</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,7 @@
</head>
<body>
<div id="mainTitle">{% block h1 %}<h1>Crans Intranet</h1>{% endblock %}</div>
{% block precontent %}{% endblock %}
<div class="main_div">
{% block content %}{% endblock %}
</div>
......
......@@ -10,7 +10,7 @@ from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(''
urlpatterns = patterns('',
# Les pages existantes
url('^$', 'intranet.accueil.view'),
# Pages de login
......
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