root / pykota / trunk / bin / edpykota @ 3549

Revision 3549, 18.7 kB (checked in by jerome, 14 years ago)

Removed support for the MaxJobSize? attribute for users group print quota
entries : I couldn't see a real use for this at the moment, and it would
complexify the code. This support might reappear later however. Added full
support for the MaxJobSize? attribute for user print quota entries,
editable with edpykota's new --maxjobsize command line switch. Changed
the internal handling of the MaxJobSize? attribute for printers :
internally 0 used to mean unlimited, it now allows one to forbid
printing onto a particular printer. The database upgrade script (only
for PostgreSQL) takes care of this.
IMPORTANT : the database schema changes. A database upgrade script is
provided for PostgreSQL only. The LDAP schema doesn't change to not
break any existing LDAP directory, so the pykotaMaxJobSize attribute is
still allowed on group print quota entries, but never used.
Seems to work as expected, for a change :-)
Fixes #15.

  • 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/env python
2# -*- coding: utf-8 -*-
3#
4# PyKota : Print Quotas for CUPS
5#
6# (c) 2003-2009 Jerome Alet <alet@librelogiciel.com>
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19#
20# $Id$
21#
22#
23
24"""A print quota entries manager for PyKota."""
25
26import sys
27
28import pykota.appinit
29from pykota.utils import run
30from pykota.commandline import PyKotaOptionParser
31from pykota.errors import PyKotaCommandLineError
32from pykota.tool import PyKotaTool
33from pykota.storage import StorageUserPQuota, StorageGroupPQuota
34from pykota.progressbar import Percent
35
36class EdPyKota(PyKotaTool) :
37    """A class for edpykota."""
38    def modifyPQEntry(self, pqkey, pqentry, noquota, softlimit, hardlimit, increase, reset, hardreset, suffix, used, maxjobsize) :
39        """Modifies a print quota entry."""
40        if noquota or ((softlimit is not None) and (hardlimit is not None)) :
41            pqentry.setLimits(softlimit, hardlimit)
42        if increase :
43            newsoft = (pqentry.SoftLimit or 0) + increase
44            newhard = (pqentry.HardLimit or 0) + increase
45            if (newsoft >= 0) and (newhard >= 0) :
46                pqentry.setLimits(newsoft, newhard)
47            else :
48                self.printInfo(_("You can't set negative limits for %s") % pqkey, "error")
49        if reset :
50            pqentry.reset()
51        if hardreset :
52            pqentry.hardreset()
53        if suffix == "User" :
54            if used :
55                pqentry.setUsage(used)
56            if maxjobsize is not None :
57                if maxjobsize == "unlimited" :
58                    pqentry.setMaxJobSize(None)
59                else :
60                    pqentry.setMaxJobSize(maxjobsize)
61
62    def main(self, names, options) :
63        """Edit user or group quotas."""
64        islist = (options.action == "list")
65        isadd = (options.action == "add")
66        isdelete = (options.action == "delete")
67
68        if not islist :
69            self.adminOnly()
70
71        names = self.sanitizeNames(names, options.groups)
72        if not names :
73            if isdelete :
74                raise PyKotaCommandLineError, _("You must specify users or groups names on the command line.")
75            names = [u"*"]
76
77        if (((islist or isdelete) and (options.used  \
78                                      or options.softlimit \
79                                      or options.hardlimit \
80                                      or options.reset \
81                                      or options.hardreset \
82                                      or options.noquota \
83                                      or options.increase \
84                                      or options.maxjobsize \
85                                      or options.skipexisting))) \
86             or (options.groups and (options.used \
87                                  or options.maxjobsize \
88                                  or options.increase \
89                                  or options.reset \
90                                  or options.hardreset)) :
91            raise PyKotaCommandLineError, _("Incompatible command line options. Please look at the online help or manual page.")
92
93        suffix = (options.groups and "Group") or "User"
94        printernames = options.printer.split(",")
95
96        if not islist :
97            percent = Percent(self)
98            percent.display("%s..." % _("Extracting datas"))
99        printers = self.storage.getMatchingPrinters(options.printer)
100        entries = getattr(self.storage, "getMatching%ss" % suffix)(",".join(names))
101        if not islist :
102            percent.setSize(len(printers) * len(entries))
103
104        if islist :
105            for printer in printers :
106                for entry in entries :
107                    pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
108                    if pqentry.Exists :
109                        self.display("%s@%s\n" % (entry.Name, printer.Name))
110                        self.display("    %s\n" % (_("Page counter : %s") % pqentry.PageCounter))
111                        self.display("    %s\n" % (_("Lifetime page counter : %s") % pqentry.LifePageCounter))
112                        self.display("    %s\n" % (_("Soft limit : %s") % pqentry.SoftLimit))
113                        self.display("    %s\n" % (_("Hard limit : %s") % pqentry.HardLimit))
114                        self.display("    %s\n" % (_("Date limit : %s") % pqentry.DateLimit))
115                        if suffix == "User" :
116                            self.display("    %s\n" % (_("Maximum job size : %s") % (((pqentry.MaxJobSize is not None) and (_("%s pages") % pqentry.MaxJobSize)) or _("Unlimited"))))
117                        if hasattr(pqentry, "WarnCount") :
118                            self.display("    %s\n" % (_("Warning banners printed : %s") % pqentry.WarnCount))
119                        self.display("\n")
120        elif isdelete :
121            percent.display("\n%s..." % _("Deletion"))
122            getattr(self.storage, "deleteMany%sPQuotas" % suffix)(printers, entries)
123            percent.display("\n")
124        else :
125            used = options.used
126            if used :
127                used = used.strip()
128                try :
129                    int(used)
130                except ValueError :
131                    raise PyKotaCommandLineError, _("Invalid used value %s.") % used
132
133            increase = options.increase
134            if increase :
135                try :
136                    increase = int(increase.strip())
137                except ValueError :
138                    raise PyKotaCommandLineError, _("Invalid increase value %s.") % increase
139
140            softlimit = hardlimit = None
141            if not options.noquota :
142                if options.softlimit :
143                    try :
144                        softlimit = int(options.softlimit.strip())
145                        if softlimit < 0 :
146                            raise ValueError
147                    except ValueError :
148                        raise PyKotaCommandLineError, _("Invalid softlimit value %s.") % options.softlimit
149                if options.hardlimit :
150                    try :
151                        hardlimit = int(options.hardlimit.strip())
152                        if hardlimit < 0 :
153                            raise ValueError
154                    except ValueError :
155                        raise PyKotaCommandLineError, _("Invalid hardlimit value %s.") % options.hardlimit
156                if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :
157                    self.printInfo(_("Hard limit %(hardlimit)i is less than soft limit %(softlimit)i, values will be exchanged.") \
158                                       % locals())
159                    (softlimit, hardlimit) = (hardlimit, softlimit)
160                if hardlimit is None :
161                    hardlimit = softlimit
162                    if hardlimit is not None :
163                        self.printInfo(_("Undefined hard limit set to soft limit (%s).") % str(hardlimit))
164                if softlimit is None :
165                    softlimit = hardlimit
166                    if softlimit is not None :
167                        self.printInfo(_("Undefined soft limit set to hard limit (%s).") % str(softlimit))
168
169            if options.maxjobsize :
170                if options.maxjobsize.lower() == "unlimited" :
171                    maxjobsize = "unlimited"
172                else :
173                    try :
174                        maxjobsize = int(options.maxjobsize)
175                        if maxjobsize < 0 :
176                            raise ValueError
177                    except ValueError :
178                        raise PyKotaCommandLineError, _("Invalid maximum job size value %s") % options.maxjobsize
179            else :
180                maxjobsize = None
181
182            self.storage.beginTransaction()
183            try :
184                if isadd :
185                    percent.display("\n%s...\n" % _("Creation"))
186                    if not entries :
187                        self.printInfo(_("No entry matches %s. Please use pkusers to create them first.") \
188                                           % (" ".join(names)), "warn")
189
190                    factory = globals()["Storage%sPQuota" % suffix]
191                    for printer in printers :
192                        pname = printer.Name
193                        for entry in entries :
194                            ename = entry.Name
195                            pqkey = "%s@%s" % (ename, pname)
196                            pqentry = factory(self.storage, entry, printer)
197                            self.modifyPQEntry(pqkey,
198                                               pqentry,
199                                               options.noquota,
200                                               softlimit,
201                                               hardlimit,
202                                               increase,
203                                               options.reset,
204                                               options.hardreset,
205                                               suffix,
206                                               used,
207                                               maxjobsize)
208                            oldpqentry = getattr(self.storage, "add%sPQuota" % suffix)(pqentry)
209                            if oldpqentry is not None :
210                                if options.skipexisting :
211                                    self.logdebug("%s print quota entry %s@%s already exists, skipping." \
212                                                      % (suffix, ename, pname))
213                                else :
214                                    self.logdebug("%s print quota entry %s@%s already exists, will be modified." \
215                                                      % (suffix, ename, pname))
216                                    self.modifyPQEntry(pqkey,
217                                                       oldpqentry,
218                                                       options.noquota,
219                                                       softlimit,
220                                                       hardlimit,
221                                                       increase,
222                                                       options.reset,
223                                                       options.hardreset,
224                                                       suffix,
225                                                       used,
226                                                       maxjobsize)
227                                    oldpqentry.save()
228                            percent.oneMore()
229                else :
230                    percent.display("\n%s...\n" % _("Modification"))
231                    for printer in printers :
232                        for entry in entries :
233                            pqkey = "%s@%s" % (entry.Name, printer.Name)
234                            pqentry = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer)
235                            if pqentry.Exists :
236                                self.modifyPQEntry(pqkey,
237                                                   pqentry,
238                                                   options.noquota,
239                                                   softlimit,
240                                                   hardlimit,
241                                                   increase,
242                                                   options.reset,
243                                                   options.hardreset,
244                                                   suffix,
245                                                   used,
246                                                   maxjobsize)
247                                pqentry.save()
248                            percent.oneMore()
249            except :
250                self.storage.rollbackTransaction()
251                raise
252            else :
253                self.storage.commitTransaction()
254
255        if not islist :
256            percent.done()
257
258if __name__ == "__main__" :
259    parser = PyKotaOptionParser(description=_("Manages PyKota print quota entries for users or users groups. A print quota entry is related to both an user and a printer, or to both a group and a printer, meaning that for example different users can have different page count limits on the same printer. If an user doesn't have a print quota entry on a particular printer, he won't be allowed to print to it."),
260                                usage="edpykota [options] [usernames|groupnames]")
261    parser.add_option("-a", "--add",
262                            action="store_const",
263                            const="add",
264                            dest="action",
265                            help=_("Add new, or modify existing, users or groups print quota entries."))
266    parser.add_option("-d", "--delete",
267                            action="store_const",
268                            const="delete",
269                            dest="action",
270                            help=_("Delete the specified users or groups print quota entries. When deleting users print quota entries, the matching jobs are also deleted from the printing history."))
271    parser.add_option("-S", "--softlimit",
272                            dest="softlimit",
273                            help=_("Set the soft page count limit for the specified print quota entries. Users can print over this limit for a number of days specified in the 'gracedelay' directive in pykota.conf"))
274    parser.add_option("-H", "--hardlimit",
275                            dest="hardlimit",
276                            help=_("Set the hard page count limit for the specified print quota entries. Users are never allowed to print over this limit."))
277    parser.add_option("-g", "--groups",
278                            action="store_true",
279                            dest="groups",
280                            help=_("Manage groups print quota entries instead of users print quota entries."))
281    parser.add_option("-I", "--increase",
282                            dest="increase",
283                            help=_("Increase the existing soft and hard page count limits for the specified print quota entries. You can decrease the values instead by prefixing this parameter with a negative sign."))
284    parser.add_option("-L", "--list",
285                            action="store_const",
286                            const="list",
287                            dest="action",
288                            help=_("Display detailed informations about the specified users or groups print quota entries."))
289    parser.add_option("-m", "--maxjobsize",
290                            dest="maxjobsize",
291                            help=_("Set the maximum job size in pages the specified users are allowed to print to the specified printers in a single job. Accepted values are '0' to forbid printing, 'unlimited' to allow unrestricted printing, or any positive integer value. This option is not supported for users groups."))
292    parser.add_option("-n", "--noquota",
293                            dest="noquota",
294                            action="store_true",
295                            help=_("Set no limit for both soft and hard page counts for the specified users or groups print quota entries."))
296    parser.add_option("-P", "--printer",
297                            dest="printer",
298                            default="*",
299                            help=_("Specify a comma separated list of printers you want to manage print quota entries on. The default is '*', meaning all printers."))
300    parser.add_option("-r", "--reset",
301                            dest="reset",
302                            action="store_true",
303                            help=_("Reset the actual page counter for the specified users print quota entries (doesn't work for groups print quota entries). The life time page counter is left unchanged."))
304    parser.add_option("-R", "--hardreset",
305                            dest="hardreset",
306                            action="store_true",
307                            help=_("Reset the actual and life time page counters for the specified users print quota entries (doesn't work for groups print quota entries). This is a shortcut for --used 0."))
308    parser.add_option("-s", "--skipexisting",
309                            action="store_true",
310                            dest="skipexisting",
311                            help=_("If --add is used, ensure that existing users or groups print quota entries won't be modified."))
312    parser.add_option("-U", "--used",
313                            dest="used",
314                            help=_("Set the values of both the actual and life time page counters for the specified users print quota entries (doesn't work for groups print quota entries). This can be useful when migrating from a different print quota software. The values can also be increased or decreased by prefixing this parameter with either a positive or negative sign."))
315
316    parser.add_example("--add john paul george ringo",
317                       _("Would create print quota entries with no page count limits for these four users on all existing printers."))
318    parser.add_example("--printer HP --softlimit 50 --hardlimit 60 jerome",
319                       _("Would allow user 'jerome' to print up to 60 pages on printer 'HP'. This user would be warned when he would have reached 50 pages on this printer. Both the user and printer must have been created previously using the pkusers and pkprinters commands, respectively."))
320    parser.add_example("--groups --softlimit 500 --hardlimit 600 support financial",
321                       _("Would set soft and hard page count limits on any printer for groups 'support' and 'financial'."))
322    parser.add_example('--reset --printer HP jerome "jo*"',
323                       _("Would reset the actual page counter for users 'jerome' and all users whose name begins with 'jo' on printer 'HP'."))
324    parser.add_example("--printer HPCOLOR --noquota jerome",
325                       _("Would allow this user to print without any page limit on printer 'HPCOLOR'. Depending on how this user is limited, he may still be subject to being limited by the number of available credits in his account."))
326    parser.add_example("--add --skipexisting",
327                       _("Would create a print quota entry for each user on each printer for which none already existed. You'll most likely want to use this command at least once after initial setup."))
328    run(parser, EdPyKota)
Note: See TracBrowser for help on using the browser.