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

Revision 2028, 14.6 kB (checked in by jalet, 19 years ago)

Modified copyright years

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