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

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

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • 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