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

Revision 3333, 14.1 kB (checked in by jerome, 17 years ago)

Now escapes the content of the GPL blurb, which contains (in its
v3.0) reserved HTML characters.

  • 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: UTF-8 -*-
3
4# PyKota Print Quota Reports generator
5#
6# PyKota - Print Quotas for CUPS
7#
8# (c) 2003, 2004, 2005, 2006, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>.
21#
22# $Id$
23#
24#
25
26import sys
27import os
28import cgi
29import urllib
30from xml.sax import saxutils
31
32from mx import DateTime
33
34import pykota.appinit
35
36from pykota import version, utils
37from pykota.tool import PyKotaTool
38from pykota.errors import PyKotaToolError, PyKotaReporterError
39from pykota.reporter import openReporter
40
41header = """Content-type: text/html;charset=%s
42
43<html>
44  <head>
45    <title>%s</title>
46    <link rel="stylesheet" type="text/css" href="/pykota.css" />
47  </head>
48  <body>
49    <p>
50      <form action="printquota.cgi" method="POST">
51        <table>
52          <tr>
53            <td>
54              <p>
55                <a href="%s"><img src="%s?version=%s" alt="PyKota's Logo" /></a>
56                <br />
57                <a href="%s">PyKota v%s</a>
58              </p>
59            </td>
60            <td colspan="2">
61              <h1>%s</h1>
62            </td>
63          </tr>
64          <tr>
65            <td colspan="3" align="center">
66              <input type="submit" name="report" value="%s" />
67            </td>
68          </tr>
69        </table>"""
70   
71footer = """
72        <table>
73          <tr>
74            <td colspan="3" align="center">
75              <input type="submit" name="report" value="%s" />
76            </td>
77          </tr>
78        </table> 
79      </form>
80    </p>
81    <hr width="25%%" />
82    <p>
83      <font size="-2">
84        <a href="http://www.pykota.com/">%s</a>
85        &copy; %s %s
86        <br />
87        <pre>
88%s
89        </pre>
90      </font>
91    </p>
92  </body>
93</html>""" 
94
95class PyKotaReportGUI(PyKotaTool) :
96    """PyKota Administrative GUI"""
97    def guiDisplay(self) :
98        """Displays the administrative interface."""
99        global header, footer
100        content = [ header % (self.charset, _("PyKota Reports"), \
101                              self.config.getLogoLink(), \
102                              self.config.getLogoURL(), version.__version__, \
103                              self.config.getLogoLink(), \
104                              version.__version__, _("PyKota Reports"), \
105                              _("Report")) ]
106        content.append(self.body)                     
107        content.append(footer % (_("Report"),
108                                 version.__doc__,
109                                 version.__years__,
110                                 version.__author__,
111                                 saxutils.escape(version.__gplblurb__)))
112        for c in content :
113            sys.stdout.write(c.encode(self.charset, "replace"))
114        sys.stdout.flush()
115       
116    def error(self, message) :
117        """Adds an error message to the GUI's body."""
118        if message :
119            self.body = '<p><font color="red">%s</font></p>\n%s' % (message, self.body)
120       
121    def htmlListPrinters(self, selected=[], mask="*") :   
122        """Displays the printers multiple selection list."""
123        printers = self.storage.getMatchingPrinters(mask)
124        selectednames = [p.Name for p in selected]
125        message = '<table><tr><td valign="top">%s :</td><td valign="top"><select name="printers" multiple="multiple">' % _("Printer")
126        for printer in printers :
127            if printer.Name in selectednames :
128                message += '<option value="%s" selected="selected">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
129            else :
130                message += '<option value="%s">%s (%s)</option>' % (printer.Name, printer.Name, printer.Description)
131        message += '</select></td></tr></table>'
132        return message
133       
134    def htmlUGNamesInput(self, value="*") :   
135        """Input field for user/group names wildcard."""
136        return _("User / Group names mask") + (' : <input type="text" name="ugmask" size="20" value="%s" /> <em>e.g. <strong>jo*</strong></em>' % (value or "*"))
137       
138    def htmlGroupsCheckbox(self, isgroup=0) :
139        """Groups checkbox."""
140        if isgroup :
141            return _("Groups report") + ' : <input type="checkbox" checked="checked" name="isgroup" />'
142        else :   
143            return _("Groups report") + ' : <input type="checkbox" name="isgroup" />'
144           
145    def guiAction(self) :
146        """Main function"""
147        printers = ugmask = isgroup = None
148        remuser = os.environ.get("REMOTE_USER", "root")   
149        # special hack to accomodate mod_auth_ldap Apache module
150        try :
151            remuser = remuser.split("=")[1].split(",")[0]
152        except IndexError :   
153            pass
154        self.body = "<p>%s</p>\n" % _("Please click on the above button")
155        if self.form.has_key("report") :
156            if self.form.has_key("printers") :
157                printersfield = self.form["printers"]
158                if type(printersfield) != type([]) :
159                    printersfield = [ printersfield ]
160                printers = [self.storage.getPrinter(p.value) for p in printersfield]
161            else :   
162                printers = self.storage.getMatchingPrinters("*")
163            if remuser == "root" :
164                if self.form.has_key("ugmask") :     
165                    ugmask = self.form["ugmask"].value
166                else :     
167                    ugmask = "*"
168            else :       
169                if self.form.has_key("isgroup") :   
170                    user = self.storage.getUser(remuser)
171                    if user.Exists :
172                        ugmask = " ".join([ g.Name for g in self.storage.getUserGroups(user) ])
173                    else :   
174                        ugmask = remuser # result will probably be empty, we don't care
175                else :   
176                    ugmask = remuser
177            if self.form.has_key("isgroup") :   
178                isgroup = 1
179            else :   
180                isgroup = 0
181        self.body += self.htmlListPrinters(printers or [])           
182        self.body += "<br />"
183        self.body += self.htmlUGNamesInput(ugmask)
184        self.body += "<br />"
185        self.body += self.htmlGroupsCheckbox(isgroup)
186        try :
187            if not self.form.has_key("history") :
188                if printers and ugmask :
189                    self.reportingtool = openReporter(admin, "html", printers, ugmask.split(), isgroup)
190                    self.body += "%s" % self.reportingtool.generateReport()
191            else :       
192                if remuser != "root" :
193                    username = remuser
194                elif self.form.has_key("username") :   
195                    username = self.form["username"].value
196                else :   
197                    username = None
198                if username is not None :   
199                    user = self.storage.getUser(username)
200                else :   
201                    user = None
202                if self.form.has_key("printername") :
203                    printer = self.storage.getPrinter(self.form["printername"].value)
204                else :   
205                    printer = None
206                if self.form.has_key("datelimit") :   
207                    datelimit = self.form["datelimit"].value
208                else :   
209                    datelimit = None
210                if self.form.has_key("hostname") :   
211                    hostname = self.form["hostname"].value
212                else :   
213                    hostname = None
214                if self.form.has_key("billingcode") :   
215                    billingcode = self.form["billingcode"].value
216                else :   
217                    billingcode = None
218                self.report = ["<h2>%s</h2>" % _("History")]   
219                history = self.storage.retrieveHistory(user=user, printer=printer, hostname=hostname, billingcode=billingcode, end=datelimit)
220                if not history :
221                    self.report.append("<h3>%s</h3>" % _("Empty"))
222                else :
223                    self.report.append('<table class="pykotatable" border="1">')
224                    headers = [_("Date"), _("Action"), _("User"), _("Printer"), \
225                               _("Hostname"), _("JobId"), _("Number of pages"), \
226                               _("Cost"), _("Copies"), _("Number of bytes"), \
227                               _("Printer's internal counter"), _("Title"), _("Filename"), \
228                               _("Options"), _("MD5Sum"), _("Billing code"), \
229                               _("Precomputed number of pages"), _("Precomputed cost"), _("Pages details") + " " + _("(not supported yet)")]
230                    self.report.append('<tr class="pykotacolsheader">%s</tr>' % "".join(["<th>%s</th>" % h for h in headers]))
231                    oddeven = 0
232                    for job in history :
233                        oddeven += 1
234                        if job.JobAction == "ALLOW" :   
235                            if oddeven % 2 :
236                                oddevenclass = "odd"
237                            else :   
238                                oddevenclass = "even"
239                        else :
240                            oddevenclass = (job.JobAction or "UNKNOWN").lower()
241                        username_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "username" : job.UserName}), job.UserName)
242                        printername_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "printername" : job.PrinterName}), job.PrinterName)
243                        if job.JobHostName :
244                            hostname_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "hostname" : job.JobHostName}), job.JobHostName)
245                        else :   
246                            hostname_url = None
247                        if job.JobBillingCode :
248                            billingcode_url = '<a href="%s?%s">%s</a>' % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode({"history" : 1, "billingcode" : job.JobBillingCode}), job.JobBillingCode)
249                        else :   
250                            billingcode_url = None
251                        curdate = DateTime.ISO.ParseDateTime(str(job.JobDate)[:19])
252                        self.report.append('<tr class="%s">%s</tr>' % \
253                                              (oddevenclass, \
254                                               "".join(["<td>%s</td>" % (h or "&nbsp;") \
255                                                  for h in (str(curdate)[:19], \
256                                                            _(job.JobAction), \
257                                                            username_url, \
258                                                            printername_url, \
259                                                            hostname_url, \
260                                                            job.JobId, \
261                                                            job.JobSize, \
262                                                            job.JobPrice, \
263                                                            job.JobCopies, \
264                                                            job.JobSizeBytes, \
265                                                            job.PrinterPageCounter, \
266                                                            job.JobTitle, \
267                                                            job.JobFileName, \
268                                                            job.JobOptions, \
269                                                            job.JobMD5Sum, \
270                                                            billingcode_url, \
271                                                            job.PrecomputedJobSize, \
272                                                            job.PrecomputedJobPrice, \
273                                                            job.JobPages)])))
274                    self.report.append('</table>')
275                    dico = { "history" : 1,
276                             "datelimit" : "%04i-%02i-%02i %02i:%02i:%02i" \
277                                                         % (curdate.year, \
278                                                            curdate.month, \
279                                                            curdate.day, \
280                                                            curdate.hour, \
281                                                            curdate.minute, \
282                                                            curdate.second),
283                           }
284                    if user and user.Exists :
285                        dico.update({ "username" : user.Name })
286                    if printer and printer.Exists :
287                        dico.update({ "printername" : printer.Name })
288                    if hostname :   
289                        dico.update({ "hostname" : hostname })
290                    prevurl = "%s?%s" % (os.environ.get("SCRIPT_NAME", ""), urllib.urlencode(dico))
291                    self.report.append('<a href="%s">%s</a>' % (prevurl, _("Previous page")))
292                self.body = "\n".join(self.report)   
293        except :
294                self.body += '<p><font color="red">%s</font></p>' % self.crashed("CGI Error").replace("\n", "<br />")
295           
296if __name__ == "__main__" :
297    utils.reinitcgilocale()
298    admin = PyKotaReportGUI()
299    admin.deferredInit()
300    admin.form = cgi.FieldStorage()
301    admin.guiAction()
302    admin.guiDisplay()
303    try :
304        admin.storage.close()
305    except (TypeError, NameError, AttributeError) :   
306        pass
307       
308    sys.exit(0)
Note: See TracBrowser for help on using the browser.