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

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

Fixed incorrect import statement

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