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

Revision 2139, 15.1 kB (checked in by jerome, 19 years ago)

Added the Log keyword property

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