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

Revision 2032, 14.8 kB (checked in by jalet, 19 years ago)

Now dumpykota.cgi behaves like printquota.cgi wrt the REMOTE_USER environment
variables if the script is username+password protected.
Small fix in printquota.cgi wrt ldap auth with Apache : the workaround was
not used everywhere.

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