Changeset 1041

Show
Ignore:
Timestamp:
06/25/03 16:10:01 (21 years ago)
Author:
jalet
Message:

Hey, it may work (edpykota --reset excepted) !

Location:
pykota/trunk
Files:
14 modified

Legend:

Unmodified
Added
Removed
  • pykota/trunk/bin/edpykota

    r1031 r1041  
    2323# 
    2424# $Log$ 
     25# Revision 1.47  2003/06/25 14:10:01  jalet 
     26# Hey, it may work (edpykota --reset excepted) ! 
     27# 
    2528# Revision 1.46  2003/06/16 11:59:09  jalet 
    2629# More work on LDAP 
     
    330333    def main(self, names, options) : 
    331334        """Edit user or group quotas.""" 
    332         printeradded = 0 
    333         printers = self.storage.getMatchingPrinters(options["printer"]) 
    334         if not printers : 
    335             pname = options["printer"] 
    336             if options["add"] and pname : 
    337                 if self.isValidName(pname) : 
    338                     printerid = self.storage.addPrinter(pname) 
    339                     printers = [ (printerid, pname) ] 
    340                     printeradded = 1 
    341                 else :     
    342                     raise PyKotaToolError, _("Invalid printer name %s") % pname 
    343             else : 
    344                 raise PyKotaToolError, _("There's no printer matching %s") % pname 
    345                  
     335         
     336        suffix = (options["groups"] and "Group") or "User"         
     337         
    346338        softlimit = hardlimit = None     
    347         if options["softlimit"] : 
    348             try : 
    349                 softlimit = int(options["softlimit"].strip()) 
    350             except ValueError :     
    351                 raise PyKotaToolError, _("Invalid softlimit value %s.") % options["softlimit"] 
    352         if options["hardlimit"] : 
    353             try : 
    354                 hardlimit = int(options["hardlimit"].strip()) 
    355             except ValueError :     
    356                 raise PyKotaToolError, _("Invalid hardlimit value %s.") % options["hardlimit"] 
    357         if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :         
    358             # error, exchange them 
    359             self.logger.log_message(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit)) 
    360             (softlimit, hardlimit) = (hardlimit, softlimit) 
     339        if not options["noquota"] : 
     340            if options["softlimit"] : 
     341                try : 
     342                    softlimit = int(options["softlimit"].strip()) 
     343                except ValueError :     
     344                    raise PyKotaToolError, _("Invalid softlimit value %s.") % options["softlimit"] 
     345            if options["hardlimit"] : 
     346                try : 
     347                    hardlimit = int(options["hardlimit"].strip()) 
     348                except ValueError :     
     349                    raise PyKotaToolError, _("Invalid hardlimit value %s.") % options["hardlimit"] 
     350            if (softlimit is not None) and (hardlimit is not None) and (hardlimit < softlimit) :         
     351                # error, exchange them 
     352                self.logger.log_message(_("Hard limit %i is less than soft limit %i, values will be exchanged.") % (hardlimit, softlimit)) 
     353                (softlimit, hardlimit) = (hardlimit, softlimit) 
    361354             
    362         if not names :     
    363             if options["add"] and not printeradded : 
    364                 raise PyKotaToolError, _("You have to pass user or group names on the command line") 
    365             else :     
    366                 names = [ "*" ] # all users 
    367                  
    368355        balance = options["balance"] 
    369356        if balance : 
     
    394381            groupnames = [] 
    395382             
    396         uwaschanged = {}         # tracks changed made at the user level 
    397         gwaschanged = {}         # tracks changed made at the group level 
    398         for (printerid, printer) in printers : 
     383        if options["prototype"] :     
     384            protoentry = getattr(self.storage, "get%s" % suffix)(options["prototype"]) 
     385             
     386        printeradded = 0 
     387        printers = self.storage.getMatchingPrinters(options["printer"]) 
     388        if not printers : 
     389            pname = options["printer"] 
     390            if options["add"] and pname : 
     391                if self.isValidName(pname) : 
     392                    printers = [ self.storage.addPrinter(pname) ] 
     393                    if printers[0].Exists : 
     394                        printeradded = 1 
     395                    else :     
     396                        raise PyKotaToolError, _("Impossible to add printer %s") % pname 
     397                else :     
     398                    raise PyKotaToolError, _("Invalid printer name %s") % pname 
     399            else : 
     400                raise PyKotaToolError, _("There's no printer matching %s") % pname 
     401        if not names :     
     402            if options["add"] and not printeradded : 
     403                raise PyKotaToolError, _("You have to pass user or group names on the command line") 
     404            else :     
     405                names = [ "*" ] # all users 
     406                 
     407        changed = {} # tracks changes made at the user/group level 
     408        for printer in printers : 
    399409            if options["charge"] : 
    400410                (perpage, perjob) = charges 
    401                 if perjob is None : 
    402                     # we don't want to change this one, get the old value 
    403                     (dummy, perjob) = self.storage.getPrinterPrices(printerid) 
    404                 self.storage.setPrinterPrices(printerid, perpage, perjob)     
     411                printer.setPrices(perpage, perjob)     
     412                 
    405413            if options["prototype"] : 
    406                 if options["groups"] : 
    407                     prototype = self.storage.getGroupPQuota(self.storage.getGroupId(options["prototype"]), printerid) 
    408                 else :      
    409                     # default is user quota edition 
    410                     prototype = self.storage.getUserPQuota(self.storage.getUserId(options["prototype"]), printerid) 
    411                 if prototype is None : 
    412                     self.logger.log_message(_("Prototype %s not found in Quota Storage for printer %s.") % (options["prototype"], printer)) 
    413                     continue    # skip this printer 
    414                 else :     
    415                     (softlimit, hardlimit) = (prototype["softlimit"], prototype["hardlimit"]) 
    416             if hardlimit is None :     
    417                 hardlimit = softlimit 
    418                 if hardlimit is not None : 
    419                     self.logger.log_message(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer)) 
    420             if softlimit is None :     
    421                 softlimit = hardlimit 
    422                 if softlimit is not None : 
    423                     self.logger.log_message(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer)) 
    424             if (not options["ingroups"] and not options["reset"] and not options["noquota"] and not options["prototype"] and not options["limitby"] and not options["balance"] and not options["delete"] and not options["charge"]) and ((hardlimit is None) or (softlimit is None)) : 
    425                 raise PyKotaToolError, _("Both hard and soft limits must be set ! Aborting.") 
     414                if protoentry.Exists : 
     415                    protoquota = getattr(self.storage, "get%PQuota" % suffix)(protoentry, printer) 
     416                    if not protoquota.Exists : 
     417                        self.logger.log_message(_("Prototype %s not found in Quota Storage for printer %s.") % (protoentry.Name, printer.Name)) 
     418                        continue    # skip this printer 
     419                    else :     
     420                        (softlimit, hardlimit) = (protoquota.SoftLimit, protoquota.HardLimit) 
     421                else :         
     422                    self.logger.log_message(_("Prototype object %s not found in Quota Storage.") % protoentry.Name) 
     423            if not options["noquota"] :     
     424                if hardlimit is None :     
     425                    hardlimit = softlimit 
     426                    if hardlimit is not None : 
     427                        self.logger.log_message(_("Undefined hard limit set to soft limit (%s) on printer %s.") % (str(hardlimit), printer.Name)) 
     428                if softlimit is None :     
     429                    softlimit = hardlimit 
     430                    if softlimit is not None : 
     431                        self.logger.log_message(_("Undefined soft limit set to hard limit (%s) on printer %s.") % (str(softlimit), printer.Name)) 
     432                         
    426433            if options["add"] :     
    427                 if options["groups"] :     
    428                     allidnames = [(self.storage.getGroupId(n), n) for n in names] 
    429                 else : 
    430                     allidnames = [(self.storage.getUserId(n), n) for n in names] 
     434                allentries = []     
     435                for name in names : 
     436                    entry = getattr(self.storage, "get%s" % suffix)(name) 
     437                    entrypquota = getattr(self.storage, "get%sPQuota" % suffix)(entry, printer) 
     438                    allentries.append((entry, entrypquota)) 
    431439            else :    
    432                 if options["groups"] :     
    433                     allidnames = self.storage.getPrinterGroups(printerid) or [] 
    434                 else :     
    435                     allidnames = self.storage.getPrinterUsers(printerid) or [] 
    436             for (ident, name) in [(i, n) for (i, n) in allidnames if self.matchString(n, names)]: 
    437                 if options["groups"] : 
    438                     if not gwaschanged.has_key(name) : 
    439                         gwaschanged[name] = {} 
    440                     quota = self.storage.getGroupPQuota(ident, printerid) 
    441                 else : 
    442                     if not uwaschanged.has_key(name) : 
    443                         uwaschanged[name] = {"ingroups": []} 
    444                     quota = self.storage.getUserPQuota(ident, printerid) 
    445                 if quota is None : 
     440                allentries = getattr(self.storage, "getPrinter%ssAndQuotas" % suffix)(printer) 
     441                 
     442            for (entry, entrypquota) in [(e, q) for (e, q) in allentries if self.matchString(e.Name, names)] : 
     443                if not changed.has_key(entry.Name) : 
     444                    changed[entry.Name] = {} 
     445                if not entrypquota.Exists : 
    446446                    # not found 
    447447                    if options["add"] : 
     
    450450                        # like /etc/passwd because users may be defined  
    451451                        # only remotely 
    452                         if options["groups"] : 
    453                             if self.isValidName(name) : 
    454                                 (ident, printerid) = self.storage.addGroupPQuota(name, printerid) 
    455                                 quota = self.storage.getGroupPQuota(ident, printerid) 
     452                        if self.isValidName(entry.Name) : 
     453                            if not entry.Exists : 
     454                                entry = getattr(self.storage, "add%s" % suffix)(entry) 
     455                            entrypquota = getattr(self.storage, "add%sPQuota" % suffix)(entry, printer) 
     456                        else :     
     457                            if options["groups"] : 
     458                                self.logger.log_message(_("Invalid group name %s") % entry.Name) 
    456459                            else :     
    457                                 self.logger.log_message(_("Invalid group name %s") % name) 
    458                         else : 
    459                             if self.isValidName(name) : 
    460                                 (ident, printerid) = self.storage.addUserPQuota(name, printerid) 
    461                                 quota = self.storage.getUserPQuota(ident, printerid) 
    462                             else :     
    463                                 self.logger.log_message(_("Invalid user name %s") % name) 
    464                 if quota is None :      
    465                     self.logger.log_message(_("Quota not found for object %s on printer %s.") % (name, printer)) 
     460                                self.logger.log_message(_("Invalid user name %s") % entry.Name) 
     461                if not entrypquota.Exists :      
     462                    self.logger.log_message(_("Quota not found for object %s on printer %s.") % (entry.Name, printer.Name)) 
    466463                else :     
    467464                    if options["delete"] : 
    468                         if options["groups"] : 
    469                             self.storage.deleteGroup(ident) 
    470                         else : 
    471                             self.storage.deleteUser(ident) 
     465                        entry.delete() 
    472466                    else : 
    473                         if options["groups"] : 
    474                             if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) : 
    475                                 self.storage.setGroupPQuota(ident, printerid, softlimit, hardlimit) 
     467                        if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) : 
     468                            entrypquota.setLimits(softlimit, hardlimit) 
     469                        if limitby : 
     470                            if changed[entry.Name].get("limitby") is None : 
     471                                entry.setLimitBy(limitby) 
     472                                changed[entry.Name]["limitby"] = limitby 
     473                         
     474                        if not options["groups"] : 
    476475                            if options["reset"] : 
    477                                 self.storage.resetGroupPQuota(ident, printerid) 
    478                             if limitby : 
    479                                 if gwaschanged[name].get("limitby") is None : 
    480                                     self.storage.limitGroupBy(ident, limitby) 
    481                                     gwaschanged[name]["limitby"] = limitby 
    482                             self.warnGroupPQuota(name, printer)     
    483                         else : 
    484                             if options["noquota"] or options["prototype"] or ((softlimit is not None) and (hardlimit is not None)) : 
    485                                 self.storage.setUserPQuota(ident, printerid, softlimit, hardlimit) 
    486                             if options["reset"] : 
    487                                 self.storage.resetUserPQuota(ident, printerid) 
    488                             if limitby : 
    489                                 if uwaschanged[name].get("limitby") is None : 
    490                                     self.storage.limitUserBy(ident, limitby) 
    491                                     uwaschanged[name]["limitby"] = limitby 
     476                                entrypquota.reset() 
     477                                 
    492478                            if balance : 
    493                                 if uwaschanged[name].get("balance") is None : 
     479                                if changed[entry.Name].get("balance") is None : 
    494480                                    if balance.startswith("+") or balance.startswith("-") : 
    495                                         self.storage.increaseUserBalance(ident, balancevalue) 
     481                                        entry.consumeAccountBalance(-balancevalue) 
    496482                                    else : 
    497                                         self.storage.setUserBalance(ident, balancevalue) 
    498                                     uwaschanged[name]["balance"] = balance 
     483                                        entry.consumeAccountBalance(float(entry.AccountBalance or 0.0) - balancevalue) 
     484                                    changed[entry.Name]["balance"] = balance 
    499485                            for groupname in groupnames :         
    500                                 if groupname not in uwaschanged[name]["ingroups"] : 
    501                                     groupid = self.storage.getGroupId(groupname) 
    502                                     if groupid is not None : 
    503                                         self.storage.addUserToGroup(ident, groupid) 
    504                                         uwaschanged[name]["ingroups"].append(groupname) 
     486                                if groupname not in changed[name]["ingroups"] : 
     487                                    group = self.storage.getGroup(groupname) 
     488                                    if group.Exists : 
     489                                        self.storage.addUserToGroup(entry, group) 
     490                                        changed[entry.Name]["ingroups"].append(groupname) 
    505491                                    else : 
    506492                                        self.logger.log_message(_("Group %s not found in the PyKota Storage.") % groupname) 
    507                             self.warnUserPQuota(name, printer)     
     493                                         
     494                        getattr(self, "warn%sPQuota" % suffix)(entrypquota)     
    508495                      
    509496if __name__ == "__main__" :  
  • pykota/trunk/bin/pykota

    r1026 r1041  
    2323# 
    2424# $Log$ 
     25# Revision 1.35  2003/06/25 14:10:01  jalet 
     26# Hey, it may work (edpykota --reset excepted) ! 
     27# 
    2528# Revision 1.34  2003/06/13 18:54:17  jalet 
    2629# Bug with remote jobs and LPRng fixed. 
     
    239242     
    240243    # Get the last page counter and last username from the Quota Storage backend 
    241     printerid = kotafilter.storage.getPrinterId(kotafilter.printername) 
    242     if printerid is None : 
     244    printer = kotafilter.storage.getPrinter(kotafilter.printername) 
     245    if not printer.Exists : 
    243246        # The printer is unknown from the Quota Storage perspective 
    244247        # we let the job pass through, but log a warning message 
    245248        kotafilter.logger.log_message(_("Printer %s not registered in the PyKota system") % kotafilter.printername, "warn") 
    246249    else :     
    247         userid = kotafilter.storage.getUserId(kotafilter.username) 
    248         if userid is None : 
     250        user = kotafilter.storage.getUser(kotafilter.username) 
     251        if not user.Exists : 
    249252            # The user is unknown from the Quota Storage perspective 
    250253            # Depending on the default policy for this printer, we 
     
    261264        else : 
    262265            # Now does the accounting and act depending on the result 
    263             action = kotafilter.accounter.doAccounting(printerid, userid) 
     266            action = kotafilter.accounter.doAccounting(printer, user) 
    264267             
    265268            # if not allowed to print then die, else proceed. 
  • pykota/trunk/bin/repykota

    r1030 r1041  
    2323# 
    2424# $Log$ 
     25# Revision 1.39  2003/06/25 14:10:01  jalet 
     26# Hey, it may work (edpykota --reset excepted) ! 
     27# 
    2528# Revision 1.38  2003/06/15 22:26:52  jalet 
    2629# More work on LDAP 
     
    147150 
    148151import sys 
     152import os 
     153import pwd 
     154import grp 
    149155 
    150156from mx import DateTime 
     
    187193   
    188194  This will print the quota status for all users on all printers. 
     195   
     196  $ repykota --printer "laser*" jerome "jo*" 
     197   
     198  This will print the quota status for user jerome and all users 
     199  whose name begins with "jo" on all printers which name begin 
     200  with "laser" 
     201   
     202  If launched by a non-root user, additionnal arguments representing 
     203  users or groups names are ignored, and only the current user/group 
     204  is reported. 
    189205 
    190206This program is free software; you can redistribute it and/or modify 
     
    206222class RePyKota(PyKotaTool) :         
    207223    """A class for repykota.""" 
    208     def main(self, options) : 
     224    def main(self, ugnames, options) : 
    209225        """Print Quota reports generator.""" 
     226        uid = os.geteuid() 
     227        if not uid : 
     228            # root user 
     229            if not ugnames : 
     230                # no username, means all usernames 
     231                ugnames = [ "*" ] 
     232        else :         
     233            # not the root user 
     234            # reports only the current user 
     235            if options["groups"] : 
     236                ugnames = [ grp.getgrgid(pwd.getpwuid(uid)[3])[0] ] 
     237            else : 
     238                ugnames = [ pwd.getpwuid(uid)[0] ] 
     239         
    210240        printers = self.storage.getMatchingPrinters(options["printer"]) 
    211241        if not printers : 
    212242            raise PyKotaToolError, _("There's no printer matching %s") % options["printer"] 
    213         for (printerid, printer) in printers : 
    214             print _("*** Report for %s quota on printer %s") % ((options["groups"] and "group") or "user", printer) 
    215             print _("Pages grace time: %i days") % self.config.getGraceDelay(printer) 
    216             prices = self.storage.getPrinterPrices(printerid) 
    217             if prices is None : 
    218                 (perpage, perjob) = (None, None) 
    219             else :     
    220                 (perpage, perjob) = prices 
    221             if perjob is not None : 
    222                 print _("Price per job: %.3f") % perjob 
    223             if perpage is not None :     
    224                 print _("Price per page: %.3f") % perpage 
     243        for printer in printers : 
     244            print _("*** Report for %s quota on printer %s") % ((options["groups"] and "group") or "user", printer.Name) 
     245            print _("Pages grace time: %i days") % self.config.getGraceDelay(printer.Name) 
     246            if printer.PricePerJob is not None : 
     247                print _("Price per job: %.3f") % printer.PricePerJob 
     248            if printer.PricePerPage is not None :     
     249                print _("Price per page: %.3f") % printer.PricePerPage 
    225250            total = 0 
    226251            totalmoney = 0.0 
     
    228253                print _("Group           used    soft    hard    balance grace         total       paid")  
    229254                print "------------------------------------------------------------------------------" 
    230                 for (ident, name) in (self.storage.getPrinterGroups(printerid) or []) : 
    231                     quota = self.storage.getGroupPQuota(ident, printerid)  
    232                     balance = self.storage.getGroupBalance(ident) 
    233                     limitby = self.storage.getGroupLimitBy(ident) 
    234                     (pages, money) = self.printQuota(name, quota, balance, limitby) 
     255                for (group, grouppquota) in self.storage.getPrinterGroupsAndQuotas(printer, ugnames) : 
     256                    (pages, money) = self.printQuota(group, grouppquota) 
    235257                    total += pages 
    236258                    totalmoney += money 
     
    239261                print _("User            used    soft    hard    balance grace         total       paid")  
    240262                print "------------------------------------------------------------------------------" 
    241                 for (ident, name) in (self.storage.getPrinterUsers(printerid) or []) : 
    242                     quota = self.storage.getUserPQuota(ident, printerid) 
    243                     balance = self.storage.getUserBalance(ident) 
    244                     limitby = self.storage.getUserLimitBy(ident) 
    245                     (pages, money) = self.printQuota(name, quota, balance, limitby) 
     263                for (user, userpquota) in self.storage.getPrinterUsersAndQuotas(printer, ugnames) : 
     264                    (pages, money) = self.printQuota(user, userpquota) 
    246265                    total += pages 
    247266                    totalmoney += money 
    248267            if total or totalmoney :         
    249268                print (" " * 50) + (_("Total : %9i") % total) + ("%11s" % ("%7.2f" % totalmoney)[:11]) 
    250             printerpagecounter = self.storage.getPrinterPageCounter(printerid) 
    251269            try : 
    252                 msg = "%9i" % printerpagecounter["pagecounter"] 
     270                msg = "%9i" % printer.LastJob.PrinterPageCounter 
    253271            except TypeError :      
    254272                msg = _("unknown") 
     
    258276            print _("Totals may be inaccurate if some users are members of several groups.") 
    259277                         
    260     def printQuota(self, name, quota, balance, limitby) : 
     278    def printQuota(self, entry, quota) : 
    261279        """Prints the quota information.""" 
    262         if quota is not None : 
    263             lifepagecounter = quota["lifepagecounter"] or 0 
    264             pagecounter = quota["pagecounter"] or 0 
    265             softlimit = quota["softlimit"] 
    266             hardlimit = quota["hardlimit"] 
    267             datelimit = quota["datelimit"] 
    268             if balance is not None : 
    269                 (balance, lifetimepaid) = balance 
    270             else :     
    271                 (balance, lifetimepaid) = (0.0, 0.0) 
    272             if datelimit is not None : 
    273                 now = DateTime.now() 
    274                 datelimit = DateTime.ISO.ParseDateTime(datelimit) 
    275                 if now >= datelimit : 
    276                     datelimit = "DENY" 
    277             else :     
    278                 datelimit = "" 
    279             if limitby == "balance" :     
    280                 reached = (((balance <= 0) and "+") or "-") + "B" 
    281             else : 
    282                 reached = (((softlimit is not None) and (pagecounter >= softlimit) and "+") or "-") + "Q" 
    283             balance = balance or 0.0     
    284             lifetimepaid = lifetimepaid or 0.0 
    285             strbalance = ("%5.2f" % balance)[:10] 
    286             strlifetimepaid = ("%6.2f" % lifetimepaid)[:10] 
    287             print "%-9.9s %s %7i %7s %7s %10s %-10.10s %8i %10s" % (name, reached, pagecounter, str(softlimit), str(hardlimit), strbalance, str(datelimit)[:10], lifepagecounter, strlifetimepaid) 
    288             return (lifepagecounter, lifetimepaid) 
     280        lifepagecounter = int(quota.LifePageCounter or 0) 
     281        pagecounter = int(quota.PageCounter or 0) 
     282        balance = float(entry.AccountBalance or 0.0) 
     283        lifetimepaid = float(entry.LifeTimePaid or 0.0) 
     284         
     285        if quota.DateLimit is not None : 
     286            now = DateTime.now() 
     287            datelimit = DateTime.ISO.ParseDateTime(quota.DateLimit) 
     288            if now >= datelimit : 
     289                datelimit = "DENY" 
     290        elif (quota.HardLimit is not None) and (pagecounter >= quota.HardLimit) :     
     291            datelimit = "DENY" 
     292        elif (quota.HardLimit is None) and (quota.SoftLimit is not None) and (pagecounter >= quota.SoftLimit) : 
     293            datelimit = "DENY" 
    289294        else :     
    290             return (0, 0) 
    291          
     295            datelimit = "" 
     296             
     297        if entry.LimitBy.lower() == "balance" :     
     298            reached = (((balance <= 0) and "+") or "-") + "B" 
     299        else : 
     300            reached = (((quota.SoftLimit is not None) and (pagecounter >= quota.SoftLimit) and "+") or "-") + "Q" 
     301             
     302        strbalance = ("%5.2f" % balance)[:10] 
     303        strlifetimepaid = ("%6.2f" % lifetimepaid)[:10] 
     304        print "%-9.9s %s %7i %7s %7s %10s %-10.10s %8i %10s" % (entry.Name, reached, pagecounter, str(quota.SoftLimit), str(quota.HardLimit), strbalance, str(datelimit)[:10], lifepagecounter, strlifetimepaid) 
     305        return (lifepagecounter, lifetimepaid) 
    292306                     
    293307if __name__ == "__main__" :  
     
    318332        elif options["users"] and options["groups"] :     
    319333            raise PyKotaToolError, _("incompatible options, see help.") 
    320         elif args :     
    321             raise PyKotaToolError, _("unused arguments [%s]. Aborting.") % ", ".join(args) 
    322334        else : 
    323             sys.exit(reporter.main(options)) 
     335            sys.exit(reporter.main(args, options)) 
    324336    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError), msg :             
    325337        sys.stderr.write("%s\n" % msg) 
  • pykota/trunk/bin/warnpykota

    r975 r1041  
    2323# 
    2424# $Log$ 
     25# Revision 1.20  2003/06/25 14:10:01  jalet 
     26# Hey, it may work (edpykota --reset excepted) ! 
     27# 
    2528# Revision 1.19  2003/04/29 22:03:38  jalet 
    2629# Better error handling. 
     
    8487 
    8588import sys 
     89import os 
     90import pwd 
     91import grp 
    8692 
    8793from pykota import version 
     
    96102command line usage : 
    97103 
    98   warnpykota [options]  
     104  warnpykota  [options]  [names] 
    99105 
    100106options : 
     
    125131  any printer. 
    126132 
    127   $ warnpykota --groups --printer "laserjet*" 
    128    
    129   This will warn all users of groups which have exceeded  
    130   their print quota on any printer which name begins with "laserjet" 
     133  $ warnpykota --groups --printer "laserjet*" "dev*" 
     134   
     135  This will warn all users of groups which names begins with "dev" and 
     136  who have exceeded their print quota on any printer which name begins  
     137  with "laserjet" 
     138   
     139  If launched by a non-root user, additionnal arguments representing 
     140  users or groups names are ignored, and only the current user/group 
     141  is warned. 
    131142 
    132143This program is free software; you can redistribute it and/or modify 
     
    148159class WarnPyKota(PyKotaTool) :         
    149160    """A class for warnpykota.""" 
    150     def main(self, options) : 
     161    def main(self, ugnames, options) : 
    151162        """Warn users or groups over print quota.""" 
     163        uid = os.geteuid() 
     164        if not uid : 
     165            # root user 
     166            if not ugnames : 
     167                # no username, means all usernames 
     168                ugnames = [ "*" ] 
     169        else :         
     170            # not the root user 
     171            # warns only the current user 
     172            # the utility of this is discutable, but at least it 
     173            # protects other users from mail bombing if they are 
     174            # over quota. 
     175            if options["groups"] : 
     176                ugnames = [ grp.getgrgid(pwd.getpwuid(uid)[3])[0] ] 
     177            else : 
     178                ugnames = [ pwd.getpwuid(uid)[0] ] 
     179         
    152180        printers = self.storage.getMatchingPrinters(options["printer"]) 
    153181        if not printers : 
    154182            raise PyKotaToolError, _("There's no printer matching %s") % options["printer"] 
    155         for (printerid, printer) in printers : 
     183        for printer in printers : 
    156184            if options["groups"] : 
    157                 for (ident, name) in self.storage.getPrinterGroups(printerid) : 
    158                     self.warnGroupPQuota(name, printer) 
     185                for (group, grouppquota) in self.storage.getPrinterGroupsAndQuotas(printer, ugnames) : 
     186                    self.warnGroupPQuota(grouppquota) 
    159187            else : 
    160                 for (ident, name) in self.storage.getPrinterUsers(printerid) : 
    161                     self.warnUserPQuota(name, printer) 
     188                for (user, userpquota) in self.storage.getPrinterUsersAndQuotas(printer, ugnames) : 
     189                    self.warnUserPQuota(userpquota) 
    162190                      
    163191if __name__ == "__main__" :  
     
    188216        elif options["users"] and options["groups"] :     
    189217            raise PyKotaToolError, _("incompatible options, see help.") 
    190         elif args :     
    191             raise PyKotaToolError, _("unused arguments [%s]. Aborting.") % ", ".join(args) 
    192218        else : 
    193             sys.exit(sender.main(options)) 
     219            sys.exit(sender.main(args, options)) 
    194220    except (PyKotaToolError, PyKotaConfigError, PyKotaStorageError), msg :             
    195221        sys.stderr.write("%s\n" % msg) 
  • pykota/trunk/initscripts/ldap/pykota.schema

    r1036 r1041  
    5555attributetype ( 1.3.6.1.4.1.16868.1.1.6 NAME 'pykotaSoftLimit' 
    5656        DESC 'Soft limit in maximal number of pages' 
    57         EQUALITY integerMatch 
    58         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) 
     57        EQUALITY caseIgnoreIA5Match 
     58        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) 
    5959         
    6060# pykotaHardLimit         
    6161attributetype ( 1.3.6.1.4.1.16868.1.1.7 NAME 'pykotaHardLimit' 
    6262        DESC 'Hard limit in maximal number of pages' 
    63         EQUALITY integerMatch 
    64         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) 
     63        EQUALITY caseIgnoreIA5Match 
     64        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) 
    6565 
    6666# pykotaDateLimit 
     
    9797attributetype ( 1.3.6.1.4.1.16868.1.1.13 NAME 'pykotaJobSize' 
    9898        DESC 'Current job size in number of pages in the history' 
    99         EQUALITY integerMatch 
    100         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) 
     99        EQUALITY caseIgnoreIA5Match 
     100        SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) 
    101101 
    102102# pykotaAction 
  • pykota/trunk/NEWS

    r1029 r1041  
    2222PyKota NEWS : 
    2323 
     24    - 1.09alpha2 : 
     25     
     26        - LDAP schema modified a bit. Please upgrade. 
     27         
     28        - LDAP backend works ! 
     29         
     30        - repykota and warnpykota allow the root user to pass 
     31          users or groups names on the command line. Users  
     32          and groups names may contain wildcards. 
     33           
     34        - repykota and warnpykota only reports or warns the 
     35          current user when launched by non-root users. 
     36           
     37        - Minor bug fixes.   
     38     
    2439    - 1.09alpha1 : 
    2540     
  • pykota/trunk/pykota/accounters/external.py

    r1000 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.4  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.3  2003/05/27 23:00:21  jalet 
    2427# Big rewrite of external accounting methods. 
     
    4144 
    4245class Accounter(AccounterBase) : 
    43     def doAccounting(self, printerid, userid) : 
     46    def doAccounting(self, printer, user) : 
    4447        """Deletgates the computation of the job size to an external command. 
    4548         
     
    5053             
    5154        # get last job information for this printer 
    52         pgc = self.filter.storage.getPrinterPageCounter(printerid)     
    53         if pgc is None : 
     55        if not printer.LastJob.Exists : 
    5456            # The printer hasn't been used yet, from PyKota's point of view 
    5557            counterbeforejob = 0 
     
    5860            # Last lifetime page counter before actual job is  
    5961            # last page counter + last job size 
    60             counterbeforejob = (pgc["pagecounter"] or 0) + (pgc["jobsize"] or 0) 
     62            counterbeforejob = int(printer.LastJob.PrinterPageCounter or 0) + int(printer.LastJob.JobSize or 0) 
    6163             
    6264        # Is the current user allowed to print at all ? 
    63         action = self.filter.warnUserPQuota(self.filter.username, self.filter.printername) 
     65        userpquota = self.filter.storage.getUserPQuota(user, printer) 
     66        action = self.filter.warnUserPQuota(userpquota) 
    6467         
    6568        # update the quota for the current user on this printer, if allowed to print 
     
    6770            jobsize = 0 
    6871        else :     
    69             self.filter.storage.updateUserPQuota(userid, printerid, jobsize) 
     72            userpquota.increasePagesUsage(jobsize) 
    7073         
    7174        # adds the current job to history     
    72         self.filter.storage.addJobToHistory(self.filter.jobid, self.filter.storage.getUserId(self.filter.username), printerid, counterbeforejob, action, jobsize) 
     75        printer.addJobToHistory(self.filter.jobid, user, counterbeforejob, action, jobsize) 
    7376             
    7477        return action 
     
    102105            # launches child process 
    103106            command = "%s <%s >%s 2>%s" % (self.arguments, infilename, outfilename, errfilename) 
    104             o = open("/tmp/comm", "w") 
    105             o.write("%s\n" % command) 
    106             o.close() 
    107107            retcode = os.system(command) 
    108108             
  • pykota/trunk/pykota/accounters/querying.py

    r988 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.4  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.3  2003/05/06 14:55:47  jalet 
    2427# Missing import ! 
     
    3841from pykota.requester import openRequester, PyKotaRequesterError 
    3942 
    40 MAXTRIES = 6     # maximum number of tries to get the printer's internal page counter 
     43MAXTRIES = 12    # maximum number of tries to get the printer's internal page counter 
    4144TIMETOSLEEP = 10 # number of seconds to sleep between two tries to get the printer's internal page counter 
    4245 
    4346class Accounter(AccounterBase) : 
    44     def doAccounting(self, printerid, userid) : 
     47    def doAccounting(self, printer, user) : 
    4548        """Does print accounting and returns if the job status is ALLOW or DENY.""" 
    4649        # Get the page counter directly from the printer itself 
     
    6568         
    6669        # get last job information for this printer 
    67         pgc = self.filter.storage.getPrinterPageCounter(printerid)     
    68         if pgc is None : 
     70        if not printer.LastJob.Exists : 
    6971            # The printer hasn't been used yet, from PyKota's point of view 
    70             lasthistoryid = None 
    71             lastjobid = self.filter.jobid 
    72             lastuserid = userid 
    73             lastusername = self.filter.username 
     72            lastjob = None 
     73            lastuser = user 
    7474            lastpagecounter = counterbeforejob 
    7575        else :     
    7676            # get last values from Quota Storage 
    77             (lasthistoryid, lastjobid, lastuserid, lastusername, lastpagecounter) = (pgc["id"], pgc["jobid"], pgc["userid"], pgc["username"], pgc["pagecounter"]) 
     77            lastjob = printer.LastJob 
     78            lastuser = printer.LastJob.User 
     79            lastpagecounter = printer.LastJob.PrinterPageCounter 
    7880             
    7981        # if printer is off then we assume the correct counter value is the last one 
     
    107109            # For more accurate accounting, don't switch off your HP printers ! 
    108110            # explanation at : http://web.mit.edu/source/third/lprng/doc/LPRng-HOWTO-15.html 
    109             self.filter.logger.log_message(_("Error in page count value %i for user %s on printer %s") % (jobsize, lastusername, self.filter.printername), "error") 
     111            self.filter.logger.log_message(_("Error in page count value %i for user %s on printer %s") % (jobsize, lastuser.Name, self.filter.printername), "error") 
    110112            jobsize = abs(int((10 - abs(jobsize)) / 2))     # Workaround for HP printers' feature ! 
    111113             
    112114        # update the quota for the previous user on this printer  
    113         self.filter.storage.updateUserPQuota(lastuserid, printerid, jobsize) 
     115        lastuserquota = self.filter.storage.getUserPQuota(lastuser, printer) 
     116        if lastuserquota.Exists : 
     117            lastuserquota.increasePagesUsage(jobsize) 
    114118         
    115119        # update the last job size in the history 
    116         self.filter.storage.updateJobSizeInHistory(lasthistoryid, jobsize) 
     120        if printer.LastJob.Exists : 
     121            printer.LastJob.setSize(jobsize) 
    117122         
    118123        # warns the last user if he is over quota 
    119         self.filter.warnUserPQuota(lastusername, self.filter.printername) 
     124        if lastuserquota.Exists : 
     125            self.filter.warnUserPQuota(lastuserquota) 
    120126             
    121127        # Is the current user allowed to print at all ? 
    122         action = self.filter.warnUserPQuota(self.filter.username, self.filter.printername) 
     128        action = self.filter.warnUserPQuota(self.filter.storage.getUserPQuota(user, printer)) 
    123129         
    124130        # adds the current job to history     
    125         self.filter.storage.addJobToHistory(self.filter.jobid, self.filter.storage.getUserId(self.filter.username), printerid, counterbeforejob, action) 
     131        printer.addJobToHistory(self.filter.jobid, user, counterbeforejob, action) 
    126132             
    127133        return action 
  • pykota/trunk/pykota/accounters/stupid.py

    r1000 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.4  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.3  2003/05/27 23:00:21  jalet 
    2427# Big rewrite of external accounting methods. 
     
    3942 
    4043class Accounter(AccounterBase) : 
    41     def doAccounting(self, printerid, userid) : 
     44    def doAccounting(self, printer, user) : 
    4245        """Does print accounting by stupidly counting the 'showpage' postscript instructions in the document. 
    4346         
     
    5154             
    5255        # get last job information for this printer 
    53         pgc = self.filter.storage.getPrinterPageCounter(printerid)     
    54         if pgc is None : 
     56        if not printer.LastJob.Exists : 
    5557            # The printer hasn't been used yet, from PyKota's point of view 
    5658            counterbeforejob = 0 
     
    5961            # Last lifetime page counter before actual job is  
    6062            # last page counter + last job size 
    61             counterbeforejob = (pgc["pagecounter"] or 0) + (pgc["jobsize"] or 0) 
     63            counterbeforejob = int(printer.LastJob.PrinterPageCounter or 0) + int(printer.LastJob.JobSize or 0) 
    6264             
    6365        # Is the current user allowed to print at all ? 
    64         action = self.filter.warnUserPQuota(self.filter.username, self.filter.printername) 
     66        userpquota = self.filter.storage.getUserPQuota(user, printer) 
     67        action = self.filter.warnUserPQuota(userpquota) 
    6568         
    6669        # update the quota for the current user on this printer, if allowed to print 
     
    6871            jobsize = 0 
    6972        else :     
    70             self.filter.storage.updateUserPQuota(userid, printerid, jobsize) 
     73            userpquota.increasePagesUsage(jobsize) 
    7174         
    7275        # adds the current job to history     
    73         self.filter.storage.addJobToHistory(self.filter.jobid, self.filter.storage.getUserId(self.filter.username), printerid, counterbeforejob, action, jobsize) 
     76        printer.addJobToHistory(self.filter.jobid, user, counterbeforejob, action, jobsize) 
    7477             
    7578        return action 
  • pykota/trunk/pykota/config.py

    r1029 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.30  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.29  2003/06/14 22:44:21  jalet 
    2427# More work on LDAP storage backend. 
     
    201204        ldapinfo = {} 
    202205        for option in [ "userbase", "userrdn", \ 
     206                        "balancebase", "balancerdn", \ 
    203207                        "groupbase", "grouprdn", "groupmembers", \ 
    204208                        "printerbase", "printerrdn", \ 
  • pykota/trunk/pykota/storage.py

    r1021 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.14  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.13  2003/06/10 16:37:54  jalet 
    2427# Deletion of the second user which is not needed anymore. 
     
    8487    __str__ = __repr__ 
    8588         
     89class StorageObject : 
     90    """Object present in the Quota Storage.""" 
     91    def __init__(self, parent) : 
     92        "Initialize minimal data.""" 
     93        self.parent = parent 
     94        self.ident = None 
     95        self.Exists = 0 
     96         
     97class StorageUser(StorageObject) :         
     98    """User class.""" 
     99    def __init__(self, parent, name) : 
     100        StorageObject.__init__(self, parent) 
     101        self.Name = name 
     102        self.LimitBy = None 
     103        self.AccountBalance = None 
     104        self.LifeTimePaid = None 
     105         
     106    def consumeAccountBalance(self, amount) :      
     107        """Consumes an amount of money from the user's account balance.""" 
     108        newbalance = float(self.AccountBalance or 0.0) - amount 
     109        self.parent.writeUserAccountBalance(self, newbalance) 
     110        self.AccountBalance = newbalance 
     111         
     112    def setAccountBalance(self, balance, lifetimepaid) :     
     113        """Sets the user's account balance in case he pays more money.""" 
     114         
     115    def setLimitBy(self, limitby) :     
     116        """Sets the user's limiting factor.""" 
     117        limitby = limitby.lower() 
     118        if limitby in ["quota", "balance"] : 
     119            self.parent.writeUserLimitBy(self, limitby) 
     120            self.LimitBy = limitby 
     121         
     122    def delete(self) :     
     123        """Deletes an user from the Quota Storage.""" 
     124        self.parent.beginTransaction() 
     125        try : 
     126            self.parent.deleteUser(self) 
     127        except PyKotaStorageError, msg :     
     128            self.parent.rollbackTransaction() 
     129            raise PyKotaStorageError, msg 
     130        else :     
     131            self.parent.commitTransaction() 
     132         
     133class StorageGroup(StorageObject) :         
     134    """User class.""" 
     135    def __init__(self, parent, name) : 
     136        StorageObject.__init__(self, parent) 
     137        self.Name = name 
     138        self.LimitBy = None 
     139        self.AccountBalance = None 
     140        self.LifeTimePaid = None 
     141         
     142    def setLimitBy(self, limitby) :     
     143        """Sets the user's limiting factor.""" 
     144        limitby = limitby.lower() 
     145        if limitby in ["quota", "balance"] : 
     146            self.parent.writeGroupLimitBy(self, limitby) 
     147            self.LimitBy = limitby 
     148         
     149    def delete(self) :     
     150        """Deletes a group from the Quota Storage.""" 
     151        self.parent.beginTransaction() 
     152        try : 
     153            self.parent.deleteGroup(self) 
     154        except PyKotaStorageError, msg :     
     155            self.parent.rollbackTransaction() 
     156            raise PyKotaStorageError, msg 
     157        else :     
     158            self.parent.commitTransaction() 
     159         
     160class StoragePrinter(StorageObject) : 
     161    """Printer class.""" 
     162    def __init__(self, parent, name) : 
     163        StorageObject.__init__(self, parent) 
     164        self.Name = name 
     165        self.PricePerPage = None 
     166        self.PricePerJob = None 
     167        self.LastJob = None 
     168         
     169    def addJobToHistory(self, jobid, user, pagecounter, action, jobsize=None) :     
     170        """Adds a job to the printer's history.""" 
     171        self.parent.writeJobNew(self, user, jobid, pagecounter, action, jobsize) 
     172        # TODO : update LastJob object ? Probably not needed. 
     173         
     174    def setPrices(self, priceperpage = None, priceperjob = None) :     
     175        """Sets the printer's prices.""" 
     176        if priceperpage is None : 
     177            priceperpage = self.PricePerPage 
     178        else :     
     179            self.PricePerPage = float(priceperpage) 
     180        if priceperjob is None :     
     181            priceperjob = self.PricePerJob 
     182        else :     
     183            self.PricePerJob = float(priceperjob) 
     184        self.parent.writePrinterPrices(self) 
     185         
     186class StorageUserPQuota(StorageObject) : 
     187    """User Print Quota class.""" 
     188    def __init__(self, parent, user, printer) : 
     189        StorageObject.__init__(self, parent) 
     190        self.User = user 
     191        self.Printer = printer 
     192        self.PageCounter = None 
     193        self.LifePageCounter = None 
     194        self.SoftLimit = None 
     195        self.HardLimit = None 
     196        self.DateLimit = None 
     197         
     198    def setDateLimit(self, datelimit) :     
     199        """Sets the date limit for this quota.""" 
     200        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second) 
     201        self.parent.writeUserPQuotaDateLimit(self, date) 
     202        self.DateLimit = date 
     203         
     204    def setLimits(self, softlimit, hardlimit) :     
     205        """Sets the soft and hard limit for this quota.""" 
     206        self.parent.writeUserPQuotaLimits(self, softlimit, hardlimit) 
     207        self.SoftLimit = softlimit 
     208        self.HardLimit = hardlimit 
     209         
     210    def reset(self) :     
     211        """Resets page counter to 0.""" 
     212        self.parent.writeUserPQuotaPagesCounters(self, 0, int(self.LifePageCounter or 0)) 
     213        self.PageCounter = 0 
     214         
     215    def increasePagesUsage(self, nbpages) : 
     216        """Increase the value of used pages and money.""" 
     217        if nbpages : 
     218            jobprice = (float(self.Printer.PricePerPage or 0.0) * nbpages) + float(self.Printer.PricePerJob or 0.0) 
     219            newpagecounter = int(self.PageCounter or 0) + nbpages 
     220            newlifepagecounter = int(self.LifePageCounter or 0) + nbpages 
     221            self.parent.beginTransaction() 
     222            try : 
     223                if jobprice : # optimization : don't access the database if unneeded. 
     224                    self.User.consumeAccountBalance(jobprice) 
     225                self.parent.writeUserPQuotaPagesCounters(self, newpagecounter, newlifepagecounter) 
     226            except PyKotaStorageError, msg :     
     227                self.parent.rollbackTransaction() 
     228                raise PyKotaStorageError, msg 
     229            else :     
     230                self.parent.commitTransaction() 
     231                self.PageCounter = newpagecounter 
     232                self.LifePageCounter = newlifepagecounter 
     233         
     234class StorageGroupPQuota(StorageObject) : 
     235    """Group Print Quota class.""" 
     236    def __init__(self, parent, group, printer) : 
     237        StorageObject.__init__(self, parent) 
     238        self.Group = group 
     239        self.Printer = printer 
     240        self.PageCounter = None 
     241        self.LifePageCounter = None 
     242        self.SoftLimit = None 
     243        self.HardLimit = None 
     244        self.DateLimit = None 
     245         
     246    def setDateLimit(self, datelimit) :     
     247        """Sets the date limit for this quota.""" 
     248        date = "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second) 
     249        self.parent.writeGroupPQuotaDateLimit(self, date) 
     250        self.DateLimit = date 
     251         
     252    def setLimits(self, softlimit, hardlimit) :     
     253        """Sets the soft and hard limit for this quota.""" 
     254        self.parent.writeGroupPQuotaLimits(self, softlimit, hardlimit) 
     255        self.SoftLimit = softlimit 
     256        self.HardLimit = hardlimit 
     257         
     258class StorageLastJob(StorageObject) : 
     259    """Printer's Last Job class.""" 
     260    def __init__(self, parent, printer) : 
     261        StorageObject.__init__(self, parent) 
     262        self.Printer = printer 
     263        self.JobId = None 
     264        self.User = None 
     265        self.PrinterPageCounter = None 
     266        self.JobSize = None 
     267        self.JobAction = None 
     268        self.JobDate = None 
     269         
     270    def setSize(self, jobsize) : 
     271        """Sets the last job's size.""" 
     272        self.parent.writeLastJobSize(self, jobsize) 
     273        self.JobSize = jobsize 
     274     
    86275def openConnection(pykotatool) : 
    87276    """Returns a connection handle to the appropriate Quota Storage Database.""" 
  • pykota/trunk/pykota/storages/ldapstorage.py

    r1032 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.11  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.10  2003/06/16 21:55:15  jalet 
    2427# More work on LDAP, again. Problem detected. 
     
    6669import time 
    6770import md5 
    68 import fnmatch 
    6971 
    7072from pykota.storage import PyKotaStorageError 
     73from pykota.storage import StorageObject,StorageUser,StorageGroup,StoragePrinter,StorageLastJob,StorageUserPQuota,StorageGroupPQuota 
    7174 
    7275try : 
     
    114117        return md5.md5("%s" % time.time()).hexdigest() 
    115118         
     119    def beginTransaction(self) :     
     120        """Starts a transaction.""" 
     121        if self.debug : 
     122            self.tool.logger.log_message("Transaction begins... WARNING : No transactions in LDAP !", "debug") 
     123         
     124    def commitTransaction(self) :     
     125        """Commits a transaction.""" 
     126        if self.debug : 
     127            self.tool.logger.log_message("Transaction committed. WARNING : No transactions in LDAP !", "debug") 
     128         
     129    def rollbackTransaction(self) :      
     130        """Rollbacks a transaction.""" 
     131        if self.debug : 
     132            self.tool.logger.log_message("Transaction aborted. WARNING : No transaction in LDAP !", "debug") 
     133         
    116134    def doSearch(self, key, fields=None, base="", scope=ldap.SCOPE_SUBTREE) : 
    117135        """Does an LDAP search query.""" 
     
    119137            base = base or self.basedn 
    120138            if self.debug : 
    121                 self.tool.logger.log_message("QUERY : BaseDN : %s, Scope : %s, Filter : %s, Attributes : %s" % (base, scope, key, fields), "debug") 
     139                self.tool.logger.log_message("QUERY : Filter : %s, BaseDN : %s, Scope : %s, Attributes : %s" % (key, base, scope, fields), "debug") 
    122140            result = self.database.search_s(base or self.basedn, scope, key, fields) 
    123141        except ldap.LDAPError :     
     
    139157            return dn 
    140158             
    141     def doModify(self, dn, fields) : 
     159    def doDelete(self, dn) : 
     160        """Deletes an entry from the LDAP directory.""" 
     161        try : 
     162            if self.debug : 
     163                self.tool.logger.log_message("QUERY : Delete(%s)" % dn, "debug") 
     164            self.database.delete_s(dn) 
     165        except ldap.LDAPError : 
     166            raise PyKotaStorageError, _("Problem deleting LDAP entry (%s)") % dn 
     167             
     168    def doModify(self, dn, fields, ignoreold=1) : 
    142169        """Modifies an entry in the LDAP directory.""" 
    143170        try : 
     
    145172            if self.debug : 
    146173                self.tool.logger.log_message("QUERY : Modify(%s, %s ==> %s)" % (dn, oldentry[0][1], fields), "debug") 
    147             self.database.modify_s(dn, modlist.modifyModlist(oldentry[0][1], fields, ignore_oldexistent=1)) 
     174            self.database.modify_s(dn, modlist.modifyModlist(oldentry[0][1], fields, ignore_oldexistent=ignoreold)) 
    148175        except ldap.LDAPError : 
    149176            raise PyKotaStorageError, _("Problem modifying LDAP entry (%s, %s)") % (dn, fields) 
    150177        else : 
    151178            return dn 
     179             
     180    def getUser(self, username) :     
     181        """Extracts user information given its name.""" 
     182        user = StorageUser(self, username) 
     183        result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaLimitBy"], base=self.info["userbase"]) 
     184        if result : 
     185            fields = result[0][1] 
     186            user.ident = result[0][0] 
     187            user.LimitBy = fields.get("pykotaLimitBy")[0] 
     188            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["balancerdn"], username), ["pykotaBalance", "pykotaLifeTimePaid"], base=self.info["balancebase"]) 
     189            if result : 
     190                fields = result[0][1] 
     191                user.idbalance = result[0][0] 
     192                user.AccountBalance = fields.get("pykotaBalance") 
     193                if user.AccountBalance is not None : 
     194                    if user.AccountBalance[0].upper() == "NONE" : 
     195                        user.AccountBalance = None 
     196                    else :     
     197                        user.AccountBalance = float(user.AccountBalance[0]) 
     198                user.AccountBalance = user.AccountBalance or 0.0         
     199                user.LifeTimePaid = fields.get("pykotaLifeTimePaid") 
     200                if user.LifeTimePaid is not None : 
     201                    if user.LifeTimePaid[0].upper() == "NONE" : 
     202                        user.LifeTimePaid = None 
     203                    else :     
     204                        user.LifeTimePaid = float(user.LifeTimePaid[0]) 
     205                user.LifeTimePaid = user.LifeTimePaid or 0.0         
     206            user.Exists = 1 
     207        return user 
     208        
     209    def getGroup(self, groupname) :     
     210        """Extracts group information given its name.""" 
     211        group = StorageGroup(self, groupname) 
     212        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (groupname, self.info["grouprdn"], groupname), ["pykotaLimitBy"], base=self.info["groupbase"]) 
     213        if result : 
     214            fields = result[0][1] 
     215            group.ident = result[0][0] 
     216            group.LimitBy = fields.get("pykotaLimitBy")[0] 
     217            group.AccountBalance = 0.0 
     218            group.LifeTimePaid = 0.0 
     219            group.Members = self.getGroupMembers(group) 
     220            for member in group.Members : 
     221                group.AccountBalance += member.AccountBalance 
     222                group.LifeTimePaid += member.LifeTimePaid 
     223            group.Exists = 1 
     224        return group 
     225        
     226    def getPrinter(self, printername) :         
     227        """Extracts printer information given its name.""" 
     228        printer = StoragePrinter(self, printername) 
     229        result = self.doSearch("(&(objectClass=pykotaPrinter)(|(pykotaPrinterName=%s)(%s=%s)))" % (printername, self.info["printerrdn"], printername), ["pykotaPricePerPage", "pykotaPricePerJob"], base=self.info["printerbase"]) 
     230        if result : 
     231            fields = result[0][1] 
     232            printer.ident = result[0][0] 
     233            printer.PricePerJob = float(fields.get("pykotaPricePerJob")[0] or 0.0) 
     234            printer.PricePerPage = float(fields.get("pykotaPricePerPage")[0] or 0.0) 
     235            printer.LastJob = self.getPrinterLastJob(printer) 
     236            printer.Exists = 1 
     237        return printer     
     238             
     239    def getUserGroups(self, user) :         
     240        """Returns the user's groups list.""" 
     241        groups = [] 
     242        result = self.doSearch("(&(objectClass=pykotaGroup)(%s=%s))" % (self.info["groupmembers"], user.Name), [self.info["grouprdn"]], base=self.info["groupbase"]) 
     243        if result : 
     244            for (groupid, fields) in result : 
     245                groups.append(self.getGroup(fields.get(self.info["grouprdn"])[0])) 
     246        return groups         
     247         
     248    def getGroupMembers(self, group) :         
     249        """Returns the group's members list.""" 
     250        groupmembers = [] 
     251        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (group.Name, self.info["grouprdn"], group.Name), [self.info["groupmembers"]], base=self.info["groupbase"]) 
     252        if result : 
     253            for username in result[0][1].get(self.info["groupmembers"], []) : 
     254                groupmembers.append(self.getUser(username)) 
     255        return groupmembers         
     256         
     257    def getUserPQuota(self, user, printer) :         
     258        """Extracts a user print quota.""" 
     259        userpquota = StorageUserPQuota(self, user, printer) 
     260        if user.Exists : 
     261            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s)(pykotaPrinterName=%s))" % (user.Name, printer.Name), ["pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["userquotabase"]) 
     262            if result : 
     263                fields = result[0][1] 
     264                userpquota.ident = result[0][0] 
     265                userpquota.PageCounter = int(fields.get("pykotaPageCounter")[0] or 0) 
     266                userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter")[0] or 0) 
     267                userpquota.SoftLimit = fields.get("pykotaSoftLimit") 
     268                if userpquota.SoftLimit is not None : 
     269                    if userpquota.SoftLimit[0].upper() == "NONE" : 
     270                        userpquota.SoftLimit = None 
     271                    else :     
     272                        userpquota.SoftLimit = int(userpquota.SoftLimit[0]) 
     273                userpquota.HardLimit = fields.get("pykotaHardLimit") 
     274                if userpquota.HardLimit is not None : 
     275                    if userpquota.HardLimit[0].upper() == "NONE" : 
     276                        userpquota.HardLimit = None 
     277                    elif userpquota.HardLimit is not None :     
     278                        userpquota.HardLimit = int(userpquota.HardLimit[0]) 
     279                userpquota.DateLimit = fields.get("pykotaDateLimit") 
     280                if userpquota.DateLimit is not None : 
     281                    if userpquota.DateLimit[0].upper() == "NONE" :  
     282                        userpquota.DateLimit = None 
     283                    else :     
     284                        userpquota.DateLimit = userpquota.DateLimit[0] 
     285                userpquota.Exists = 1 
     286        return userpquota 
     287         
     288    def getGroupPQuota(self, group, printer) :         
     289        """Extracts a group print quota.""" 
     290        grouppquota = StorageGroupPQuota(self, group, printer) 
     291        if group.Exists : 
     292            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaGroupName=%s)(pykotaPrinterName=%s))" % (group.Name, printer.Name), ["pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["groupquotabase"]) 
     293            if result : 
     294                fields = result[0][1] 
     295                grouppquota.ident = result[0][0] 
     296                grouppquota.SoftLimit = fields.get("pykotaSoftLimit") 
     297                if grouppquota.SoftLimit is not None : 
     298                    if grouppquota.SoftLimit[0].upper() == "NONE" : 
     299                        grouppquota.SoftLimit = None 
     300                    else :     
     301                        grouppquota.SoftLimit = int(grouppquota.SoftLimit[0]) 
     302                grouppquota.HardLimit = fields.get("pykotaHardLimit") 
     303                if grouppquota.HardLimit is not None : 
     304                    if grouppquota.HardLimit[0].upper() == "NONE" : 
     305                        grouppquota.HardLimit = None 
     306                    else :     
     307                        grouppquota.HardLimit = int(grouppquota.HardLimit[0]) 
     308                grouppquota.DateLimit = fields.get("pykotaDateLimit") 
     309                if grouppquota.DateLimit is not None : 
     310                    if grouppquota.DateLimit[0].upper() == "NONE" :  
     311                        grouppquota.DateLimit = None 
     312                    else :     
     313                        grouppquota.DateLimit = grouppquota.DateLimit[0] 
     314                grouppquota.PageCounter = 0 
     315                grouppquota.LifePageCounter = 0 
     316                if (not hasattr(group, "Members")) or (group.Members is None) : 
     317                    group.Members = self.getGroupMembers(group) 
     318                usernamesfilter = "".join(["(pykotaUserName=%s)" % member.Name for member in group.Members]) 
     319                result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s)(|%s))" % (printer.Name, usernamesfilter), ["pykotaPageCounter", "pykotaLifePageCounter"], base=self.info["userquotabase"]) 
     320                if result : 
     321                    for userpquota in result :     
     322                        grouppquota.PageCounter += int(userpquota[1].get("pykotaPageCounter")[0] or 0) 
     323                        grouppquota.LifePageCounter += int(userpquota[1].get("pykotaLifePageCounter")[0] or 0) 
     324                grouppquota.Exists = 1 
     325        return grouppquota 
     326         
     327    def getPrinterLastJob(self, printer) :         
     328        """Extracts a printer's last job information.""" 
     329        lastjob = StorageLastJob(self, printer) 
     330        result = self.doSearch("(&(objectClass=pykotaLastjob)(|(pykotaPrinterName=%s)(%s=%s)))" % (printer.Name, self.info["printerrdn"], printer.Name), ["pykotaLastJobIdent"], base=self.info["lastjobbase"]) 
     331        if result : 
     332            lastjob.lastjobident = result[0][0] 
     333            lastjobident = result[0][1]["pykotaLastJobIdent"][0] 
     334            result = self.doSearch("objectClass=pykotaJob", ["pykotaUserName", "pykotaJobId", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "createTimestamp"], base="cn=%s,%s" % (lastjobident, self.info["jobbase"]), scope=ldap.SCOPE_BASE) 
     335            if result : 
     336                fields = result[0][1] 
     337                lastjob.ident = result[0][0] 
     338                lastjob.JobId = fields.get("pykotaJobId")[0] 
     339                lastjob.User = self.getUser(fields.get("pykotaUserName")[0]) 
     340                lastjob.PrinterPageCounter = int(fields.get("pykotaPrinterPageCounter")[0] or 0) 
     341                lastjob.JobSize = int(fields.get("pykotaJobSize", [0])[0]) 
     342                lastjob.JobAction = fields.get("pykotaAction")[0] 
     343                date = fields.get("createTimestamp")[0] 
     344                year = int(date[:4]) 
     345                month = int(date[4:6]) 
     346                day = int(date[6:8]) 
     347                hour = int(date[8:10]) 
     348                minute = int(date[10:12]) 
     349                second = int(date[12:14]) 
     350                lastjob.JobDate = "%04i-%02i-%02i %02i:%02i:%02i" % (year, month, day, hour, minute, second) 
     351                lastjob.Exists = 1 
     352        return lastjob 
    152353         
    153354    def getMatchingPrinters(self, printerpattern) : 
    154         """Returns the list of all printers as tuples (id, name) for printer names which match a certain pattern.""" 
    155         result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=self.info["printerbase"]) 
    156         if result : 
    157             return [(printerid, printer["pykotaPrinterName"][0]) for (printerid, printer) in result if fnmatch.fnmatchcase(printer["pykotaPrinterName"][0], printerpattern)] 
    158              
    159     def getPrinterId(self, printername) :         
    160         """Returns a printerid given a printername.""" 
    161         result = self.doSearch("(&(objectClass=pykotaPrinter)(|(pykotaPrinterName=%s)(%s=%s)))" % (printername, self.info["printerrdn"], printername), ["pykotaPrinterName"], base=self.info["printerbase"]) 
    162         if result : 
    163             return result[0][0] 
    164              
    165     def getPrinterName(self, printerid) :         
    166         """Returns a printerid given a printer id.""" 
    167         result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"], base=printerid, scope=ldap.SCOPE_BASE) 
    168         if result : 
    169             return result[0][1]["pykotaPrinterName"][0] 
    170              
    171     def getPrinterPrices(self, printerid) :         
    172         """Returns a printer prices per page and per job given a printerid.""" 
    173         result = self.doSearch("(|(pykotaPrinterName=*)(%s=*))" % self.info["printerrdn"], ["pykotaPricePerPage", "pykotaPricePerJob"], base=printerid, scope=ldap.SCOPE_BASE) 
    174         if result : 
    175             return (float(result[0][1]["pykotaPricePerPage"][0]), float(result[0][1]["pykotaPricePerJob"][0])) 
    176              
    177     def setPrinterPrices(self, printerid, perpage, perjob) : 
    178         """Sets prices per job and per page for a given printer.""" 
    179         fields = {  
    180                    "pykotaPricePerPage" : str(perpage), 
    181                    "pykotaPricePerJob" : str(perjob), 
    182                  }  
    183         return self.doModify(printerid, fields) 
    184      
    185     def getUserId(self, username) : 
    186         """Returns a userid given a username.""" 
    187         result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), [self.info["userrdn"]], base=self.info["userbase"]) 
    188         if result : 
    189             return result[0][0] 
    190              
    191     def getUserName(self, userid) : 
    192         """Returns a username given a userid.""" 
    193         result = self.doSearch("objectClass=pykotaAccount", ["pykotaUserName"], base=userid, scope=ldap.SCOPE_BASE) 
    194         if result : 
    195             return result[0][1]["pykotaUserName"][0] 
    196              
    197     def getGroupId(self, groupname) : 
    198         """Returns a groupid given a grupname.""" 
    199         result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (groupname, self.info["grouprdn"], groupname), [self.info["grouprdn"]], base=self.info["groupbase"]) 
    200         if result is not None : 
    201             (groupid, dummy) = result[0] 
    202             return groupid 
    203              
    204     def getJobHistoryId(self, jobid, userid, printerid) :         
    205         """Returns the history line's id given a (jobid, userid, printerid). 
    206          
    207            TODO : delete because shouldn't be needed by the LDAP backend 
    208         """ 
    209         raise PyKotaStorageError, "Not implemented !" 
    210              
    211     def getPrinterUsers(self, printerid) :         
    212         """Returns the list of userids and usernames which uses a given printer.""" 
    213         # first get the printer's name from the id 
    214         result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", self.info["printerrdn"]], base=printerid, scope=ldap.SCOPE_BASE) 
    215         if result : 
    216             fields = result[0][1] 
    217             printername = (fields.get("pykotaPrinterName") or fields.get(self.info["printerrdn"]))[0] 
    218             result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaUserName"], base=self.info["userquotabase"])  
    219             if result : 
    220                 return [(pquotauserid, fields["pykotaUserName"][0]) for (pquotauserid, fields) in result] 
    221          
    222     def getPrinterGroups(self, printerid) :         
    223         """Returns the list of groups which uses a given printer.""" 
    224         # first get the printer's name from the id 
    225         result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", self.info["printerrdn"]], base=printerid, scope=ldap.SCOPE_BASE) 
    226         if result : 
    227             fields = result[0][1] 
    228             printername = (fields.get("pykotaPrinterName") or fields.get(self.info["printerrdn"]))[0] 
    229             result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaGroupName"], base=self.info["groupquotabase"])  
    230             if result : 
    231                 return [(pquotagroupid, fields["pykotaGroupName"][0]) for (pquotagroupid, fields) in result] 
    232          
    233     def getGroupMembersNames(self, groupname) :         
    234         """Returns the list of user's names which are member of this group.""" 
    235         result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (groupname, self.info["grouprdn"], groupname), [self.info["groupmembers"]]) 
    236         if result : 
    237             fields = result[0][1] 
    238             return fields.get(self.info["groupmembers"]) 
    239          
    240     def getUserGroupsNames(self, userid) :         
    241         """Returns the list of groups' names the user is a member of.""" 
    242         username = self.getUserName(userid) 
    243         if username : 
    244             result = self.doSearch("(&(objectClass=pykotaGroup)(%s=%s))" % (self.info["groupmembers"], username), [self.info["grouprdn"]], base=self.info["groupbase"]) 
    245             if result : 
    246                 return [v[self.info["grouprdn"]][0] for (k, v) in result] 
    247         return []         
     355        """Returns the list of all printers for which name matches a certain pattern.""" 
     356        printers = [] 
     357        # see comment at the same place in pgstorage.py 
     358        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", "pykotaPricePerPage", "pykotaPricePerJob"], base=self.info["printerbase"]) 
     359        if result : 
     360            for (printerid, fields) in result : 
     361                printername = fields["pykotaPrinterName"][0] 
     362                if self.tool.matchString(printername, [ printerpattern ]) : 
     363                    printer = StoragePrinter(self, printername) 
     364                    printer.ident = printerid 
     365                    printer.PricePerJob = float(fields.get("pykotaPricePerJob")[0] or 0.0) 
     366                    printer.PricePerPage = float(fields.get("pykotaPricePerPage")[0] or 0.0) 
     367                    printer.LastJob = self.getPrinterLastJob(printer) 
     368                    printer.Exists = 1 
     369                    printers.append(printer) 
     370        return printers         
     371         
     372    def getPrinterUsersAndQuotas(self, printer, names=None) :         
     373        """Returns the list of users who uses a given printer, along with their quotas.""" 
     374        usersandquotas = [] 
     375        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printer.Name, ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=self.info["userquotabase"]) 
     376        if result : 
     377            for (userquotaid, fields) in result : 
     378                user = self.getUser(fields["pykotaUserName"][0]) 
     379                if (names is None) or self.tool.matchString(user.Name, names) : 
     380                    userpquota = StorageUserPQuota(self, user, printer) 
     381                    userpquota.ident = userquotaid 
     382                    userpquota.PageCounter = int(fields.get("pykotaPageCounter")[0] or 0) 
     383                    userpquota.LifePageCounter = int(fields.get("pykotaLifePageCounter")[0] or 0) 
     384                    userpquota.SoftLimit = fields.get("pykotaSoftLimit") 
     385                    if userpquota.SoftLimit is not None : 
     386                        if userpquota.SoftLimit[0].upper() == "NONE" : 
     387                            userpquota.SoftLimit = None 
     388                        else :     
     389                            userpquota.SoftLimit = int(userpquota.SoftLimit[0]) 
     390                    userpquota.HardLimit = fields.get("pykotaHardLimit") 
     391                    if userpquota.HardLimit is not None : 
     392                        if userpquota.HardLimit[0].upper() == "NONE" : 
     393                            userpquota.HardLimit = None 
     394                        elif userpquota.HardLimit is not None :     
     395                            userpquota.HardLimit = int(userpquota.HardLimit[0]) 
     396                    userpquota.DateLimit = fields.get("pykotaDateLimit") 
     397                    if userpquota.DateLimit is not None : 
     398                        if userpquota.DateLimit[0].upper() == "NONE" :  
     399                            userpquota.DateLimit = None 
     400                        else :     
     401                            userpquota.DateLimit = userpquota.DateLimit[0] 
     402                    userpquota.Exists = 1 
     403                    usersandquotas.append((user, userpquota)) 
     404        return usersandquotas 
     405                 
     406    def getPrinterGroupsAndQuotas(self, printer, names=None) :         
     407        """Returns the list of groups which uses a given printer, along with their quotas.""" 
     408        groupsandquotas = [] 
     409        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printer.Name, ["pykotaGroupName"], base=self.info["groupquotabase"]) 
     410        if result : 
     411            for (groupquotaid, fields) in result : 
     412                group = self.getGroup(fields.get("pykotaGroupName")[0]) 
     413                if (names is None) or self.tool.matchString(user.Name, names) : 
     414                    grouppquota = self.getGroupPQuota(group, printer) 
     415                    groupsandquotas.append((group, grouppquota)) 
     416        return groupsandquotas 
    248417         
    249418    def addPrinter(self, printername) :         
    250         """Adds a printer to the quota storage, returns its id.""" 
     419        """Adds a printer to the quota storage, returns it.""" 
    251420        fields = { self.info["printerrdn"] : printername, 
    252421                   "objectClass" : ["pykotaObject", "pykotaPrinter"], 
     422                   "cn" : printername, 
    253423                   "pykotaPrinterName" : printername, 
    254424                   "pykotaPricePerPage" : "0.0", 
     
    256426                 }  
    257427        dn = "%s=%s,%s" % (self.info["printerrdn"], printername, self.info["printerbase"]) 
    258         return self.doAdd(dn, fields) 
    259          
    260     def addUser(self, username) :         
    261         """Adds a user to the quota storage, returns its id.""" 
    262         fields = { self.info["userrdn"] : username, 
    263                    "objectClass" : ["pykotaObject", "pykotaAccount", "pykotaAccountBalance"], 
    264                    "pykotaUserName" : username, 
    265                    "pykotaLimitBy" : "quota", 
    266                    "pykotaBalance" : "0.0", 
    267                    "pykotaLifeTimePaid" : "0.0", 
     428        self.doAdd(dn, fields) 
     429        return self.getPrinter(printername) 
     430         
     431    def addUser(self, user) :         
     432        """Adds a user to the quota storage, returns it.""" 
     433        fields = { self.info["userrdn"] : user.Name, 
     434                   "objectClass" : ["pykotaObject", "pykotaAccount"], 
     435                   "cn" : user.Name, 
     436                   "pykotaUserName" : user.Name, 
     437                   "pykotaLimitBY" : (user.LimitBy or "quota"), 
    268438                 }  
    269         dn = "%s=%s,%s" % (self.info["userrdn"], username, self.info["userbase"]) 
    270         return self.doAdd(dn, fields) 
    271          
    272     def addGroup(self, groupname) :         
    273         """Adds a group to the quota storage, returns its id.""" 
    274         fields = { self.info["grouprdn"] : groupname, 
     439        dn = "%s=%s,%s" % (self.info["userrdn"], user.Name, self.info["userbase"]) 
     440        self.doAdd(dn, fields) 
     441        fields = {  
     442                   "objectClass" : ["pykotaObject", "pykotaAccountBalance"], 
     443                   "cn" : user.Name, 
     444                   "pykotaUserName" : user.Name, 
     445                   "pykotaBalance" : str(user.AccountBalance or 0.0), 
     446                   "pykotaLifeTimePaid" : str(user.LifeTimePaid or 0.0), 
     447                 }  
     448        dn = "cn=%s,%s" % (user.Name, self.info["balancebase"]) 
     449        self.doAdd(dn, fields) 
     450        return self.getUser(user.Name) 
     451         
     452    def addGroup(self, group) :         
     453        """Adds a group to the quota storage, returns it.""" 
     454        fields = { self.info["grouprdn"] : group.Name, 
    275455                   "objectClass" : ["pykotaObject", "pykotaGroup"], 
    276                    "pykotaGroupName" : groupname, 
    277                    "pykotaLimitBy" : "quota", 
     456                   "cn" : group.Name, 
     457                   "pykotaGroupName" : group.Name, 
     458                   "pykotaLimitBY" : (group.LimitBy or "quota"), 
    278459                 }  
    279         dn = "%s=%s,%s" % (self.info["grouprdn"], groupname, self.info["groupbase"]) 
    280         return self.doAdd(dn, fields) 
    281          
    282     def addUserPQuota(self, username, printerid) : 
    283         """Initializes a user print quota on a printer, adds the user to the quota storage if needed.""" 
     460        dn = "%s=%s,%s" % (self.info["grouprdn"], group.Name, self.info["groupbase"]) 
     461        self.doAdd(dn, fields) 
     462        return self.getGroup(group.Name) 
     463         
     464    def addUserToGroup(self, user, group) :     
     465        """Adds an user to a group.""" 
     466        if user.Name not in [u.Name for u in group.Members] : 
     467            result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)     
     468            if result : 
     469                fields = result[0][1] 
     470                fields[self.info["groupmembers"]].append(user.Name) 
     471                self.doModify(group.ident, fields) 
     472                group.Members.append(user) 
     473                 
     474    def addUserPQuota(self, user, printer) : 
     475        """Initializes a user print quota on a printer.""" 
    284476        uuid = self.genUUID() 
    285         fields = { "objectClass" : ["pykotaObject", "pykotaUserPQuota"], 
    286                    "cn" : uuid, 
    287                    "pykotaUserName" : username, 
    288                    "pykotaPrinterName" : self.getPrinterName(printerid),  
     477        fields = { "cn" : uuid, 
     478                   "objectClass" : ["pykotaObject", "pykotaUserPQuota"], 
     479                   "pykotaUserName" : user.Name, 
     480                   "pykotaPrinterName" : printer.Name, 
     481                   "pykotaDateLimit" : "None", 
    289482                   "pykotaPageCounter" : "0", 
    290483                   "pykotaLifePageCounter" : "0", 
    291                    "pykotaSoftLimit" : "0", 
    292                    "pykotaHardLimit" : "0", 
    293                    "pykotaDateLimit" : "None", 
    294484                 }  
    295485        dn = "cn=%s,%s" % (uuid, self.info["userquotabase"]) 
    296486        self.doAdd(dn, fields) 
    297         return (dn, printerid) 
    298          
    299     def addGroupPQuota(self, groupname, printerid) : 
    300         """Initializes a group print quota on a printer, adds the group to the quota storage if needed.""" 
     487        return self.getUserPQuota(user, printer) 
     488         
     489    def addGroupPQuota(self, group, printer) : 
     490        """Initializes a group print quota on a printer.""" 
    301491        uuid = self.genUUID() 
    302         fields = { "objectClass" : ["pykotaObject", "pykotaGroupPQuota"], 
    303                    "cn" : uuid, 
    304                    "pykotaGroupName" : groupname, 
    305                    "pykotaPrinterName" : self.getPrinterName(printerid),  
    306                    "pykotaSoftLimit" : "0", 
    307                    "pykotaHardLimit" : "0", 
     492        fields = { "cn" : uuid, 
     493                   "objectClass" : ["pykotaObject", "pykotaGroupPQuota"], 
     494                   "pykotaGroupName" : group.Name, 
     495                   "pykotaPrinterName" : printer.Name, 
    308496                   "pykotaDateLimit" : "None", 
    309497                 }  
    310498        dn = "cn=%s,%s" % (uuid, self.info["groupquotabase"]) 
    311499        self.doAdd(dn, fields) 
    312         return (dn, printerid) 
    313          
    314     def increaseUserBalance(self, userquotaid, amount) :     
    315         """Increases (or decreases) an user's account balance by a given amount.""" 
    316         balance = self.getUserBalance(userquotaid) 
    317         if balance : 
    318             (newbal, newpaid) = [(float(v) + float(amount)) for v in balance] 
    319             result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    320             if result : 
    321                 username = result[0][1]["pykotaUserName"][0] 
    322                 if username : 
    323                     result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % username , [ "pykotaBalance", "pykotaLifeTimePaid"]) 
    324                     fields = { 
    325                                "pykotaBalance" : str(newbal), 
    326                                "pykotaLifeTimePaid" : str(newpaid), 
    327                              } 
    328                     return self.doModify(result[0][0], fields)          
    329          
    330     def getUserBalance(self, userquotaid) :     
    331         """Returns the current account balance for a given user quota identifier.""" 
    332         # first get the user's name from the user quota id 
    333         result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    334         if result : 
    335             username = result[0][1]["pykotaUserName"][0] 
    336             result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaBalance", "pykotaLifeTimePaid"]) 
    337             if result : 
    338                 fields = result[0][1] 
    339                 return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0])) 
    340          
    341     def getUserBalanceFromUserId(self, userid) :     
    342         """Returns the current account balance for a given user id.""" 
    343         # first get the user's name from the user id 
    344         result = self.doSearch("objectClass=pykotaAccount", ["pykotaUserName", self.info["userrdn"]], base=userid, scope=ldap.SCOPE_BASE) 
    345         if result : 
    346             fields = result[0][1] 
    347             username = (fields.get("pykotaUserName") or fields.get(self.info["userrdn"]))[0] 
    348             result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaBalance", "pykotaLifeTimePaid"]) 
    349             if result : 
    350                 fields = result[0][1] 
    351                 return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0])) 
    352          
    353     def getGroupBalance(self, groupquotaid) :     
    354         """Returns the current account balance for a given group, as the sum of each of its users' account balance.""" 
    355         # first get the group's name from the group quota id 
    356         result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE) 
    357         if result : 
    358             groupname = result[0][1]["pykotaGroupName"][0] 
    359             members = self.getGroupMembersNames(groupname) or [] 
    360             balance = lifetimepaid = 0.0 
    361             for member in members : 
    362                 userid = self.getUserId(member) 
    363                 if userid : 
    364                     userbal = self.getUserBalanceFromUserId(userid) 
    365                     if userbal : 
    366                         (bal, paid) = userbal 
    367                         balance += bal 
    368                         lifetimepaid += paid 
    369             return (balance, lifetimepaid)             
    370          
    371     def getUserLimitBy(self, userquotaid) :     
    372         """Returns the way in which user printing is limited.""" 
    373         result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    374         if result : 
    375             username = result[0][1]["pykotaUserName"][0] 
    376             result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(%s=%s)))" % (username, self.info["userrdn"], username), ["pykotaLimitBy"]) 
    377             if result : 
    378                 return result[0][1]["pykotaLimitBy"][0] 
    379          
    380     def getGroupLimitBy(self, groupquotaid) :     
    381         """Returns the way in which group printing is limited.""" 
    382         # first get the group's name from the group quota id 
    383         result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE) 
    384         if result : 
    385             groupname = result[0][1]["pykotaGroupName"][0] 
    386             result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(%s=%s)))" % (groupname, self.info["grouprdn"], groupname), ["pykotaLimitBy"]) 
    387             if result : 
    388                 return result[0][1]["pykotaLimitBy"][0] 
    389          
    390     def setUserBalance(self, userquotaid, balance) :     
    391         """Sets the account balance for a given user to a fixed value.""" 
    392         oldbalance = self.getUserBalance(userquotaid) 
    393         if oldbalance : 
    394             (oldbal, oldpaid) = oldbalance 
    395             difference = balance - oldbal 
    396             return self.increaseUserBalance(userquotaid, difference) 
    397          
    398     def limitUserBy(self, userquotaid, limitby) :     
    399         """Limits a given user based either on print quota or on account balance.""" 
    400         result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    401         if result : 
    402             username = result[0][1]["pykotaUserName"][0] 
    403             fields = { 
    404                        "pykotaLimitBy" : limitby, 
    405                      } 
    406             self.doModify(self.getUserId(username), fields) 
    407          
    408     def limitGroupBy(self, groupquotaid, limitby) :     
    409         """Limits a given group based either on print quota or on sum of its users' account balances.""" 
    410         result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE) 
    411         if result : 
    412             groupname = result[0][1]["pykotaGroupName"][0] 
    413             fields = { 
    414                        "pykotaLimitBy" : limitby, 
    415                      } 
    416             self.doModify(self.getGroupId(groupname), fields) 
    417          
    418     def setUserPQuota(self, userquotaid, printerid, softlimit, hardlimit) : 
    419         """Sets soft and hard limits for a user quota on a specific printer given (userid, printerid).""" 
    420         fields = {  
    421                    "pykotaSoftLimit" : str(softlimit), 
    422                    "pykotaHardLimit" : str(hardlimit), 
    423                    "pykotaDateLimit" : "None", 
    424                  }  
    425         return self.doModify(userquotaid, fields) 
    426          
    427     def setGroupPQuota(self, groupquotaid, printerid, softlimit, hardlimit) : 
    428         """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid).""" 
    429         fields = {  
    430                    "pykotaSoftLimit" : str(softlimit), 
    431                    "pykotaHardLimit" : str(hardlimit), 
    432                    "pykotaDateLimit" : "None", 
    433                  }  
    434         return self.doModify(groupquotaid, fields) 
    435          
    436     def resetUserPQuota(self, userquotaid, printerid) :     
    437         """Resets the page counter to zero for a user on a printer. Life time page counter is kept unchanged.""" 
    438         fields = { 
    439                    "pykotaPageCounter" : "0", 
    440                    "pykotaDateLimit" : "None", 
    441                  } 
    442         return self.doModify(userquotaid, fields)       
    443          
    444     def resetGroupPQuota(self, groupquotaid, printerid) :     
    445         """Resets the page counter to zero for a group on a printer. Life time page counter is kept unchanged.""" 
    446         fields = { 
    447                    "pykotaPageCounter" : "0", 
    448                    "pykotaDateLimit" : "None", 
    449                  } 
    450         return self.doModify(groupquotaid, fields)       
    451          
    452     def updateUserPQuota(self, userquotaid, printerid, pagecount) : 
    453         """Updates the used user Quota information given (userid, printerid) and a job size in pages.""" 
    454         jobprice = self.computePrinterJobPrice(printerid, pagecount) 
    455         result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaPageCounter", "pykotaLifePageCounter"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    456         if result : 
    457             oldfields = result[0][1] 
    458             fields = { 
    459                        "pykotaPageCounter" : str(pagecount + int(oldfields["pykotaPageCounter"][0])), 
    460                        "pykotaLifePageCounter" : str(pagecount + int(oldfields["pykotaLifePageCounter"][0])), 
    461                      }   
    462             return self.doModify(userquotaid, fields)          
    463          
    464     def getUserPQuota(self, userquotaid, printerid) : 
    465         """Returns the Print Quota information for a given (userquotaid, printerid).""" 
    466         # first get the user's name from the id 
    467         result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=userquotaid, scope=ldap.SCOPE_BASE) 
    468         if result : 
    469             fields = result[0][1] 
    470             datelimit = fields["pykotaDateLimit"][0].strip() 
    471             if (not datelimit) or (datelimit.upper() == "NONE") :  
    472                 datelimit = None 
    473             return { "lifepagecounter" : int(fields["pykotaLifePageCounter"][0]),  
    474                      "pagecounter" : int(fields["pykotaPageCounter"][0]), 
    475                      "softlimit" : int(fields["pykotaSoftLimit"][0]), 
    476                      "hardlimit" : int(fields["pykotaHardLimit"][0]), 
    477                      "datelimit" : datelimit 
    478                    } 
    479          
    480     def getGroupPQuota(self, grouppquotaid, printerid) : 
    481         """Returns the Print Quota information for a given (grouppquotaid, printerid).""" 
    482         result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=grouppquotaid, scope=ldap.SCOPE_BASE) 
    483         if result : 
    484             fields = result[0][1] 
    485             groupname = fields["pykotaGroupName"][0] 
    486             datelimit = fields["pykotaDateLimit"][0].strip() 
    487             if (not datelimit) or (datelimit.upper() == "NONE") :  
    488                 datelimit = None 
    489             quota = { 
    490                       "softlimit" : int(fields["pykotaSoftLimit"][0]), 
    491                       "hardlimit" : int(fields["pykotaHardLimit"][0]), 
    492                       "datelimit" : datelimit 
    493                     } 
    494             members = self.getGroupMembersNames(groupname) or [] 
    495             pagecounter = lifepagecounter = 0 
    496             printerusers = self.getPrinterUsers(printerid) 
    497             if printerusers : 
    498                 for (userid, username) in printerusers : 
    499                     if username in members : 
    500                         userpquota = self.getUserPQuota(userid, printerid) 
    501                         if userpquota : 
    502                             pagecounter += userpquota["pagecounter"] 
    503                             lifepagecounter += userpquota["lifepagecounter"] 
    504             quota.update({"pagecounter": pagecounter, "lifepagecounter": lifepagecounter})                 
    505             return quota 
    506          
    507     def setUserDateLimit(self, userquotaid, printerid, datelimit) : 
    508         """Sets the limit date for a soft limit to become an hard one given (userid, printerid).""" 
     500        return self.getGroupPQuota(group, printer) 
     501         
     502    def writePrinterPrices(self, printer) :     
     503        """Write the printer's prices back into the storage.""" 
     504        fields = { 
     505                   "pykotaPricePerPage" : str(printer.PricePerPage), 
     506                   "pykotaPricePerJob" : str(printer.PricePerJob), 
     507                 } 
     508        self.doModify(printer.ident, fields) 
     509         
     510    def writeUserLimitBy(self, user, limitby) :     
     511        """Sets the user's limiting factor.""" 
     512        fields = { 
     513                   "pykotaLimitBy" : limitby, 
     514                 } 
     515        self.doModify(user.ident, fields)          
     516         
     517    def writeGroupLimitBy(self, group, limitby) :     
     518        """Sets the group's limiting factor.""" 
     519        fields = { 
     520                   "pykotaLimitBy" : limitby, 
     521                 } 
     522        self.doModify(group.ident, fields)          
     523         
     524    def writeUserPQuotaDateLimit(self, userpquota, datelimit) :     
     525        """Sets the date limit permanently for a user print quota.""" 
    509526        fields = { 
    510527                   "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second), 
    511528                 } 
    512         return self.doModify(userquotaid, fields) 
    513          
    514     def setGroupDateLimit(self, groupquotaid, printerid, datelimit) : 
    515         """Sets the limit date for a soft limit to become an hard one given (groupid, printerid).""" 
     529        return self.doModify(userpquota.ident, fields) 
     530             
     531    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :     
     532        """Sets the date limit permanently for a group print quota.""" 
    516533        fields = { 
    517534                   "pykotaDateLimit" : "%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second), 
    518535                 } 
    519         return self.doModify(groupquotaid, fields) 
    520          
    521     def addJobToHistory(self, jobid, userid, printerid, pagecounter, action, jobsize=None) : 
    522         """Adds a job to the history: (jobid, userid, printerid, last page counter taken from requester).""" 
     536        return self.doModify(grouppquota.ident, fields) 
     537         
     538    def writeUserPQuotaPagesCounters(self, userpquota, newpagecounter, newlifepagecounter) :     
     539        """Sets the new page counters permanently for a user print quota.""" 
     540        fields = { 
     541                   "pykotaPageCounter" : str(newpagecounter), 
     542                   "pykotaLifePageCounter" : str(newlifepagecounter), 
     543                 }   
     544        return self.doModify(userpquota.ident, fields)          
     545        
     546    def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) :     
     547        """Sets the new account balance and eventually new lifetime paid.""" 
     548        fields = { 
     549                   "pykotaBalance" : str(newbalance), 
     550                 } 
     551        if newlifetimepaid is not None : 
     552            fields.update({ "pykotaLifeTimePaid" : str(newlifetimepaid) }) 
     553        return self.doModify(user.idbalance, fields)          
     554             
     555    def writeLastJobSize(self, lastjob, jobsize) :         
     556        """Sets the last job's size permanently.""" 
     557        fields = { 
     558                   "pykotaJobSize" : str(jobsize), 
     559                 } 
     560        self.doModify(lastjob.ident, fields)          
     561         
     562    def writeJobNew(self, printer, user, jobid, pagecounter, action, jobsize=None) :     
     563        """Adds a job in a printer's history.""" 
    523564        uuid = self.genUUID() 
    524         printername = self.getPrinterName(printerid) 
    525565        fields = { 
    526566                   "objectClass" : ["pykotaObject", "pykotaJob"], 
    527567                   "cn" : uuid, 
    528                    "pykotaUserName" : self.getUserName(userid), 
    529                    "pykotaPrinterName" : printername, 
     568                   "pykotaUserName" : user.Name, 
     569                   "pykotaPrinterName" : printer.Name, 
    530570                   "pykotaJobId" : jobid, 
    531571                   "pykotaPrinterPageCounter" : str(pagecounter), 
     
    536576        dn = "cn=%s,%s" % (uuid, self.info["jobbase"]) 
    537577        self.doAdd(dn, fields) 
    538         result = self.doSearch("(&(objectClass=pykotaLastJob)(pykotaPrinterName=%s))" % printername, None, base=self.info["lastjobbase"]) 
    539         if result : 
    540             lastjdn = result[0][0]  
     578        if printer.LastJob.Exists : 
    541579            fields = { 
    542580                       "pykotaLastJobIdent" : uuid, 
    543581                     } 
    544             self.doModify(lastjdn, fields)          
     582            self.doModify(printer.LastJob.lastjobident, fields)          
    545583        else :     
    546584            lastjuuid = self.genUUID() 
     
    549587                       "objectClass" : ["pykotaObject", "pykotaLastJob"], 
    550588                       "cn" : lastjuuid, 
    551                        "pykotaPrinterName" : printername, 
     589                       "pykotaPrinterName" : printer.Name, 
    552590                       "pykotaLastJobIdent" : uuid, 
    553591                     }   
    554592            self.doAdd(lastjdn, fields)           
    555      
    556     def updateJobSizeInHistory(self, historyid, jobsize) : 
    557         """Updates a job size in the history given the history line's id.""" 
    558         result = self.doSearch("(&(objectClass=pykotaJob)(cn=%s))" % historyid, ["cn"], base=self.info["jobbase"]) 
    559         if result : 
    560             fields = { 
    561                        "pykotaJobSize" : str(jobsize), 
    562                      } 
    563             self.doModify(result[0][0], fields)          
    564      
    565     def getPrinterPageCounter(self, printerid) : 
    566         """Returns the last page counter value for a printer given its id, also returns last username, last jobid and history line id.""" 
    567         result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", self.info["printerrdn"]], base=printerid, scope=ldap.SCOPE_BASE) 
     593             
     594    def writeUserPQuotaLimits(self, userpquota, softlimit, hardlimit) : 
     595        """Sets soft and hard limits for a user quota.""" 
     596        fields = {  
     597                   "pykotaSoftLimit" : str(softlimit), 
     598                   "pykotaHardLimit" : str(hardlimit), 
     599                 } 
     600        self.doModify(userpquota.ident, fields) 
     601         
     602    def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : 
     603        """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid).""" 
     604        fields = {  
     605                   "pykotaSoftLimit" : str(softlimit), 
     606                   "pykotaHardLimit" : str(hardlimit), 
     607                 } 
     608        self.doModify(grouppquota.ident, fields) 
     609             
     610    def deleteUser(self, user) :     
     611        """Completely deletes an user from the Quota Storage.""" 
     612        # TODO : What should we do if we delete the last person who used a given printer ? 
     613        # TODO : we can't reassign the last job to the previous one, because next user would be 
     614        # TODO : incorrectly charged (overcharged). 
     615        result = self.doSearch("(&(objectClass=pykotaLastJob)(pykotaUserName=%s))" % user.Name, base=self.info["lastjobbase"]) 
     616        for (ident, fields) in result : 
     617            self.doDelete(ident) 
     618        result = self.doSearch("(&(objectClass=pykotaJob)(pykotaUserName=%s))" % user.Name, base=self.info["jobbase"]) 
     619        for (ident, fields) in result : 
     620            self.doDelete(ident) 
     621        result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaUserName=%s))" % user.Name, ["pykotaUserName"], base=self.info["userquotabase"]) 
     622        for (ident, fields) in result : 
     623            self.doDelete(ident) 
     624        result = self.doSearch("objectClass=pykotaAccount", None, base=user.ident, scope=ldap.SCOPE_BASE)     
    568625        if result : 
    569626            fields = result[0][1] 
    570             printername = (fields.get("pykotaPrinterName") or fields.get(self.info["printerrdn"]))[0] 
    571             result = self.doSearch("(&(objectClass=pykotaLastjob)(|(pykotaPrinterName=%s)(%s=%s)))" % (printername, self.info["printerrdn"], printername), ["pykotaLastJobIdent"], base=self.info["lastjobbase"]) 
    572             if result : 
    573                 lastjobident = result[0][1]["pykotaLastJobIdent"][0] 
    574                 result = self.doSearch("(&(objectClass=pykotaJob)(cn=%s))" % lastjobident, ["pykotaUserName", "pykotaPrinterName", "pykotaJobId", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "createTimestamp"], base=self.info["jobbase"]) 
    575                 if result : 
    576                     fields = result[0][1] 
    577                     return { "id": lastjobident,  
    578                              "jobid" : fields.get("pykotaJobId")[0], 
    579                              "userid" : self.getUserId(fields.get("pykotaUserName")[0]), 
    580                              "username" : fields.get("pykotaUserName")[0],  
    581                              "pagecounter" : int(fields.get("pykotaPrinterPageCounter")[0]), 
    582                              "jobsize" : int(fields.get("pykotaJobSize")[0]), 
    583                            } 
    584          
    585     def addUserToGroup(self, userid, groupid) :     
    586         """Adds an user to a group.""" 
    587         raise PyKotaStorageError, "Not implemented !" 
    588          
    589     def deleteUser(self, userid) :     
    590         """Completely deletes an user from the Quota Storage.""" 
    591         raise PyKotaStorageError, "Not implemented !" 
    592          
    593     def deleteGroup(self, groupid) :     
    594         """Completely deletes an user from the Quota Storage.""" 
    595         raise PyKotaStorageError, "Not implemented !" 
    596          
    597     def computePrinterJobPrice(self, printerid, jobsize) :     
    598         """Returns the price for a job on a given printer.""" 
    599         # TODO : create a base class with things like this 
    600         prices = self.getPrinterPrices(printerid) 
    601         if prices is None : 
    602             perpage = perjob = 0.0 
    603         else :     
    604             (perpage, perjob) = prices 
    605         return perjob + (perpage * jobsize) 
     627            for k in fields.keys() : 
     628                if k.startswith("pykota") : 
     629                    del fields[k] 
     630                elif k.lower() == "objectclass" :     
     631                    todelete = [] 
     632                    for i in range(len(fields[k])) : 
     633                        if fields[k][i].startswith("pykota") :  
     634                            todelete.append(i) 
     635                    todelete.sort()         
     636                    todelete.reverse() 
     637                    for i in todelete : 
     638                        del fields[k][i] 
     639            if fields.get("objectclass") :             
     640                self.doModify(user.ident, fields, ignoreold=0)         
     641            else :     
     642                self.doDelete(user.ident) 
     643        result = self.doSearch("(&(objectClass=pykotaAccountBalance)(pykotaUserName=%s))" % user.Name, ["pykotaUserName"], base=self.info["balancebase"]) 
     644        for (ident, fields) in result : 
     645            self.doDelete(ident) 
     646         
     647    def deleteGroup(self, group) :     
     648        """Completely deletes a group from the Quota Storage.""" 
     649        result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaGroupName=%s))" % group.Name, ["pykotaGroupName"], base=self.info["groupquotabase"]) 
     650        for (ident, fields) in result : 
     651            self.doDelete(ident) 
     652        result = self.doSearch("objectClass=pykotaGroup", None, base=group.ident, scope=ldap.SCOPE_BASE)     
     653        if result : 
     654            fields = result[0][1] 
     655            for k in fields.keys() : 
     656                if k.startswith("pykota") : 
     657                    del fields[k] 
     658                elif k.lower() == "objectclass" :     
     659                    todelete = [] 
     660                    for i in range(len(fields[k])) : 
     661                        if fields[k][i].startswith("pykota") :  
     662                            todelete.append(i) 
     663                    todelete.sort()         
     664                    todelete.reverse() 
     665                    for i in todelete : 
     666                        del fields[k][i] 
     667            if fields.get("objectclass") :             
     668                self.doModify(group.ident, fields, ignoreold=0)         
     669            else :     
     670                self.doDelete(group.ident) 
     671             
  • pykota/trunk/pykota/storages/pgstorage.py

    r1024 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.3  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.2  2003/06/12 21:09:57  jalet 
    2427# wrongly placed code. 
     
    3437# 
    3538 
    36 import fnmatch 
    37  
    3839from pykota.storage import PyKotaStorageError 
     40from pykota.storage import StorageObject,StorageUser,StorageGroup,StoragePrinter,StorageLastJob,StorageUserPQuota,StorageGroupPQuota 
    3941 
    4042try : 
     
    7476                self.tool.logger.log_message("Database closed.", "debug") 
    7577         
    76     def doQuery(self, query) : 
    77         """Does a query.""" 
    78         if type(query) in (type([]), type(())) : 
    79             query = ";".join(query) 
     78    def beginTransaction(self) :     
     79        """Starts a transaction.""" 
     80        self.database.query("BEGIN;") 
     81        if self.debug : 
     82            self.tool.logger.log_message("Transaction begins...", "debug") 
     83         
     84    def commitTransaction(self) :     
     85        """Commits a transaction.""" 
     86        self.database.query("COMMIT;") 
     87        if self.debug : 
     88            self.tool.logger.log_message("Transaction committed.", "debug") 
     89         
     90    def rollbackTransaction(self) :      
     91        """Rollbacks a transaction.""" 
     92        self.database.query("ROLLBACK;") 
     93        if self.debug : 
     94            self.tool.logger.log_message("Transaction aborted.", "debug") 
     95         
     96    def doSearch(self, query) : 
     97        """Does a search query.""" 
    8098        query = query.strip()     
    8199        if not query.endswith(';') :     
    82100            query += ';' 
    83         self.database.query("BEGIN;") 
    84         if self.debug : 
    85             self.tool.logger.log_message("Transaction began.", "debug") 
    86101        try : 
    87102            if self.debug : 
     
    89104            result = self.database.query(query) 
    90105        except pg.error, msg :     
    91             self.database.query("ROLLBACK;") 
    92             if self.debug : 
    93                 self.tool.logger.log_message("Transaction aborted.", "debug") 
    94106            raise PyKotaStorageError, msg 
    95107        else :     
    96             self.database.query("COMMIT;") 
     108            if (result is not None) and (result.ntuples() > 0) :  
     109                return result.dictresult() 
     110             
     111    def doModify(self, query) : 
     112        """Does a (possibly multiple) modify query.""" 
     113        query = query.strip()     
     114        if not query.endswith(';') :     
     115            query += ';' 
     116        try : 
    97117            if self.debug : 
    98                 self.tool.logger.log_message("Transaction committed.", "debug") 
    99             return result 
    100          
     118                self.tool.logger.log_message("QUERY : %s" % query, "debug") 
     119            result = self.database.query(query) 
     120        except pg.error, msg :     
     121            raise PyKotaStorageError, msg 
     122             
    101123    def doQuote(self, field) : 
    102124        """Quotes a field for use as a string in SQL queries.""" 
     
    109131        return pg._quote(field, typ) 
    110132         
    111     def doParseResult(self, result) : 
    112         """Returns the result as a list of Python mappings.""" 
    113         if (result is not None) and (result.ntuples() > 0) : 
    114             return result.dictresult() 
    115              
     133    def getUser(self, username) :     
     134        """Extracts user information given its name.""" 
     135        user = StorageUser(self, username) 
     136        result = self.doSearch("SELECT * FROM users WHERE username=%s LIMIT 1" % self.doQuote(username)) 
     137        if result : 
     138            fields = result[0] 
     139            user.ident = fields.get("id") 
     140            user.LimitBy = fields.get("limitby") 
     141            user.AccountBalance = fields.get("balance") 
     142            user.LifeTimePaid = fields.get("lifetimepaid") 
     143            user.Exists = 1 
     144        return user 
     145        
     146    def getGroup(self, groupname) :     
     147        """Extracts group information given its name.""" 
     148        group = StorageGroup(self, groupname) 
     149        result = self.doSearch("SELECT * FROM groups WHERE groupname=%s LIMIT 1" % self.doQuote(groupname)) 
     150        if result : 
     151            fields = result[0] 
     152            group.ident = fields.get("id") 
     153            group.LimitBy = fields.get("limitby") 
     154            result = self.doSearch("SELECT SUM(balance) AS balance, SUM(lifetimepaid) AS lifetimepaid FROM users WHERE id IN (SELECT userid FROM groupsmembers WHERE groupid=%s)" % self.doQuote(group.ident)) 
     155            if result : 
     156                fields = result[0] 
     157                group.AccountBalance = fields.get("balance") 
     158                group.LifeTimePaid = fields.get("lifetimepaid") 
     159            group.Exists = 1 
     160        return group 
     161        
     162    def getPrinter(self, printername) :         
     163        """Extracts printer information given its name.""" 
     164        printer = StoragePrinter(self, printername) 
     165        result = self.doSearch("SELECT * FROM printers WHERE printername=%s LIMIT 1" % self.doQuote(printername)) 
     166        if result : 
     167            fields = result[0] 
     168            printer.ident = fields.get("id") 
     169            printer.PricePerJob = fields.get("priceperjob") 
     170            printer.PricePerPage = fields.get("priceperpage") 
     171            printer.LastJob = self.getPrinterLastJob(printer) 
     172            printer.Exists = 1 
     173        return printer     
     174             
     175    def getUserGroups(self, user) :         
     176        """Returns the user's groups list.""" 
     177        groups = [] 
     178        result = self.doSearch("SELECT groupname FROM groupsmembers JOIN groups ON groupsmembers.groupid=groups.id WHERE userid=%s" % self.doQuote(user.ident)) 
     179        if result : 
     180            for record in result : 
     181                groups.append(self.getGroup(record.get("groupname"))) 
     182        return groups         
     183         
     184    def getGroupMembers(self, group) :         
     185        """Returns the group's members list.""" 
     186        groupmembers = [] 
     187        result = self.doSearch("SELECT * FROM groupsmembers JOIN users ON groupsmembers.userid=users.id WHERE groupid=%s" % self.doQuote(group.ident)) 
     188        if result : 
     189            for record in result : 
     190                user = StorageUser(self, record.get("username")) 
     191                user.ident = record.get("userid") 
     192                user.LimitBy = record.get("limitby") 
     193                user.AccountBalance = record.get("balance") 
     194                user.LifeTimePaid = record.get("lifetimepaid") 
     195                user.Exists = 1 
     196                groupmembers.append(user) 
     197        return groupmembers         
     198         
     199    def getUserPQuota(self, user, printer) :         
     200        """Extracts a user print quota.""" 
     201        userpquota = StorageUserPQuota(self, user, printer) 
     202        if user.Exists : 
     203            result = self.doSearch("SELECT id, lifepagecounter, pagecounter, softlimit, hardlimit, datelimit FROM userpquota WHERE userid=%s AND printerid=%s" % (self.doQuote(user.ident), self.doQuote(printer.ident))) 
     204            if result : 
     205                fields = result[0] 
     206                userpquota.ident = fields.get("id") 
     207                userpquota.PageCounter = fields.get("pagecounter") 
     208                userpquota.LifePageCounter = fields.get("lifepagecounter") 
     209                userpquota.SoftLimit = fields.get("softlimit") 
     210                userpquota.HardLimit = fields.get("hardlimit") 
     211                userpquota.DateLimit = fields.get("datelimit") 
     212                userpquota.Exists = 1 
     213        return userpquota 
     214         
     215    def getGroupPQuota(self, group, printer) :         
     216        """Extracts a group print quota.""" 
     217        grouppquota = StorageGroupPQuota(self, group, printer) 
     218        if group.Exists : 
     219            result = self.doSearch("SELECT id, softlimit, hardlimit, datelimit FROM grouppquota WHERE groupid=%s AND printerid=%s" % (self.doQuote(group.ident), self.doQuote(printer.ident))) 
     220            if result : 
     221                fields = result[0] 
     222                grouppquota.ident = fields.get("id") 
     223                grouppquota.SoftLimit = fields.get("softlimit") 
     224                grouppquota.HardLimit = fields.get("hardlimit") 
     225                grouppquota.DateLimit = fields.get("datelimit") 
     226                result = self.doSearch("SELECT SUM(lifepagecounter) AS lifepagecounter, SUM(pagecounter) AS pagecounter FROM userpquota WHERE printerid=%s AND userid IN (SELECT userid FROM groupsmembers WHERE groupid=%s)" % (self.doQuote(printer.ident), self.doQuote(group.ident))) 
     227                if result : 
     228                    fields = result[0] 
     229                    grouppquota.PageCounter = fields.get("pagecounter") 
     230                    grouppquota.LifePageCounter = fields.get("lifepagecounter") 
     231                grouppquota.Exists = 1 
     232        return grouppquota 
     233         
     234    def getPrinterLastJob(self, printer) :         
     235        """Extracts a printer's last job information.""" 
     236        lastjob = StorageLastJob(self, printer) 
     237        result = self.doSearch("SELECT jobhistory.id, jobid, userid, username, pagecounter, jobsize, jobdate FROM jobhistory, users WHERE printerid=%s AND userid=users.id ORDER BY jobdate DESC LIMIT 1" % self.doQuote(printer.ident)) 
     238        if result : 
     239            fields = result[0] 
     240            lastjob.ident = fields.get("id") 
     241            lastjob.JobId = fields.get("jobid") 
     242            lastjob.User = self.getUser(fields.get("username")) 
     243            lastjob.PrinterPageCounter = fields.get("pagecounter") 
     244            lastjob.JobSize = fields.get("jobsize") 
     245            lastjob.JobAction = fields.get("action") 
     246            lastjob.JobDate = fields.get("jobdate") 
     247            lastjob.Exists = 1 
     248        return lastjob 
     249         
    116250    def getMatchingPrinters(self, printerpattern) : 
    117         """Returns the list of all printers as tuples (id, name) for printer names which match a certain pattern.""" 
    118         printerslist = [] 
     251        """Returns the list of all printers for which name matches a certain pattern.""" 
     252        printers = [] 
    119253        # We 'could' do a SELECT printername FROM printers WHERE printername LIKE ... 
    120254        # but we don't because other storages semantics may be different, so every 
    121255        # storage should use fnmatch to match patterns and be storage agnostic 
    122         result = self.doQuery("SELECT id, printername FROM printers") 
    123         result = self.doParseResult(result) 
    124         if result is not None : 
    125             for printer in result : 
    126                 if fnmatch.fnmatchcase(printer["printername"], printerpattern) : 
    127                     printerslist.append((printer["id"], printer["printername"])) 
    128         return printerslist         
    129              
    130     def getPrinterId(self, printername) :         
    131         """Returns a printerid given a printername.""" 
    132         result = self.doQuery("SELECT id FROM printers WHERE printername=%s" % self.doQuote(printername)) 
    133         try : 
    134             return self.doParseResult(result)[0]["id"] 
    135         except TypeError :      # Not found     
    136             return 
    137              
    138     def getPrinterPrices(self, printerid) :         
    139         """Returns a printer prices per page and per job given a printerid.""" 
    140         result = self.doQuery("SELECT priceperpage, priceperjob FROM printers WHERE id=%s" % self.doQuote(printerid)) 
    141         try : 
    142             printerprices = self.doParseResult(result)[0] 
    143             return (printerprices["priceperpage"], printerprices["priceperjob"]) 
    144         except TypeError :      # Not found     
    145             return 
    146              
    147     def setPrinterPrices(self, printerid, perpage, perjob) : 
    148         """Sets prices per job and per page for a given printer.""" 
    149         self.doQuery("UPDATE printers SET priceperpage=%s, priceperjob=%s WHERE id=%s" % (self.doQuote(perpage), self.doQuote(perjob), self.doQuote(printerid))) 
    150      
    151     def getUserId(self, username) : 
    152         """Returns a userid given a username.""" 
    153         result = self.doQuery("SELECT id FROM users WHERE username=%s" % self.doQuote(username)) 
    154         try : 
    155             return self.doParseResult(result)[0]["id"] 
    156         except TypeError :      # Not found 
    157             return 
    158              
    159     def getGroupId(self, groupname) : 
    160         """Returns a groupid given a grupname.""" 
    161         result = self.doQuery("SELECT id FROM groups WHERE groupname=%s" % self.doQuote(groupname)) 
    162         try : 
    163             return self.doParseResult(result)[0]["id"] 
    164         except TypeError :      # Not found 
    165             return 
    166              
    167     def getJobHistoryId(self, jobid, userid, printerid) :         
    168         """Returns the history line's id given a (jobid, userid, printerid).""" 
    169         result = self.doQuery("SELECT id FROM jobhistory WHERE jobid=%s AND userid=%s AND printerid=%s" % (self.doQuote(jobid), self.doQuote(userid), self.doQuote(printerid))) 
    170         try : 
    171             return self.doParseResult(result)[0]["id"] 
    172         except TypeError :      # Not found     
    173             return 
    174              
    175     def getPrinterUsers(self, printerid) :         
    176         """Returns the list of userids and usernames which uses a given printer.""" 
    177         result = self.doQuery("SELECT DISTINCT id, username FROM users WHERE id IN (SELECT userid FROM userpquota WHERE printerid=%s) ORDER BY username" % self.doQuote(printerid)) 
    178         result = self.doParseResult(result) 
    179         if result is None : 
    180             return [] 
    181         else :     
    182             return [(record["id"], record["username"]) for record in result] 
    183          
    184     def getPrinterGroups(self, printerid) :         
    185         """Returns the list of groups which uses a given printer.""" 
    186         result = self.doQuery("SELECT DISTINCT id, groupname FROM groups WHERE id IN (SELECT groupid FROM grouppquota WHERE printerid=%s)" % self.doQuote(printerid)) 
    187         result = self.doParseResult(result) 
    188         if result is None : 
    189             return [] 
    190         else :     
    191             return [(record["id"], record["groupname"]) for record in result] 
    192          
    193     def getGroupMembersNames(self, groupname) :         
    194         """Returns the list of user's names which are member of this group.""" 
    195         groupid = self.getGroupId(groupname) 
    196         if groupid is None : 
    197             return [] 
    198         else : 
    199             result = self.doQuery("SELECT DISTINCT username FROM users WHERE id IN (SELECT userid FROM groupsmembers WHERE groupid=%s)" % self.doQuote(groupid)) 
    200             return [record["username"] for record in (self.doParseResult(result) or [])] 
    201          
    202     def getUserGroupsNames(self, userid) :         
    203         """Returns the list of groups' names the user is a member of.""" 
    204         result = self.doQuery("SELECT DISTINCT groupname FROM groups WHERE id IN (SELECT groupid FROM groupsmembers WHERE userid=%s)" % self.doQuote(userid)) 
    205         return [record["groupname"] for record in (self.doParseResult(result) or [])] 
     256        result = self.doSearch("SELECT * FROM printers") 
     257        if result : 
     258            for record in result : 
     259                if self.tool.matchString(record["printername"], [ printerpattern ]) : 
     260                    printer = StoragePrinter(self, record["printername"]) 
     261                    printer.ident = record.get("id") 
     262                    printer.PricePerJob = record.get("priceperjob") 
     263                    printer.PricePerPage = record.get("priceperpage") 
     264                    printer.LastJob = self.getPrinterLastJob(printer) 
     265                    printer.Exists = 1 
     266                    printers.append(printer) 
     267        return printers         
     268         
     269    def getPrinterUsersAndQuotas(self, printer, names=None) :         
     270        """Returns the list of users who uses a given printer, along with their quotas.""" 
     271        usersandquotas = [] 
     272        result = self.doSearch("SELECT users.id as uid,username,balance,lifetimepaid,limitby,userpquota.id,lifepagecounter,pagecounter,softlimit,hardlimit,datelimit FROM users JOIN userpquota ON users.id=userpquota.userid AND printerid=%s" % self.doQuote(printer.ident)) 
     273        if result : 
     274            for record in result : 
     275                user = StorageUser(self, record.get("username")) 
     276                if (names is None) or self.tool.matchString(user.Name, names) : 
     277                    user.ident = record.get("uid") 
     278                    user.LimitBy = record.get("limitby") 
     279                    user.AccountBalance = record.get("balance") 
     280                    user.LifeTimePaid = record.get("lifetimepaid") 
     281                    user.Exists = 1 
     282                    userpquota = StorageUserPQuota(self, user, printer) 
     283                    userpquota.ident = record.get("id") 
     284                    userpquota.PageCounter = record.get("pagecounter") 
     285                    userpquota.LifePageCounter = record.get("lifepagecounter") 
     286                    userpquota.SoftLimit = record.get("softlimit") 
     287                    userpquota.HardLimit = record.get("hardlimit") 
     288                    userpquota.DateLimit = record.get("datelimit") 
     289                    userpquota.Exists = 1 
     290                    usersandquotas.append((user, userpquota)) 
     291        return usersandquotas 
     292                 
     293    def getPrinterGroupsAndQuotas(self, printer, names=None) :         
     294        """Returns the list of groups which uses a given printer, along with their quotas.""" 
     295        groupsandquotas = [] 
     296        result = self.doSearch("SELECT groupname FROM groups JOIN grouppquota ON groups.id=grouppquota.groupid AND printerid=%s" % self.doQuote(printer.ident)) 
     297        if result : 
     298            for record in result : 
     299                group = self.getGroup(record.get("groupname")) 
     300                if (names is None) or self.tool.matchString(group.Name, names) : 
     301                    grouppquota = self.getGroupPQuota(group, printer) 
     302                    groupsandquotas.append((group, grouppquota)) 
     303        return groupsandquotas 
    206304         
    207305    def addPrinter(self, printername) :         
    208         """Adds a printer to the quota storage, returns its id.""" 
    209         self.doQuery("INSERT INTO printers (printername) VALUES (%s)" % self.doQuote(printername)) 
    210         return self.getPrinterId(printername) 
    211          
    212     def addUser(self, username) :         
     306        """Adds a printer to the quota storage, returns it.""" 
     307        self.doModify("INSERT INTO printers (printername) VALUES (%s)" % self.doQuote(printername)) 
     308        return self.getPrinter(printername) 
     309         
     310    def addUser(self, user) :         
    213311        """Adds a user to the quota storage, returns its id.""" 
    214         self.doQuery("INSERT INTO users (username) VALUES (%s)" % self.doQuote(username)) 
    215         return self.getUserId(username) 
    216          
    217     def addGroup(self, groupname) :         
     312        self.doModify("INSERT INTO users (username, limitby, balance, lifetimepaid) VALUES (%s, %s, %s, %s)" % (self.doQuote(user.Name), self.doQuote(user.LimitBy), self.doQuote(user.AccountBalance), self.doQuote(user.LifeTimePaid))) 
     313        return self.getUser(user.Name) 
     314         
     315    def addGroup(self, group) :         
    218316        """Adds a group to the quota storage, returns its id.""" 
    219         self.doQuery("INSERT INTO groups (groupname) VALUES (%s)" % self.doQuote(groupname)) 
    220         return self.getGroupId(groupname) 
    221          
    222     def addUserPQuota(self, username, printerid) : 
    223         """Initializes a user print quota on a printer, adds the user to the quota storage if needed.""" 
    224         userid = self.getUserId(username)      
    225         if userid is None :     
    226             userid = self.addUser(username) 
    227         uqexists = (self.getUserPQuota(userid, printerid) is not None)     
    228         if not uqexists :  
    229             self.doQuery("INSERT INTO userpquota (userid, printerid) VALUES (%s, %s)" % (self.doQuote(userid), self.doQuote(printerid))) 
    230         return (userid, printerid) 
    231          
    232     def addGroupPQuota(self, groupname, printerid) : 
    233         """Initializes a group print quota on a printer, adds the group to the quota storage if needed.""" 
    234         groupid = self.getGroupId(groupname)      
    235         if groupid is None :     
    236             groupid = self.addGroup(groupname) 
    237         gqexists = (self.getGroupPQuota(groupid, printerid) is not None)     
    238         if not gqexists :  
    239             self.doQuery("INSERT INTO grouppquota (groupid, printerid) VALUES (%s, %s)" % (self.doQuote(groupid), self.doQuote(printerid))) 
    240         return (groupid, printerid) 
    241          
    242     def increaseUserBalance(self, userid, amount) :     
    243         """Increases (or decreases) an user's account balance by a given amount.""" 
    244         self.doQuery("UPDATE users SET balance=balance+(%s), lifetimepaid=lifetimepaid+(%s) WHERE id=%s" % (self.doQuote(amount), self.doQuote(amount), self.doQuote(userid))) 
    245          
    246     def getUserBalance(self, userid) :     
    247         """Returns the current account balance for a given user.""" 
    248         result = self.doQuery("SELECT balance, lifetimepaid FROM users WHERE id=%s" % self.doQuote(userid)) 
    249         try : 
    250             result = self.doParseResult(result)[0] 
    251         except TypeError :      # Not found     
    252             return 
    253         else :     
    254             return (result["balance"], result["lifetimepaid"]) 
    255          
    256     def getGroupBalance(self, groupid) :     
    257         """Returns the current account balance for a given group, as the sum of each of its users' account balance.""" 
    258         result = self.doQuery("SELECT SUM(balance) AS balance, SUM(lifetimepaid) AS lifetimepaid FROM users WHERE id in (SELECT userid FROM groupsmembers WHERE groupid=%s)" % self.doQuote(groupid)) 
    259         try : 
    260             result = self.doParseResult(result)[0] 
    261         except TypeError :      # Not found     
    262             return 
    263         else :     
    264             return (result["balance"], result["lifetimepaid"]) 
    265          
    266     def getUserLimitBy(self, userid) :     
    267         """Returns the way in which user printing is limited.""" 
    268         result = self.doQuery("SELECT limitby FROM users WHERE id=%s" % self.doQuote(userid)) 
    269         try : 
    270             return self.doParseResult(result)[0]["limitby"] 
    271         except TypeError :      # Not found     
    272             return 
    273          
    274     def getGroupLimitBy(self, groupid) :     
    275         """Returns the way in which group printing is limited.""" 
    276         result = self.doQuery("SELECT limitby FROM groups WHERE id=%s" % self.doQuote(groupid)) 
    277         try : 
    278             return self.doParseResult(result)[0]["limitby"] 
    279         except TypeError :      # Not found     
    280             return 
    281          
    282     def setUserBalance(self, userid, balance) :     
    283         """Sets the account balance for a given user to a fixed value.""" 
    284         (current, lifetimepaid) = self.getUserBalance(userid) 
    285         difference = balance - current 
    286         self.increaseUserBalance(userid, difference) 
    287          
    288     def limitUserBy(self, userid, limitby) :     
    289         """Limits a given user based either on print quota or on account balance.""" 
    290         self.doQuery("UPDATE users SET limitby=%s WHERE id=%s" % (self.doQuote(limitby), self.doQuote(userid))) 
    291          
    292     def limitGroupBy(self, groupid, limitby) :     
    293         """Limits a given group based either on print quota or on sum of its users' account balances.""" 
    294         self.doQuery("UPDATE groups SET limitby=%s WHERE id=%s" % (self.doQuote(limitby), self.doQuote(groupid))) 
    295          
    296     def setUserPQuota(self, userid, printerid, softlimit, hardlimit) : 
    297         """Sets soft and hard limits for a user quota on a specific printer given (userid, printerid).""" 
    298         self.doQuery("UPDATE userpquota SET softlimit=%s, hardlimit=%s, datelimit=NULL WHERE userid=%s AND printerid=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(userid), self.doQuote(printerid))) 
    299          
    300     def setGroupPQuota(self, groupid, printerid, softlimit, hardlimit) : 
    301         """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid).""" 
    302         self.doQuery("UPDATE grouppquota SET softlimit=%s, hardlimit=%s, datelimit=NULL WHERE groupid=%s AND printerid=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(groupid), self.doQuote(printerid))) 
    303          
    304     def resetUserPQuota(self, userid, printerid) :     
    305         """Resets the page counter to zero for a user on a printer. Life time page counter is kept unchanged.""" 
    306         self.doQuery("UPDATE userpquota SET pagecounter=0, datelimit=NULL WHERE userid=%s AND printerid=%s" % (self.doQuote(userid), self.doQuote(printerid))) 
    307          
    308     def resetGroupPQuota(self, groupid, printerid) :     
    309         """Resets the page counter to zero for a group on a printer. Life time page counter is kept unchanged.""" 
    310         self.doQuery("UPDATE grouppquota SET pagecounter=0, datelimit=NULL WHERE groupid=%s AND printerid=%s" % (self.doQuote(groupid), self.doQuote(printerid))) 
    311          
    312     def updateUserPQuota(self, userid, printerid, pagecount) : 
    313         """Updates the used user Quota information given (userid, printerid) and a job size in pages.""" 
    314         jobprice = self.computePrinterJobPrice(printerid, pagecount) 
    315         queries = []     
    316         queries.append("UPDATE userpquota SET lifepagecounter=lifepagecounter+(%s), pagecounter=pagecounter+(%s) WHERE userid=%s AND printerid=%s" % (self.doQuote(pagecount), self.doQuote(pagecount), self.doQuote(userid), self.doQuote(printerid))) 
    317         queries.append("UPDATE users SET balance=balance-(%s) WHERE id=%s" % (self.doQuote(jobprice), self.doQuote(userid))) 
    318         self.doQuery(queries) 
    319          
    320     def getUserPQuota(self, userid, printerid) : 
    321         """Returns the Print Quota information for a given (userid, printerid).""" 
    322         result = self.doQuery("SELECT lifepagecounter, pagecounter, softlimit, hardlimit, datelimit FROM userpquota WHERE userid=%s AND printerid=%s" % (self.doQuote(userid), self.doQuote(printerid))) 
    323         try : 
    324             return self.doParseResult(result)[0] 
    325         except TypeError :      # Not found     
    326             return 
    327          
    328     def getGroupPQuota(self, groupid, printerid) : 
    329         """Returns the Print Quota information for a given (groupid, printerid).""" 
    330         result = self.doQuery("SELECT softlimit, hardlimit, datelimit FROM grouppquota WHERE groupid=%s AND printerid=%s" % (self.doQuote(groupid), self.doQuote(printerid))) 
    331         try : 
    332             grouppquota = self.doParseResult(result)[0] 
    333         except TypeError :     
    334             return 
    335         else :     
    336             result = self.doQuery("SELECT SUM(lifepagecounter) as lifepagecounter, SUM(pagecounter) as pagecounter FROM userpquota WHERE printerid=%s AND userid in (SELECT userid FROM groupsmembers WHERE groupid=%s)" % (self.doQuote(printerid), self.doQuote(groupid))) 
    337             try : 
    338                 result = self.doParseResult(result)[0] 
    339             except TypeError :      # Not found     
    340                 return 
    341             else :     
    342                 grouppquota.update({"lifepagecounter": result["lifepagecounter"], "pagecounter": result["pagecounter"]}) 
    343                 return grouppquota 
    344          
    345     def setUserDateLimit(self, userid, printerid, datelimit) : 
    346         """Sets the limit date for a soft limit to become an hard one given (userid, printerid).""" 
    347         self.doQuery("UPDATE userpquota SET datelimit=%s::TIMESTAMP WHERE userid=%s AND printerid=%s" % (self.doQuote("%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)), self.doQuote(userid), self.doQuote(printerid))) 
    348          
    349     def setGroupDateLimit(self, groupid, printerid, datelimit) : 
    350         """Sets the limit date for a soft limit to become an hard one given (groupid, printerid).""" 
    351         self.doQuery("UPDATE grouppquota SET datelimit=%s::TIMESTAMP WHERE groupid=%s AND printerid=%s" % (self.doQuote("%04i-%02i-%02i %02i:%02i:%02i" % (datelimit.year, datelimit.month, datelimit.day, datelimit.hour, datelimit.minute, datelimit.second)), self.doQuote(groupid), self.doQuote(printerid))) 
    352          
    353     def addJobToHistory(self, jobid, userid, printerid, pagecounter, action, jobsize=None) : 
    354         """Adds a job to the history: (jobid, userid, printerid, last page counter taken from requester).""" 
    355         self.doQuery("INSERT INTO jobhistory (jobid, userid, printerid, pagecounter, action, jobsize) VALUES (%s, %s, %s, %s, %s, %s)" % (self.doQuote(jobid), self.doQuote(userid), self.doQuote(printerid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize))) 
    356         return self.getJobHistoryId(jobid, userid, printerid) # in case jobid is not sufficient 
    357      
    358     def updateJobSizeInHistory(self, historyid, jobsize) : 
    359         """Updates a job size in the history given the history line's id.""" 
    360         self.doQuery("UPDATE jobhistory SET jobsize=%s WHERE id=%s" % (self.doQuote(jobsize), self.doQuote(historyid))) 
    361      
    362     def getPrinterPageCounter(self, printerid) : 
    363         """Returns the last page counter value for a printer given its id, also returns last username, last jobid and history line id.""" 
    364         result = self.doQuery("SELECT jobhistory.id, jobid, userid, username, pagecounter, jobsize FROM jobhistory, users WHERE printerid=%s AND userid=users.id ORDER BY jobdate DESC LIMIT 1" % self.doQuote(printerid)) 
    365         try : 
    366             return self.doParseResult(result)[0] 
    367         except TypeError :      # Not found 
    368             return 
    369          
    370     def addUserToGroup(self, userid, groupid) :     
     317        self.doModify("INSERT INTO groups (groupname, limitby) VALUES (%s, %s)" % (self.doQuote(group.Name), self.doQuote(group.LimitBy))) 
     318        return self.getGroup(group.Name) 
     319 
     320    def addUserToGroup(self, user, group) :     
    371321        """Adds an user to a group.""" 
    372         result = self.doQuery("SELECT COUNT(*) AS mexists FROM groupsmembers WHERE groupid=%s AND userid=%s" % (self.doQuote(groupid), self.doQuote(userid))) 
     322        result = self.doModify("SELECT COUNT(*) AS mexists FROM groupsmembers WHERE groupid=%s AND userid=%s" % (self.doQuote(group.ident), self.doQuote(user.ident))) 
    373323        try : 
    374324            mexists = self.doParseResult(result)[0]["mexists"] 
     
    376326            mexists = 0 
    377327        if not mexists :     
    378             self.doQuery("INSERT INTO groupsmembers (groupid, userid) VALUES (%s, %s)" % (self.doQuote(groupid), self.doQuote(userid))) 
    379          
    380     def deleteUser(self, userid) :     
     328            self.doModify("INSERT INTO groupsmembers (groupid, userid) VALUES (%s, %s)" % (self.doQuote(group.ident), self.doQuote(user.ident))) 
     329             
     330    def addUserPQuota(self, user, printer) : 
     331        """Initializes a user print quota on a printer.""" 
     332        self.doModify("INSERT INTO userpquota (userid, printerid) VALUES (%s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident))) 
     333        return self.getUserPQuota(user, printer) 
     334         
     335    def addGroupPQuota(self, group, printer) : 
     336        """Initializes a group print quota on a printer.""" 
     337        self.doModify("INSERT INTO grouppquota (groupid, printerid) VALUES (%s, %s)" % (self.doQuote(group.ident), self.doQuote(printer.ident))) 
     338        return self.getGroupPQuota(group, printer) 
     339         
     340    def writePrinterPrices(self, printer) :     
     341        """Write the printer's prices back into the storage.""" 
     342        self.doModify("UPDATE printers SET priceperpage=%s, priceperjob=%s WHERE printerid=%s" % (self.doQuote(printer.PricePerPage), self.doQuote(printer.PricePerJob), self.doQuote(printer.ident))) 
     343         
     344    def writeUserLimitBy(self, user, limitby) :     
     345        """Sets the user's limiting factor.""" 
     346        self.doModify("UPDATE users SET limitby=%s WHERE id=%s" % (self.doQuote(limitby), self.doQuote(user.ident))) 
     347         
     348    def writeGroupLimitBy(self, group, limitby) :     
     349        """Sets the group's limiting factor.""" 
     350        self.doModify("UPDATE groups SET limitby=%s WHERE id=%s" % (self.doQuote(limitby), self.doQuote(group.ident))) 
     351         
     352    def writeUserPQuotaDateLimit(self, userpquota, datelimit) :     
     353        """Sets the date limit permanently for a user print quota.""" 
     354        self.doModify("UPDATE userpquota SET datelimit::TIMESTAMP=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(userpquota.ident))) 
     355             
     356    def writeGroupPQuotaDateLimit(self, grouppquota, datelimit) :     
     357        """Sets the date limit permanently for a group print quota.""" 
     358        self.doModify("UPDATE grouppquota SET datelimit::TIMESTAMP=%s WHERE id=%s" % (self.doQuote(datelimit), self.doQuote(grouppquota.ident))) 
     359         
     360    def writeUserPQuotaPagesCounters(self, userpquota, newpagecounter, newlifepagecounter) :     
     361       """Sets the new page counters permanently for a user print quota.""" 
     362       self.doModify("UPDATE userpquota SET pagecounter=%s,lifepagecounter=%s WHERE id=%s" % (self.doQuote(newpagecounter), self.doQuote(newlifepagecounter), self.doQuote(userpquota.ident))) 
     363        
     364    def writeUserAccountBalance(self, user, newbalance, newlifetimepaid=None) :     
     365       """Sets the new account balance and eventually new lifetime paid.""" 
     366       if newlifetimepaid is not None : 
     367           self.doModify("UPDATE users SET balance=%s, lifetimepaid=%s WHERE id=%s" % (self.doQuote(newbalance), self.doQuote(newlifetimepaid), self.doQuote(user.ident))) 
     368       else :     
     369           self.doModify("UPDATE users SET balance=%s WHERE id=%s" % (self.doQuote(newbalance), self.doQuote(user.ident))) 
     370             
     371    def writeLastJobSize(self, lastjob, jobsize) :         
     372        """Sets the last job's size permanently.""" 
     373        self.doModify("UPDATE jobhistory SET jobsize=%s WHERE id=%s" % (self.doQuote(jobsize), self.doQuote(lastjob.ident))) 
     374         
     375    def writeJobNew(self, printer, user, jobid, pagecounter, action, jobsize=None) :     
     376        """Adds a job in a printer's history.""" 
     377        if jobsize is not None : 
     378            self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action, jobsize) VALUES (%s, %s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action), self.doQuote(jobsize))) 
     379        else :     
     380            self.doModify("INSERT INTO jobhistory (userid, printerid, jobid, pagecounter, action) VALUES (%s, %s, %s, %s, %s)" % (self.doQuote(user.ident), self.doQuote(printer.ident), self.doQuote(jobid), self.doQuote(pagecounter), self.doQuote(action))) 
     381             
     382    def writeUserPQuotaLimits(self, userpquota, softlimit, hardlimit) : 
     383        """Sets soft and hard limits for a user quota.""" 
     384        self.doModify("UPDATE userpquota SET softlimit=%s, hardlimit=%s, datelimit=NULL WHERE id=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(userpquota.ident))) 
     385         
     386    def writeGroupPQuotaLimits(self, grouppquota, softlimit, hardlimit) : 
     387        """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid).""" 
     388        self.doModify("UPDATE grouppquota SET softlimit=%s, hardlimit=%s, datelimit=NULL WHERE id=%s" % (self.doQuote(softlimit), self.doQuote(hardlimit), self.doQuote(grouppquota.ident))) 
     389 
     390    def deleteUser(self, user) :     
    381391        """Completely deletes an user from the Quota Storage.""" 
    382         queries = [] 
    383         queries.append("DELETE FROM groupsmembers WHERE userid=%s" % self.doQuote(userid)) 
    384         queries.append("DELETE FROM jobhistory WHERE userid=%s" % self.doQuote(userid)) 
    385         queries.append("DELETE FROM userpquota WHERE userid=%s" % self.doQuote(userid)) 
    386         queries.append("DELETE FROM users WHERE id=%s" % self.doQuote(userid)) 
    387392        # TODO : What should we do if we delete the last person who used a given printer ? 
    388         self.doQuery(queries) 
    389          
    390     def deleteGroup(self, groupid) :     
    391         """Completely deletes an user from the Quota Storage.""" 
    392         queries = [] 
    393         queries.append("DELETE FROM groupsmembers WHERE groupid=%s" % self.doQuote(groupid)) 
    394         queries.append("DELETE FROM grouppquota WHERE groupid=%s" % self.doQuote(groupid)) 
    395         queries.append("DELETE FROM groups WHERE id=%s" % self.doQuote(groupid)) 
    396         self.doQuery(queries) 
    397          
    398     def computePrinterJobPrice(self, printerid, jobsize) :     
    399         """Returns the price for a job on a given printer.""" 
    400         # TODO : create a base class with things like this 
    401         prices = self.getPrinterPrices(printerid) 
    402         if prices is None : 
    403             perpage = perjob = 0.0 
    404         else :     
    405             (perpage, perjob) = prices 
    406         return perjob + (perpage * jobsize) 
    407          
     393        # TODO : we can't reassign the last job to the previous one, because next user would be 
     394        # TODO : incorrectly charged (overcharged). 
     395        for q in [  
     396                    "DELETE FROM groupsmembers WHERE userid=%s" % self.doQuote(user.ident), 
     397                    "DELETE FROM jobhistory WHERE userid=%s" % self.doQuote(user.ident), 
     398                    "DELETE FROM userpquota WHERE userid=%s" % self.doQuote(user.ident), 
     399                    "DELETE FROM users WHERE id=%s" % self.doQuote(user.ident), 
     400                  ] : 
     401            self.doModify(q) 
     402         
     403    def deleteGroup(self, group) :     
     404        """Completely deletes a group from the Quota Storage.""" 
     405        for q in [ 
     406                   "DELETE FROM groupsmembers WHERE groupid=%s" % self.doQuote(group.ident), 
     407                   "DELETE FROM grouppquota WHERE groupid=%s" % self.doQuote(group.ident), 
     408                   "DELETE FROM groups WHERE id=%s" % self.doQuote(group.ident), 
     409                 ] :   
     410            self.doModify(q) 
     411         
  • pykota/trunk/pykota/tool.py

    r1021 r1041  
    2121# 
    2222# $Log$ 
     23# Revision 1.41  2003/06/25 14:10:01  jalet 
     24# Hey, it may work (edpykota --reset excepted) ! 
     25# 
    2326# Revision 1.40  2003/06/10 16:37:54  jalet 
    2427# Deletion of the second user which is not needed anymore. 
     
    305308            touser = "%s@%s" % (touser, self.smtpserver) 
    306309        server = smtplib.SMTP(self.smtpserver) 
    307         server.sendmail(adminmail, [touser], fullmessage) 
     310        try : 
     311            server.sendmail(adminmail, [touser], fullmessage) 
     312        except smtplib.SMTPRecipientsRefused, answer :     
     313            for (k, v) in answer.recipients.items() : 
     314                self.logger.log_message(_("Impossible to send mail to %s, error %s : %s") % (k, v[0], v[1]), "error") 
    308315        server.quit() 
    309316         
     
    317324        self.sendMessage(adminmail, adminmail, "Subject: %s\n\n%s" % (subject, message)) 
    318325         
    319     def checkGroupPQuota(self, groupname, printername) :     
     326    def checkGroupPQuota(self, grouppquota) :     
    320327        """Checks the group quota on a printer and deny or accept the job.""" 
    321         printerid = self.storage.getPrinterId(printername) 
    322         policy = self.config.getPrinterPolicy(printername) 
    323         groupid = self.storage.getGroupId(groupname) 
    324         limitby = self.storage.getGroupLimitBy(groupid) 
    325         if limitby == "balance" :  
    326             balance = self.storage.getGroupBalance(groupid) 
    327             if balance is None : 
     328        group = grouppquota.Group 
     329        printer = grouppquota.Printer 
     330        if group.LimitBy.lower() == "balance" :  
     331            # TODO : there's no warning (no account balance soft limit) 
     332            if float(group.AccountBalance) <= 0.0 : 
     333                action = "DENY" 
     334            else :     
     335                action = "ALLOW" 
     336        else : 
     337            if grouppquota.SoftLimit is not None : 
     338                softlimit = int(grouppquota.SoftLimit) 
     339                if grouppquota.PageCounter < softlimit : 
     340                    action = "ALLOW" 
     341                else :     
     342                    if grouppquota.HardLimit is None : 
     343                        # only a soft limit, this is equivalent to having only a hard limit 
     344                        action = "DENY" 
     345                    else :     
     346                        hardlimit = int(grouppquota.HardLimit) 
     347                        if softlimit <= grouppquota.PageCounter < hardlimit :     
     348                            now = DateTime.now() 
     349                            if grouppquota.DateLimit is not None : 
     350                                datelimit = DateTime.ISO.ParseDateTime(grouppquota.DateLimit) 
     351                            else : 
     352                                datelimit = now + self.config.getGraceDelay(printer.Name) 
     353                                grouppquota.setDateLimit(datelimit) 
     354                            if now < datelimit : 
     355                                action = "WARN" 
     356                            else :     
     357                                action = "DENY" 
     358                        else :          
     359                            action = "DENY" 
     360            else :         
     361                if grouppquota.HardLimit is not None : 
     362                    # no soft limit, only a hard one. 
     363                    hardlimit = int(grouppquota.HardLimit) 
     364                    if grouppquota.PageCounter < hardlimit : 
     365                        action = "ALLOW" 
     366                    else :       
     367                        action = "DENY" 
     368                else : 
     369                    # Both are unset, no quota, i.e. accounting only 
     370                    action = "ALLOW" 
     371        return action 
     372     
     373    def checkUserPQuota(self, userpquota) : 
     374        """Checks the user quota on a printer and deny or accept the job.""" 
     375        user = userpquota.User 
     376        printer = userpquota.Printer 
     377         
     378        # first we check any group the user is a member of 
     379        for group in self.storage.getUserGroups(user) : 
     380            grouppquota = self.storage.getGroupPQuota(group, printer) 
     381            if grouppquota.Exists : 
     382                action = self.checkGroupPQuota(grouppquota) 
     383                if action == "DENY" : 
     384                    return action 
     385                 
     386        # then we check the user's own quota 
     387        policy = self.config.getPrinterPolicy(printer.Name) 
     388        if user.LimitBy.lower() == "balance" :  
     389            if user.AccountBalance is None : 
    328390                if policy == "ALLOW" : 
    329391                    action = "POLICY_ALLOW" 
    330392                else :     
    331393                    action = "POLICY_DENY" 
    332                 self.logger.log_message(_("Unable to find group %s's account balance, applying default policy (%s) for printer %s") % (groupname, action, printername)) 
     394                self.logger.log_message(_("Unable to find user %s's account balance, applying default policy (%s) for printer %s") % (user.Name, action, printer.Name)) 
    333395            else :     
    334396                # TODO : there's no warning (no account balance soft limit) 
    335                 (balance, lifetimepaid) = balance 
    336                 if balance <= 0.0 : 
     397                if float(user.AccountBalance or 0.0) <= 0.0 : 
    337398                    action = "DENY" 
    338399                else :     
    339400                    action = "ALLOW" 
    340401        else : 
    341             quota = self.storage.getGroupPQuota(groupid, printerid) 
    342             if quota is None : 
    343                 # Unknown group or printer or combination 
     402            if not userpquota.Exists : 
     403                # Unknown userquota  
    344404                if policy == "ALLOW" : 
    345405                    action = "POLICY_ALLOW" 
    346406                else :     
    347407                    action = "POLICY_DENY" 
    348                 self.logger.log_message(_("Unable to match group %s on printer %s, applying default policy (%s)") % (groupname, printername, action)) 
     408                self.logger.log_message(_("Unable to match user %s on printer %s, applying default policy (%s)") % (user.Name, printer.Name, action)) 
    349409            else :     
    350                 pagecounter = quota["pagecounter"] 
    351                 softlimit = quota["softlimit"] 
    352                 hardlimit = quota["hardlimit"] 
    353                 datelimit = quota["datelimit"] 
    354                 if softlimit is not None : 
     410                pagecounter = int(userpquota.PageCounter or 0) 
     411                if userpquota.SoftLimit is not None : 
     412                    softlimit = int(userpquota.SoftLimit) 
    355413                    if pagecounter < softlimit : 
    356414                        action = "ALLOW" 
    357415                    else :     
    358                         if hardlimit is None : 
     416                        if userpquota.HardLimit is None : 
    359417                            # only a soft limit, this is equivalent to having only a hard limit 
    360418                            action = "DENY" 
    361419                        else :     
     420                            hardlimit = int(userpquota.HardLimit) 
    362421                            if softlimit <= pagecounter < hardlimit :     
    363422                                now = DateTime.now() 
    364                                 if datelimit is not None : 
    365                                     datelimit = DateTime.ISO.ParseDateTime(datelimit) 
     423                                if userpquota.DateLimit is not None : 
     424                                    datelimit = DateTime.ISO.ParseDateTime(userpquota.DateLimit) 
    366425                                else : 
    367                                     datelimit = now + self.config.getGraceDelay(printername) 
    368                                     self.storage.setGroupDateLimit(groupid, printerid, datelimit) 
     426                                    datelimit = now + self.config.getGraceDelay(printer.Name) 
     427                                    userpquota.setDateLimit(datelimit) 
    369428                                if now < datelimit : 
    370429                                    action = "WARN" 
     
    374433                                action = "DENY" 
    375434                else :         
    376                     if hardlimit is not None : 
     435                    if userpquota.HardLimit is not None : 
    377436                        # no soft limit, only a hard one. 
     437                        hardlimit = int(userpquota.HardLimit) 
    378438                        if pagecounter < hardlimit : 
    379439                            action = "ALLOW" 
     
    385445        return action 
    386446     
    387     def checkUserPQuota(self, username, printername) : 
    388         """Checks the user quota on a printer and deny or accept the job.""" 
    389         # first we check any group the user is a member of 
    390         userid = self.storage.getUserId(username) 
    391         for groupname in self.storage.getUserGroupsNames(userid) : 
    392             action = self.checkGroupPQuota(groupname, printername) 
    393             if action in ("DENY", "POLICY_DENY") : 
    394                 return action 
    395                  
    396         # then we check the user's own quota 
    397         printerid = self.storage.getPrinterId(printername) 
    398         policy = self.config.getPrinterPolicy(printername) 
    399         limitby = self.storage.getUserLimitBy(userid) 
    400         if limitby == "balance" :  
    401             balance = self.storage.getUserBalance(userid) 
    402             if balance is None : 
    403                 if policy == "ALLOW" : 
    404                     action = "POLICY_ALLOW" 
    405                 else :     
    406                     action = "POLICY_DENY" 
    407                 self.logger.log_message(_("Unable to find user %s's account balance, applying default policy (%s) for printer %s") % (username, action, printername)) 
    408             else :     
    409                 # TODO : there's no warning (no account balance soft limit) 
    410                 (balance, lifetimepaid) = balance 
    411                 if balance <= 0.0 : 
    412                     action = "DENY" 
    413                 else :     
    414                     action = "ALLOW" 
    415         else : 
    416             quota = self.storage.getUserPQuota(userid, printerid) 
    417             if quota is None : 
    418                 # Unknown user or printer or combination 
    419                 if policy == "ALLOW" : 
    420                     action = "POLICY_ALLOW" 
    421                 else :     
    422                     action = "POLICY_DENY" 
    423                 self.logger.log_message(_("Unable to match user %s on printer %s, applying default policy (%s)") % (username, printername, action)) 
    424             else :     
    425                 pagecounter = quota["pagecounter"] 
    426                 softlimit = quota["softlimit"] 
    427                 hardlimit = quota["hardlimit"] 
    428                 datelimit = quota["datelimit"] 
    429                 if softlimit is not None : 
    430                     if pagecounter < softlimit : 
    431                         action = "ALLOW" 
    432                     else :     
    433                         if hardlimit is None : 
    434                             # only a soft limit, this is equivalent to having only a hard limit 
    435                             action = "DENY" 
    436                         else :     
    437                             if softlimit <= pagecounter < hardlimit :     
    438                                 now = DateTime.now() 
    439                                 if datelimit is not None : 
    440                                     datelimit = DateTime.ISO.ParseDateTime(datelimit) 
    441                                 else : 
    442                                     datelimit = now + self.config.getGraceDelay(printername) 
    443                                     self.storage.setUserDateLimit(userid, printerid, datelimit) 
    444                                 if now < datelimit : 
    445                                     action = "WARN" 
    446                                 else :     
    447                                     action = "DENY" 
    448                             else :          
    449                                 action = "DENY" 
    450                 else :         
    451                     if hardlimit is not None : 
    452                         # no soft limit, only a hard one. 
    453                         if pagecounter < hardlimit : 
    454                             action = "ALLOW" 
    455                         else :       
    456                             action = "DENY" 
    457                     else : 
    458                         # Both are unset, no quota, i.e. accounting only 
    459                         action = "ALLOW" 
    460         return action 
    461      
    462     def warnGroupPQuota(self, groupname, printername) : 
     447    def warnGroupPQuota(self, grouppquota) : 
    463448        """Checks a group quota and send messages if quota is exceeded on current printer.""" 
    464         admin = self.config.getAdmin(printername) 
    465         adminmail = self.config.getAdminMail(printername) 
    466         mailto = self.config.getMailTo(printername) 
    467         action = self.checkGroupPQuota(groupname, printername) 
    468         groupmembers = self.storage.getGroupMembersNames(groupname) 
     449        group = grouppquota.Group 
     450        printer = grouppquota.Printer 
     451        admin = self.config.getAdmin(printer.Name) 
     452        adminmail = self.config.getAdminMail(printer.Name) 
     453        mailto = self.config.getMailTo(printer.Name) 
     454        action = self.checkGroupPQuota(grouppquota, printer) 
    469455        if action.startswith("POLICY_") : 
    470456            action = action[7:] 
    471457        if action == "DENY" : 
    472             adminmessage = _("Print Quota exceeded for group %s on printer %s") % (groupname, printername) 
     458            adminmessage = _("Print Quota exceeded for group %s on printer %s") % (group.Name, printer.Name) 
    473459            self.logger.log_message(adminmessage) 
    474460            if mailto in [ "BOTH", "ADMIN" ] : 
    475461                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 
    476             for username in groupmembers : 
     462            for user in self.storage.getGroupMembers(group) : 
    477463                if mailto in [ "BOTH", "USER" ] : 
    478                     self.sendMessageToUser(admin, adminmail, username, _("Print Quota Exceeded"), _("You are not allowed to print anymore because\nyour group Print Quota is exceeded on printer %s.") % printername) 
     464                    self.sendMessageToUser(admin, adminmail, user.Name, _("Print Quota Exceeded"), _("You are not allowed to print anymore because\nyour group Print Quota is exceeded on printer %s.") % printer.Name) 
    479465        elif action == "WARN" :     
    480             adminmessage = _("Print Quota soft limit exceeded for group %s on printer %s") % (groupname, printername) 
     466            adminmessage = _("Print Quota soft limit exceeded for group %s on printer %s") % (group.Name, printer.Name) 
    481467            self.logger.log_message(adminmessage) 
    482468            if mailto in [ "BOTH", "ADMIN" ] : 
    483469                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 
    484             for username in groupmembers : 
     470            for user in self.storage.getGroupMembers(group) : 
    485471                if mailto in [ "BOTH", "USER" ] : 
    486                     self.sendMessageToUser(admin, adminmail, username, _("Print Quota Exceeded"), _("You will soon be forbidden to print anymore because\nyour group Print Quota is almost reached on printer %s.") % printername) 
     472                    self.sendMessageToUser(admin, adminmail, user.Name, _("Print Quota Exceeded"), _("You will soon be forbidden to print anymore because\nyour group Print Quota is almost reached on printer %s.") % printer.Name) 
    487473        return action         
    488474         
    489     def warnUserPQuota(self, username, printername) : 
     475    def warnUserPQuota(self, userpquota) : 
    490476        """Checks a user quota and send him a message if quota is exceeded on current printer.""" 
    491         admin = self.config.getAdmin(printername) 
    492         adminmail = self.config.getAdminMail(printername) 
    493         mailto = self.config.getMailTo(printername) 
    494         action = self.checkUserPQuota(username, printername) 
     477        user = userpquota.User 
     478        printer = userpquota.Printer 
     479        admin = self.config.getAdmin(printer.Name) 
     480        adminmail = self.config.getAdminMail(printer.Name) 
     481        mailto = self.config.getMailTo(printer.Name) 
     482        action = self.checkUserPQuota(userpquota) 
    495483        if action.startswith("POLICY_") : 
    496484            action = action[7:] 
    497485        if action == "DENY" : 
    498             adminmessage = _("Print Quota exceeded for user %s on printer %s") % (username, printername) 
     486            adminmessage = _("Print Quota exceeded for user %s on printer %s") % (user.Name, printer.Name) 
    499487            self.logger.log_message(adminmessage) 
    500488            if mailto in [ "BOTH", "USER" ] : 
    501                 self.sendMessageToUser(admin, adminmail, username, _("Print Quota Exceeded"), _("You are not allowed to print anymore because\nyour Print Quota is exceeded on printer %s.") % printername) 
     489                self.sendMessageToUser(admin, adminmail, user.Name, _("Print Quota Exceeded"), _("You are not allowed to print anymore because\nyour Print Quota is exceeded on printer %s.") % printer.Name) 
    502490            if mailto in [ "BOTH", "ADMIN" ] : 
    503491                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage) 
    504492        elif action == "WARN" :     
    505             adminmessage = _("Print Quota soft limit exceeded for user %s on printer %s") % (username, printername) 
     493            adminmessage = _("Print Quota soft limit exceeded for user %s on printer %s") % (user.Name, printer.Name) 
    506494            self.logger.log_message(adminmessage) 
    507495            if mailto in [ "BOTH", "USER" ] : 
    508                 self.sendMessageToUser(admin, adminmail, username, _("Print Quota Exceeded"), _("You will soon be forbidden to print anymore because\nyour Print Quota is almost reached on printer %s.") % printername) 
     496                self.sendMessageToUser(admin, adminmail, user.Name, _("Print Quota Exceeded"), _("You will soon be forbidden to print anymore because\nyour Print Quota is almost reached on printer %s.") % printer.Name) 
    509497            if mailto in [ "BOTH", "ADMIN" ] : 
    510498                self.sendMessageToAdmin(adminmail, _("Print Quota"), adminmessage)