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

Revision 1524, 12.1 kB (checked in by jalet, 20 years ago)

Improved web history reports

  • 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
3# PyKota Print Quota Reports generator
4#
5# PyKota - Print Quotas for CUPS and LPRng
6#
7# (c) 2003-2004 Jerome Alet <alet@librelogiciel.com>
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21#
22# $Id$
23#
24# $Log$
25# Revision 1.28  2004/06/05 22:42:41  jalet
26# Improved web history reports
27#
28# Revision 1.27  2004/05/26 14:49:40  jalet
29# First try at saving the job-originating-hostname in the database
30#
31# Revision 1.26  2004/03/24 19:37:04  jalet
32# Doesn't retrieve users or printers objects to display the history,
33# this is not needed, and saves a lot of time (and database queries
34# if storagecahing is disabled)
35#
36# Revision 1.25  2004/01/12 15:28:45  jalet
37# Now can output the user's history on several printers at the same time.
38#
39# Revision 1.24  2004/01/12 14:52:03  jalet
40# Cuts the date string
41#
42# Revision 1.23  2004/01/12 14:35:01  jalet
43# Printing history added to CGI script.
44#
45# Revision 1.22  2004/01/09 07:58:53  jalet
46# Changed URL to PyKota's logo
47#
48# Revision 1.21  2004/01/08 14:10:32  jalet
49# Copyright year changed.
50#
51# Revision 1.20  2004/01/07 16:07:17  jalet
52# The stylesheet is again expected to be local, it was a bad idea to use
53# the one on my server.
54#
55# Revision 1.19  2004/01/06 16:05:45  jalet
56# Will now search the stylesheet on my own website.
57#
58# Revision 1.18  2003/12/27 16:49:25  uid67467
59# Should be ok now.
60#
61# Revision 1.16  2003/12/02 14:40:20  jalet
62# Some code refactoring.
63# New HTML reporter added, which is now used in the CGI script for web based
64# print quota reports. It will need some de-uglyfication though...
65#
66# Revision 1.15  2003/10/24 22:06:42  jalet
67# Initial support for browser's language preference added.
68#
69# Revision 1.14  2003/10/10 19:48:07  jalet
70# Now displays version number
71#
72# Revision 1.13  2003/08/25 11:23:05  jalet
73# More powerful CGI script for quota reports
74#
75# Revision 1.12  2003/07/29 20:55:17  jalet
76# 1.14 is out !
77#
78# Revision 1.11  2003/07/01 12:37:31  jalet
79# Nicer UI
80#
81# Revision 1.10  2003/07/01 07:30:32  jalet
82# Message changed.
83#
84# Revision 1.9  2003/06/30 13:47:26  jalet
85# Allows multiple user / group names masks in the input field
86#
87# Revision 1.8  2003/06/30 13:32:01  jalet
88# Much more powerful CGI script for quota reports
89#
90# Revision 1.7  2003/06/30 12:46:15  jalet
91# Extracted reporting code.
92#
93# Revision 1.6  2003/04/23 22:13:56  jalet
94# Preliminary support for LPRng added BUT STILL UNTESTED.
95#
96# Revision 1.5  2003/04/17 21:30:09  jalet
97# Now includes the logo
98#
99# Revision 1.4  2003/04/08 21:20:25  jalet
100# CGI Script now displays a link to PyKota's website.
101#
102# Revision 1.3  2003/03/29 13:45:27  jalet
103# GPL paragraphs were incorrectly (from memory) copied into the sources.
104# Two README files were added.
105# Upgrade script for PostgreSQL pre 1.01 schema was added.
106#
107# Revision 1.2  2003/02/12 11:31:51  jalet
108# doesn't use the jaxml module anymore
109#
110# Revision 1.1  2003/02/10 13:41:38  jalet
111# repykota cgi script added.
112# cleaner doc.
113#
114
115import sys
116import os
117import cgi
118import urllib
119
120from pykota import version
121from pykota.tool import PyKotaTool, PyKotaToolError
122from pykota.reporter import PyKotaReporterError, openReporter
123
124header = """Content-type: text/html
125
126<?xml version="1.0" encoding="iso-8859-1"?>
127<html>
128  <head>
129    <title>PyKota Reports</title>
130    <link rel="stylesheet" type="text/css" href="/pykota.css" />
131  </head>
132  <body>
133    <form action="printquota.cgi" method="POST">
134      <table>
135        <tr>
136          <td>
137            <p>
138              <a href="http://www.librelogiciel.com/software/"><img src="http://www.librelogiciel.com/software/PyKota/pykota.png" alt="PyKota's Logo" /></a>
139              <br />
140              <a href="http://www.librelogiciel.com/software/">PyKota version %s</a>
141            </p>
142          </td>
143          <td colspan="2">
144            <h1>PyKota Reports</h1>
145          </td>
146        </tr>
147        <tr>
148          <td colspan="3" align="center">
149            <input type="submit" name="action" value="Report" />
150          </td>
151        </tr>
152      </table>"""
153   
154footer = """
155    </form>
156  </body>
157</html>""" 
158
159def getLanguagePreference() :
160    """Returns the preferred language."""
161    languages = os.environ.get("HTTP_ACCEPT_LANGUAGE", "")
162    langs = [l.strip().split(';')[0] for l in languages.split(",")]
163    return "%s_%s" % (langs[0], langs[0].upper())
164
165class PyKotaReportGUI(PyKotaTool) :
166    """PyKota Administrative GUI"""
167       
168    def guiDisplay(self) :
169        """Displays the administrative interface."""
170        global header, footer
171        print header % version.__version__
172        print self.body
173        print footer
174       
175    def error(self, message) :
176        """Adds an error message to the GUI's body."""
177        if message :
178            self.body = '<p><font color="red">%s</font></p>\n%s' % (message, self.body)
179       
180    def htmlListPrinters(self, selected=[], mask="*") :   
181        """Displays the printers multiple selection list."""
182        printers = self.storage.getMatchingPrinters(mask)
183        selectednames = [p.Name for p in selected]
184        message = '<table><tr><td valign="top">Printer :</td><td valign="top"><select name="printers" multiple="multiple">'
185        for printer in printers :
186            if printer.Name in selectednames :
187                message += '<option value="%s" selected="selected">%s</option>' % (printer.Name, printer.Name)
188            else :
189                message += '<option value="%s">%s</option>' % (printer.Name, printer.Name)
190        message += '</select></td></tr></table>'
191        return message
192       
193    def htmlUGNamesInput(self, value="*") :   
194        """Input field for user/group names wildcard."""
195        return 'User / Group names mask : <input type="text" name="ugmask" size="20" value="%s" /> <em>e.g. <strong>jo*</strong></em>' % (value or "*")
196       
197    def htmlGroupsCheckbox(self, isgroup=0) :
198        """Groups checkbox."""
199        if isgroup :
200            return 'Groups report : <input type="checkbox" checked="checked" name="isgroup" />'
201        else :   
202            return 'Groups report : <input type="checkbox" name="isgroup" />'
203           
204    def guiAction(self) :
205        """Main function"""
206        printers = ugmask = isgroup = None
207        self.body = "<p>Please click on the button above</p>\n"
208        if self.form.has_key("action") :
209            action = self.form["action"].value
210            if action == "Report" :
211                if self.form.has_key("printers") :
212                    printersfield = self.form["printers"]
213                    if type(printersfield) != type([]) :
214                        printersfield = [ printersfield ]
215                    printers = [self.storage.getPrinter(p.value) for p in printersfield]
216                else :   
217                    printers = self.storage.getMatchingPrinters("*")
218                remuser = os.environ.get("REMOTE_USER", "root")   
219                if remuser == "root" :
220                    if self.form.has_key("ugmask") :     
221                        ugmask = self.form["ugmask"].value
222                    else :     
223                        ugmask = "*"
224                else :       
225                    if self.form.has_key("isgroup") :   
226                        user = self.storage.getUser(remuser)
227                        if user.Exists :
228                            ugmask = " ".join([ g.Name for g in self.storage.getUserGroups(user) ])
229                        else :   
230                            ugmask = remuser # result will probably be empty, we don't care
231                    else :   
232                        ugmask = remuser
233                if self.form.has_key("isgroup") :   
234                    isgroup = 1
235                else :   
236                    isgroup = 0
237            else :
238                self.error(body, "Invalid action [%s]" % action)
239        self.body += self.htmlListPrinters(printers or [])           
240        self.body += "<br />"
241        self.body += self.htmlUGNamesInput(ugmask)
242        self.body += "<br />"
243        self.body += self.htmlGroupsCheckbox(isgroup)
244        if not self.form.has_key("history") :
245            if printers and ugmask :
246                self.reportingtool = openReporter(admin, "html", printers, ugmask.split(), isgroup)
247                self.body += "%s" % self.reportingtool.generateReport()
248        else :       
249            remuser = os.environ.get("REMOTE_USER", "root")   
250            if remuser != "root" :
251                username = remuser
252            elif self.form.has_key("username") :   
253                username = self.form["username"].value
254            else :   
255                username = None
256            if username is not None :   
257                user = self.storage.getUser(username)
258            else :   
259                user =None
260            if self.form.has_key("printername") :
261                printer = self.storage.getPrinter(self.form["printername"].value)
262            else :   
263                printer = None
264            if self.form.has_key("datelimit") :   
265                datelimit = self.form["datelimit"].value
266            else :   
267                datelimit = None
268            self.report = ["<h2>History</h2>"]   
269            history = self.storage.retrieveHistory(user, printer, datelimit)
270            if not history :
271                self.report.append("<h3>Empty</h3>")
272            else :
273                self.report.append('<table class="pykotatable" border="1">')
274                headers = ["Date", "Action", "User", "Printer", "Hostname", "JobId", "JobSize", "JobPrice", "Copies", "JobBytes", "PageCounter", "Title", "Filename", "Options"]
275                self.report.append('<tr class="pykotacolsheader">%s</tr>' % "".join(["<th>%s</th>" % h for h in headers]))
276                oddeven = 0
277                for job in history :
278                    oddeven += 1
279                    if oddeven % 2 :
280                        oddevenclass = "odd"
281                    else :   
282                        oddevenclass = "even"
283                    if job.JobAction == "DENY" :
284                        oddevenclass = "deny"
285                    elif job.JobAction == "WARN" :   
286                        oddevenclass = "warn"
287                    username = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "username" : job.UserName}), job.UserName)
288                    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, job.PrinterName, job.JobHostName, job.JobId, job.JobSize, job.JobPrice, job.JobCopies, job.JobSizeBytes, job.PrinterPageCounter, job.JobTitle, job.JobFileName, job.JobOptions)])))
289                self.report.append('</table>')
290                dico = { "history" : 1,
291                         "datelimit" : job.JobDate,
292                       }
293                if user and user.Exists :
294                    dico.update({ "username" : user.Name })
295                if printer and printer.Exists :
296                    dico.update({ "printername" : printer.Name })
297                prevurl = "%s?%s" % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode(dico))
298                self.report.append('<a href="%s">Previous page</a>' % prevurl)
299            self.body = "\n".join(self.report)   
300           
301if __name__ == "__main__" :
302    os.environ["LC_ALL"] = getLanguagePreference()
303    admin = PyKotaReportGUI(lang=os.environ["LC_ALL"])
304    admin.form = cgi.FieldStorage()
305    admin.guiAction()
306    admin.guiDisplay()
307    try :
308        admin.storage.close()
309    except (TypeError, NameError, AttributeError) :   
310        pass
311       
312    sys.exit(0)
Note: See TracBrowser for help on using the browser.