root / pykota / trunk / cgi-bin / printquota.cgi @ 1763

Revision 1763, 14.5 kB (checked in by jalet, 20 years ago)

The CGI script doesn't depend anymore on what is in the submit button
to display the print quota report.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/python
2# -*- coding: ISO-8859-15 -*-
3
4# PyKota Print Quota Reports generator
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25# $Log$
26# Revision 1.38  2004/10/02 13:47:46  jalet
27# The CGI script doesn't depend anymore on what is in the submit button
28# to display the print quota report.
29#
30# Revision 1.37  2004/10/02 05:48:56  jalet
31# Should now correctly deal with charsets both when storing into databases and when
32# retrieving datas. Works with both PostgreSQL and LDAP.
33#
34# Revision 1.36  2004/09/02 10:34:09  jalet
35# Fixed problem with mod_auth_ldap Apache module
36#
37# Revision 1.35  2004/07/24 20:10:10  jalet
38# Incorrect number of parameters in error method
39#
40# Revision 1.34  2004/07/24 20:07:13  jalet
41# Added special Python comment to remove warning at runtime
42#
43# Revision 1.33  2004/07/21 19:24:48  jalet
44# Inversion
45#
46# Revision 1.32  2004/07/21 19:20:05  jalet
47# Missing translation in CGI script
48#
49# Revision 1.31  2004/07/21 13:32:02  jalet
50# All messages should be translatable now.
51#
52# Revision 1.30  2004/07/01 17:45:48  jalet
53# Added code to handle the description field for printers
54#
55# Revision 1.29  2004/06/06 21:07:55  jalet
56# Improved CGI script to allow history on printers and hostnames.
57# Better (?) colors in stylesheet.
58#
59# Revision 1.28  2004/06/05 22:42:41  jalet
60# Improved web history reports
61#
62# Revision 1.27  2004/05/26 14:49:40  jalet
63# First try at saving the job-originating-hostname in the database
64#
65# Revision 1.26  2004/03/24 19:37:04  jalet
66# Doesn't retrieve users or printers objects to display the history,
67# this is not needed, and saves a lot of time (and database queries
68# if storagecahing is disabled)
69#
70# Revision 1.25  2004/01/12 15:28:45  jalet
71# Now can output the user's history on several printers at the same time.
72#
73# Revision 1.24  2004/01/12 14:52:03  jalet
74# Cuts the date string
75#
76# Revision 1.23  2004/01/12 14:35:01  jalet
77# Printing history added to CGI script.
78#
79# Revision 1.22  2004/01/09 07:58:53  jalet
80# Changed URL to PyKota's logo
81#
82# Revision 1.21  2004/01/08 14:10:32  jalet
83# Copyright year changed.
84#
85# Revision 1.20  2004/01/07 16:07:17  jalet
86# The stylesheet is again expected to be local, it was a bad idea to use
87# the one on my server.
88#
89# Revision 1.19  2004/01/06 16:05:45  jalet
90# Will now search the stylesheet on my own website.
91#
92# Revision 1.18  2003/12/27 16:49:25  uid67467
93# Should be ok now.
94#
95# Revision 1.16  2003/12/02 14:40:20  jalet
96# Some code refactoring.
97# New HTML reporter added, which is now used in the CGI script for web based
98# print quota reports. It will need some de-uglyfication though...
99#
100# Revision 1.15  2003/10/24 22:06:42  jalet
101# Initial support for browser's language preference added.
102#
103# Revision 1.14  2003/10/10 19:48:07  jalet
104# Now displays version number
105#
106# Revision 1.13  2003/08/25 11:23:05  jalet
107# More powerful CGI script for quota reports
108#
109# Revision 1.12  2003/07/29 20:55:17  jalet
110# 1.14 is out !
111#
112# Revision 1.11  2003/07/01 12:37:31  jalet
113# Nicer UI
114#
115# Revision 1.10  2003/07/01 07:30:32  jalet
116# Message changed.
117#
118# Revision 1.9  2003/06/30 13:47:26  jalet
119# Allows multiple user / group names masks in the input field
120#
121# Revision 1.8  2003/06/30 13:32:01  jalet
122# Much more powerful CGI script for quota reports
123#
124# Revision 1.7  2003/06/30 12:46:15  jalet
125# Extracted reporting code.
126#
127# Revision 1.6  2003/04/23 22:13:56  jalet
128# Preliminary support for LPRng added BUT STILL UNTESTED.
129#
130# Revision 1.5  2003/04/17 21:30:09  jalet
131# Now includes the logo
132#
133# Revision 1.4  2003/04/08 21:20:25  jalet
134# CGI Script now displays a link to PyKota's website.
135#
136# Revision 1.3  2003/03/29 13:45:27  jalet
137# GPL paragraphs were incorrectly (from memory) copied into the sources.
138# Two README files were added.
139# Upgrade script for PostgreSQL pre 1.01 schema was added.
140#
141# Revision 1.2  2003/02/12 11:31:51  jalet
142# doesn't use the jaxml module anymore
143#
144# Revision 1.1  2003/02/10 13:41:38  jalet
145# repykota cgi script added.
146# cleaner doc.
147#
148
149import sys
150import os
151import cgi
152import urllib
153
154from pykota import version
155from pykota.tool import PyKotaTool, PyKotaToolError
156from pykota.reporter import PyKotaReporterError, openReporter
157
158header = """Content-type: text/html
159
160<?xml version="1.0" encoding="%s"?>
161<html>
162  <head>
163    <title>%s</title>
164    <link rel="stylesheet" type="text/css" href="/pykota.css" />
165  </head>
166  <body>
167    <form action="printquota.cgi" method="POST">
168      <table>
169        <tr>
170          <td>
171            <p>
172              <a href="http://www.librelogiciel.com/software/"><img src="http://www.librelogiciel.com/software/PyKota/pykota.png" alt="PyKota's Logo" /></a>
173              <br />
174              <a href="http://www.librelogiciel.com/software/">PyKota v%s</a>
175            </p>
176          </td>
177          <td colspan="2">
178            <h1>%s</h1>
179          </td>
180        </tr>
181        <tr>
182          <td colspan="3" align="center">
183            <input type="submit" name="report" value="%s" />
184          </td>
185        </tr>
186      </table>"""
187   
188footer = """
189      <table>
190        <tr>
191          <td colspan="3" align="center">
192            <input type="submit" name="report" value="%s" />
193          </td>
194        </tr>
195      </table> 
196    </form>
197  </body>
198</html>""" 
199
200def getLanguagePreference() :
201    """Returns the preferred language."""
202    languages = os.environ.get("HTTP_ACCEPT_LANGUAGE", "")
203    langs = [l.strip().split(';')[0] for l in languages.split(",")]
204    return "%s_%s" % (langs[0], langs[0].upper())
205   
206def getCharsetPreference() :
207    """Returns the preferred charset."""
208    charsets = os.environ.get("HTTP_ACCEPT_CHARSET", "no charset defined")
209    charsets = [l.strip().split(';')[0] for l in charsets.split(",")]
210    return charsets[0]
211
212class PyKotaReportGUI(PyKotaTool) :
213    """PyKota Administrative GUI"""
214    def guiDisplay(self) :
215        """Displays the administrative interface."""
216        global header, footer
217        print header % (self.getCharset(), _("PyKota Reports"), version.__version__, _("PyKota Reports"), _("Report"))
218        print self.body
219        print footer % _("Report")
220       
221    def error(self, message) :
222        """Adds an error message to the GUI's body."""
223        if message :
224            self.body = '<p><font color="red">%s</font></p>\n%s' % (message, self.body)
225       
226    def htmlListPrinters(self, selected=[], mask="*") :   
227        """Displays the printers multiple selection list."""
228        printers = self.storage.getMatchingPrinters(mask)
229        selectednames = [p.Name for p in selected]
230        message = '<table><tr><td valign="top">Printer :</td><td valign="top"><select name="printers" multiple="multiple">'
231        for printer in printers :
232            if printer.Name in selectednames :
233                message += '<option value="%s" selected="selected">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
234            else :
235                message += '<option value="%s">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
236        message += '</select></td></tr></table>'
237        return message
238       
239    def htmlUGNamesInput(self, value="*") :   
240        """Input field for user/group names wildcard."""
241        return _("User / Group names mask") + (' : <input type="text" name="ugmask" size="20" value="%s" /> <em>e.g. <strong>jo*</strong></em>' % (value or "*"))
242       
243    def htmlGroupsCheckbox(self, isgroup=0) :
244        """Groups checkbox."""
245        if isgroup :
246            return _("Groups report") + ' : <input type="checkbox" checked="checked" name="isgroup" />'
247        else :   
248            return _("Groups report") + ' : <input type="checkbox" name="isgroup" />'
249           
250    def guiAction(self) :
251        """Main function"""
252        printers = ugmask = isgroup = None
253        self.body = "<p>Please click on the button above</p>\n"
254        if self.form.has_key("report") :
255            if self.form.has_key("printers") :
256                printersfield = self.form["printers"]
257                if type(printersfield) != type([]) :
258                    printersfield = [ printersfield ]
259                printers = [self.storage.getPrinter(p.value) for p in printersfield]
260            else :   
261                printers = self.storage.getMatchingPrinters("*")
262            remuser = os.environ.get("REMOTE_USER", "root")   
263           
264            # special hack to accomodate mod_auth_ldap Apache module
265            try :
266                remuser = remuser.split("=")[1].split(",")[0]
267            except IndexError :   
268                pass
269           
270            if remuser == "root" :
271                if self.form.has_key("ugmask") :     
272                    ugmask = self.form["ugmask"].value
273                else :     
274                    ugmask = "*"
275            else :       
276                if self.form.has_key("isgroup") :   
277                    user = self.storage.getUser(remuser)
278                    if user.Exists :
279                        ugmask = " ".join([ g.Name for g in self.storage.getUserGroups(user) ])
280                    else :   
281                        ugmask = remuser # result will probably be empty, we don't care
282                else :   
283                    ugmask = remuser
284            if self.form.has_key("isgroup") :   
285                isgroup = 1
286            else :   
287                isgroup = 0
288        self.body += self.htmlListPrinters(printers or [])           
289        self.body += "<br />"
290        self.body += self.htmlUGNamesInput(ugmask)
291        self.body += "<br />"
292        self.body += self.htmlGroupsCheckbox(isgroup)
293        if not self.form.has_key("history") :
294            if printers and ugmask :
295                self.reportingtool = openReporter(admin, "html", printers, ugmask.split(), isgroup)
296                self.body += "%s" % self.reportingtool.generateReport()
297        else :       
298            remuser = os.environ.get("REMOTE_USER", "root")   
299            if remuser != "root" :
300                username = remuser
301            elif self.form.has_key("username") :   
302                username = self.form["username"].value
303            else :   
304                username = None
305            if username is not None :   
306                user = self.storage.getUser(username)
307            else :   
308                user =None
309            if self.form.has_key("printername") :
310                printer = self.storage.getPrinter(self.form["printername"].value)
311            else :   
312                printer = None
313            if self.form.has_key("datelimit") :   
314                datelimit = self.form["datelimit"].value
315            else :   
316                datelimit = None
317            if self.form.has_key("hostname") :   
318                hostname = self.form["hostname"].value
319            else :   
320                hostname = None
321            self.report = ["<h2>%s</h2>" % _("History")]   
322            history = self.storage.retrieveHistory(user, printer, datelimit, hostname)
323            if not history :
324                self.report.append("<h3>%s</h3>" % _("Empty"))
325            else :
326                self.report.append('<table class="pykotatable" border="1">')
327                headers = [_("Date"), _("Action"), _("User"), _("Printer"), _("Hostname"), _("JobId"), _("JobSize"), _("JobPrice"), _("Copies"), _("JobBytes"), _("PageCounter"), _("Title"), _("Filename"), _("Options")]
328                self.report.append('<tr class="pykotacolsheader">%s</tr>' % "".join(["<th>%s</th>" % h for h in headers]))
329                oddeven = 0
330                for job in history :
331                    oddeven += 1
332                    if oddeven % 2 :
333                        oddevenclass = "odd"
334                    else :   
335                        oddevenclass = "even"
336                    if job.JobAction == "DENY" :
337                        oddevenclass = "deny"
338                    elif job.JobAction == "WARN" :   
339                        oddevenclass = "warn"
340                    username_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "username" : job.UserName}), job.UserName)
341                    printername_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "printername" : job.PrinterName}), job.PrinterName)
342                    if job.JobHostName :
343                        hostname_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "hostname" : job.JobHostName}), job.JobHostName)
344                    else :   
345                        hostname_url = None
346                    self.report.append('<tr class="%s">%s</tr>' % (oddevenclass, "".join(["<td>%s</td>" % (h or "&nbsp;") for h in (job.JobDate[:19], job.JobAction, username_url, printername_url, hostname_url, job.JobId, job.JobSize, job.JobPrice, job.JobCopies, job.JobSizeBytes, job.PrinterPageCounter, job.JobTitle, job.JobFileName, job.JobOptions)])))
347                self.report.append('</table>')
348                dico = { "history" : 1,
349                         "datelimit" : job.JobDate,
350                       }
351                if user and user.Exists :
352                    dico.update({ "username" : user.Name })
353                if printer and printer.Exists :
354                    dico.update({ "printername" : printer.Name })
355                if hostname :   
356                    dico.update({ "hostname" : hostname })
357                prevurl = "%s?%s" % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode(dico))
358                self.report.append('<a href="%s">%s</a>' % (prevurl, _("Previous page")))
359            self.body = "\n".join(self.report)   
360           
361if __name__ == "__main__" :
362    os.environ["LC_ALL"] = getLanguagePreference()
363    admin = PyKotaReportGUI(lang=os.environ["LC_ALL"], charset=getCharsetPreference())
364    admin.form = cgi.FieldStorage()
365    admin.guiAction()
366    admin.guiDisplay()
367    try :
368        admin.storage.close()
369    except (TypeError, NameError, AttributeError) :   
370        pass
371       
372    sys.exit(0)
Note: See TracBrowser for help on using the browser.