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

Revision 1761, 14.6 kB (checked in by jalet, 20 years ago)

Should now correctly deal with charsets both when storing into databases and when
retrieving datas. Works with both PostgreSQL and LDAP.

  • 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.37  2004/10/02 05:48:56  jalet
27# Should now correctly deal with charsets both when storing into databases and when
28# retrieving datas. Works with both PostgreSQL and LDAP.
29#
30# Revision 1.36  2004/09/02 10:34:09  jalet
31# Fixed problem with mod_auth_ldap Apache module
32#
33# Revision 1.35  2004/07/24 20:10:10  jalet
34# Incorrect number of parameters in error method
35#
36# Revision 1.34  2004/07/24 20:07:13  jalet
37# Added special Python comment to remove warning at runtime
38#
39# Revision 1.33  2004/07/21 19:24:48  jalet
40# Inversion
41#
42# Revision 1.32  2004/07/21 19:20:05  jalet
43# Missing translation in CGI script
44#
45# Revision 1.31  2004/07/21 13:32:02  jalet
46# All messages should be translatable now.
47#
48# Revision 1.30  2004/07/01 17:45:48  jalet
49# Added code to handle the description field for printers
50#
51# Revision 1.29  2004/06/06 21:07:55  jalet
52# Improved CGI script to allow history on printers and hostnames.
53# Better (?) colors in stylesheet.
54#
55# Revision 1.28  2004/06/05 22:42:41  jalet
56# Improved web history reports
57#
58# Revision 1.27  2004/05/26 14:49:40  jalet
59# First try at saving the job-originating-hostname in the database
60#
61# Revision 1.26  2004/03/24 19:37:04  jalet
62# Doesn't retrieve users or printers objects to display the history,
63# this is not needed, and saves a lot of time (and database queries
64# if storagecahing is disabled)
65#
66# Revision 1.25  2004/01/12 15:28:45  jalet
67# Now can output the user's history on several printers at the same time.
68#
69# Revision 1.24  2004/01/12 14:52:03  jalet
70# Cuts the date string
71#
72# Revision 1.23  2004/01/12 14:35:01  jalet
73# Printing history added to CGI script.
74#
75# Revision 1.22  2004/01/09 07:58:53  jalet
76# Changed URL to PyKota's logo
77#
78# Revision 1.21  2004/01/08 14:10:32  jalet
79# Copyright year changed.
80#
81# Revision 1.20  2004/01/07 16:07:17  jalet
82# The stylesheet is again expected to be local, it was a bad idea to use
83# the one on my server.
84#
85# Revision 1.19  2004/01/06 16:05:45  jalet
86# Will now search the stylesheet on my own website.
87#
88# Revision 1.18  2003/12/27 16:49:25  uid67467
89# Should be ok now.
90#
91# Revision 1.16  2003/12/02 14:40:20  jalet
92# Some code refactoring.
93# New HTML reporter added, which is now used in the CGI script for web based
94# print quota reports. It will need some de-uglyfication though...
95#
96# Revision 1.15  2003/10/24 22:06:42  jalet
97# Initial support for browser's language preference added.
98#
99# Revision 1.14  2003/10/10 19:48:07  jalet
100# Now displays version number
101#
102# Revision 1.13  2003/08/25 11:23:05  jalet
103# More powerful CGI script for quota reports
104#
105# Revision 1.12  2003/07/29 20:55:17  jalet
106# 1.14 is out !
107#
108# Revision 1.11  2003/07/01 12:37:31  jalet
109# Nicer UI
110#
111# Revision 1.10  2003/07/01 07:30:32  jalet
112# Message changed.
113#
114# Revision 1.9  2003/06/30 13:47:26  jalet
115# Allows multiple user / group names masks in the input field
116#
117# Revision 1.8  2003/06/30 13:32:01  jalet
118# Much more powerful CGI script for quota reports
119#
120# Revision 1.7  2003/06/30 12:46:15  jalet
121# Extracted reporting code.
122#
123# Revision 1.6  2003/04/23 22:13:56  jalet
124# Preliminary support for LPRng added BUT STILL UNTESTED.
125#
126# Revision 1.5  2003/04/17 21:30:09  jalet
127# Now includes the logo
128#
129# Revision 1.4  2003/04/08 21:20:25  jalet
130# CGI Script now displays a link to PyKota's website.
131#
132# Revision 1.3  2003/03/29 13:45:27  jalet
133# GPL paragraphs were incorrectly (from memory) copied into the sources.
134# Two README files were added.
135# Upgrade script for PostgreSQL pre 1.01 schema was added.
136#
137# Revision 1.2  2003/02/12 11:31:51  jalet
138# doesn't use the jaxml module anymore
139#
140# Revision 1.1  2003/02/10 13:41:38  jalet
141# repykota cgi script added.
142# cleaner doc.
143#
144
145import sys
146import os
147import cgi
148import urllib
149
150from pykota import version
151from pykota.tool import PyKotaTool, PyKotaToolError
152from pykota.reporter import PyKotaReporterError, openReporter
153
154header = """Content-type: text/html
155
156<?xml version="1.0" encoding="iso-8859-1"?>
157<html>
158  <head>
159    <title>%s</title>
160    <link rel="stylesheet" type="text/css" href="/pykota.css" />
161  </head>
162  <body>
163    <form action="printquota.cgi" method="POST">
164      <table>
165        <tr>
166          <td>
167            <p>
168              <a href="http://www.librelogiciel.com/software/"><img src="http://www.librelogiciel.com/software/PyKota/pykota.png" alt="PyKota's Logo" /></a>
169              <br />
170              <a href="http://www.librelogiciel.com/software/">PyKota v%s</a>
171            </p>
172          </td>
173          <td colspan="2">
174            <h1>%s</h1>
175          </td>
176        </tr>
177        <tr>
178          <td colspan="3" align="center">
179            <input type="submit" name="action" value="%s" />
180          </td>
181        </tr>
182      </table>"""
183   
184footer = """
185      <table>
186        <tr>
187          <td colspan="3" align="center">
188            <input type="submit" name="action" value="%s" />
189          </td>
190        </tr>
191      </table> 
192    </form>
193  </body>
194</html>""" 
195
196def getLanguagePreference() :
197    """Returns the preferred language."""
198    languages = os.environ.get("HTTP_ACCEPT_LANGUAGE", "")
199    langs = [l.strip().split(';')[0] for l in languages.split(",")]
200    return "%s_%s" % (langs[0], langs[0].upper())
201   
202def getCharsetPreference() :
203    """Returns the preferred charset."""
204    charsets = os.environ.get("HTTP_ACCEPT_CHARSET", "no charset defined")
205    charsets = [l.strip().split(';')[0] for l in charsets.split(",")]
206    return charsets[0]
207
208class PyKotaReportGUI(PyKotaTool) :
209    """PyKota Administrative GUI"""
210    def guiDisplay(self) :
211        """Displays the administrative interface."""
212        global header, footer
213        print header % (_("PyKota Reports"), version.__version__, _("PyKota Reports"), _("Report"))
214        print self.body
215        print footer % _("Report")
216       
217    def error(self, message) :
218        """Adds an error message to the GUI's body."""
219        if message :
220            self.body = '<p><font color="red">%s</font></p>\n%s' % (message, self.body)
221       
222    def htmlListPrinters(self, selected=[], mask="*") :   
223        """Displays the printers multiple selection list."""
224        printers = self.storage.getMatchingPrinters(mask)
225        selectednames = [p.Name for p in selected]
226        message = '<table><tr><td valign="top">Printer :</td><td valign="top"><select name="printers" multiple="multiple">'
227        for printer in printers :
228            if printer.Name in selectednames :
229                message += '<option value="%s" selected="selected">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
230            else :
231                message += '<option value="%s">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
232        message += '</select></td></tr></table>'
233        return message
234       
235    def htmlUGNamesInput(self, value="*") :   
236        """Input field for user/group names wildcard."""
237        return _("User / Group names mask") + (' : <input type="text" name="ugmask" size="20" value="%s" /> <em>e.g. <strong>jo*</strong></em>' % (value or "*"))
238       
239    def htmlGroupsCheckbox(self, isgroup=0) :
240        """Groups checkbox."""
241        if isgroup :
242            return _("Groups report") + ' : <input type="checkbox" checked="checked" name="isgroup" />'
243        else :   
244            return _("Groups report") + ' : <input type="checkbox" name="isgroup" />'
245           
246    def guiAction(self) :
247        """Main function"""
248        printers = ugmask = isgroup = None
249        self.body = "<p>Please click on the button above</p>\n"
250        if self.form.has_key("action") :
251            action = self.form["action"].value
252            if action == _("Report") :
253                if self.form.has_key("printers") :
254                    printersfield = self.form["printers"]
255                    if type(printersfield) != type([]) :
256                        printersfield = [ printersfield ]
257                    printers = [self.storage.getPrinter(p.value) for p in printersfield]
258                else :   
259                    printers = self.storage.getMatchingPrinters("*")
260                remuser = os.environ.get("REMOTE_USER", "root")   
261               
262                # special hack to accomodate mod_auth_ldap Apache module
263                try :
264                    remuser = remuser.split("=")[1].split(",")[0]
265                except IndexError :   
266                    pass
267               
268                if remuser == "root" :
269                    if self.form.has_key("ugmask") :     
270                        ugmask = self.form["ugmask"].value
271                    else :     
272                        ugmask = "*"
273                else :       
274                    if self.form.has_key("isgroup") :   
275                        user = self.storage.getUser(remuser)
276                        if user.Exists :
277                            ugmask = " ".join([ g.Name for g in self.storage.getUserGroups(user) ])
278                        else :   
279                            ugmask = remuser # result will probably be empty, we don't care
280                    else :   
281                        ugmask = remuser
282                if self.form.has_key("isgroup") :   
283                    isgroup = 1
284                else :   
285                    isgroup = 0
286            else :
287                self.error("Invalid action [%s]" % action)
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.