root / pykota / trunk / pykota / storages / ldapstorage.py @ 1018

Revision 1018, 16.7 kB (checked in by jalet, 21 years ago)

Very latest schema. UNTESTED.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1# PyKota
2#
3# PyKota : Print Quotas for CUPS and LPRng
4#
5# (c) 2003 Jerome Alet <alet@librelogiciel.com>
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19#
20# $Id$
21#
22# $Log$
23# Revision 1.3  2003/06/06 20:49:15  jalet
24# Very latest schema. UNTESTED.
25#
26# Revision 1.2  2003/06/06 14:21:08  jalet
27# New LDAP schema.
28# Small bug fixes.
29#
30# Revision 1.1  2003/06/05 11:19:13  jalet
31# More good work on LDAP storage.
32#
33#
34#
35
36#
37# My IANA assigned number, for
38# "Conseil Internet & Logiciels Libres, J�me Alet"
39# is 16868. Use this as a base to create the LDAP schema.
40#
41
42import fnmatch
43
44from pykota.storage import PyKotaStorageError
45
46try :
47    import ldap
48except ImportError :   
49    import sys
50    # TODO : to translate or not to translate ?
51    raise PyKotaStorageError, "This python version (%s) doesn't seem to have the python-ldap module installed correctly." % sys.version.split()[0]
52   
53class Storage :
54    def __init__(self, host, dbname, user, passwd) :
55        """Opens the LDAP connection."""
56        # raise PyKotaStorageError, "Sorry, the LDAP backend for PyKota is not yet implemented !"
57        self.closed = 1
58        try :
59            self.database = ldap.initialize(host) 
60            self.database.simple_bind_s(user, passwd)
61            self.basedn = dbname
62        except ldap.SERVER_DOWN :   
63            raise PyKotaStorageError, "LDAP backend for PyKota seems to be down !" # TODO : translate
64        else :   
65            self.closed = 0
66           
67    def __del__(self) :       
68        """Closes the database connection."""
69        if not self.closed :
70            del self.database
71            self.closed = 1
72       
73    def doSearch(self, key, fields, base="", scope=ldap.SCOPE_SUBTREE) :
74        """Does an LDAP search query."""
75        try :
76            # prepends something more restrictive at the beginning of the base dn
77            result = self.database.search_s(base or self.basedn, scope, key, fields)
78        except ldap.NO_SUCH_OBJECT :   
79            return
80        else :     
81            return result
82       
83    def getMatchingPrinters(self, printerpattern) :
84        """Returns the list of all printers as tuples (id, name) for printer names which match a certain pattern."""
85        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName"])
86        if result :
87            return [(printerid, printer["pykotaPrinterName"][0]) for (printerid, printer) in result if fnmatch.fnmatchcase(printer["pykotaPrinterName"][0], printerpattern)]
88           
89    def getPrinterId(self, printername) :       
90        """Returns a printerid given a printername."""
91        result = self.doSearch("(&(objectClass=pykotaPrinter)(|(pykotaPrinterName=%s)(cn=%s)))" % (printername, printername), ["pykotaPrinterName"])
92        if result :
93            return result[0][0]
94           
95    def getPrinterPrices(self, printerid) :       
96        """Returns a printer prices per page and per job given a printerid."""
97        result = self.doSearch("(|(pykotaPrinterName=*)(cn=*))", ["pykotaPricePerPage", "pykotaPricePerJob"], base=printerid, scope=ldap.SCOPE_BASE)
98        if result :
99            return (float(result[0][1]["pykotaPricePerPage"][0]), float(result[0][1]["pykotaPricePerJob"][0]))
100           
101    def setPrinterPrices(self, printerid, perpage, perjob) :
102        """Sets prices per job and per page for a given printer."""
103        pass
104   
105    def getUserId(self, username) :
106        """Returns a userid given a username."""
107        result = self.doSearch("(&(objectClass=pykotaAccount)(|(pykotaUserName=%s)(uid=%s)))" % (username, username), ["uid"])
108        if result :
109            return result[0][0]
110           
111    def getGroupId(self, groupname) :
112        """Returns a groupid given a grupname."""
113        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(cn=%s)))" % (groupname, groupname), ["cn"])
114        if result is not None :
115            (groupid, dummy) = result[0]
116            return groupid
117           
118    def getJobHistoryId(self, jobid, userid, printerid) :       
119        """Returns the history line's id given a (jobid, userid, printerid)."""
120        pass
121           
122    def getPrinterUsers(self, printerid) :       
123        """Returns the list of userids and usernames which uses a given printer."""
124        # first get the printer's name from the id
125        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", "cn"], base=printerid, scope=ldap.SCOPE_BASE)
126        if result :
127            fields = result[0][1]
128            printername = (fields.get("pykotaPrinterName") or fields.get("cn"))[0]
129            result = self.doSearch("(&(objectClass=pykotaUserPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaUserName"]) 
130            if result :
131                return [(pquotauserid, fields["pykotaUserName"][0]) for (pquotauserid, fields) in result]
132       
133    def getPrinterGroups(self, printerid) :       
134        """Returns the list of groups which uses a given printer."""
135        # first get the printer's name from the id
136        result = self.doSearch("objectClass=pykotaPrinter", ["pykotaPrinterName", "cn"], base=printerid, scope=ldap.SCOPE_BASE)
137        if result :
138            fields = result[0][1]
139            printername = (fields.get("pykotaPrinterName") or fields.get("cn"))[0]
140            result = self.doSearch("(&(objectClass=pykotaGroupPQuota)(pykotaPrinterName=%s))" % printername, ["pykotaGroupName"]) 
141            if result :
142                return [(pquotagroupid, fields["pykotaGroupName"][0]) for (pquotagroupid, fields) in result]
143       
144    def getGroupMembersNames(self, groupname) :       
145        """Returns the list of user's names which are member of this group."""
146        result = self.doSearch("(&(objectClass=pykotaGroup)(|(pykotaGroupName=%s)(cn=%s)))" % (groupname, groupname), ["memberUid", "uniqueMember", "member"])
147        if result :
148            fields = result[0][1]
149            return fields.get("memberUid") or fields.get("uniqueMember") or fields.get("member")
150       
151    def getUserGroupsNames(self, userid) :       
152        """Returns the list of groups' names the user is a member of."""
153        pass
154       
155    def addPrinter(self, printername) :       
156        """Adds a printer to the quota storage, returns its id."""
157        pass
158       
159    def addUser(self, username) :       
160        """Adds a user to the quota storage, returns its id."""
161        pass
162       
163    def addGroup(self, groupname) :       
164        """Adds a group to the quota storage, returns its id."""
165        pass
166       
167    def addUserPQuota(self, username, printerid) :
168        """Initializes a user print quota on a printer, adds the user to the quota storage if needed."""
169        pass
170       
171    def addGroupPQuota(self, groupname, printerid) :
172        """Initializes a group print quota on a printer, adds the group to the quota storage if needed."""
173        pass
174       
175    def increaseUserBalance(self, userid, amount) :   
176        """Increases (or decreases) an user's account balance by a given amount."""
177        pass
178       
179    def getUserBalance(self, userquotaid) :   
180        """Returns the current account balance for a given user quota identifier."""
181        # first get the user's name from the user quota id
182        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName"], base=userquotaid, scope=ldap.SCOPE_BASE)
183        if result :
184            username = result[0][1]["pykotaUserName"][0]
185            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(uid=%s)))" % (username, username), ["pykotaBalance", "pykotaLifeTimePaid"])
186            if result :
187                fields = result[0][1]
188                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
189       
190    def getUserBalanceFromUserId(self, userid) :   
191        """Returns the current account balance for a given user id."""
192        # first get the user's name from the user id
193        result = self.doSearch("objectClass=pykotaAccount", ["pykotaUserName", "uid"], base=userid, scope=ldap.SCOPE_BASE)
194        if result :
195            fields = result[0][1]
196            username = (fields.get("pykotaUserName") or fields.get("uid"))[0]
197            result = self.doSearch("(&(objectClass=pykotaAccountBalance)(|(pykotaUserName=%s)(uid=%s)))" % (username, username), ["pykotaBalance", "pykotaLifeTimePaid"])
198            if result :
199                fields = result[0][1]
200                return (float(fields["pykotaBalance"][0]), float(fields["pykotaLifeTimePaid"][0]))
201       
202    def getGroupBalance(self, groupquotaid) :   
203        """Returns the current account balance for a given group, as the sum of each of its users' account balance."""
204        # first get the group's name from the group quota id
205        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
206        if result :
207            groupname = result[0][1]["pykotaGroupName"][0]
208            members = self.getGroupMembersNames(groupname)
209            balance = lifetimepaid = 0.0
210            for member in members :
211                userid = self.getUserId(member)
212                if userid :
213                    userbal = self.getUserBalanceFromUserId(userid)
214                    if userbal :
215                        (bal, paid) = userbal
216                        balance += bal
217                        lifetimepaid += paid
218            return (balance, lifetimepaid)           
219       
220    def getUserLimitBy(self, userid) :   
221        """Returns the way in which user printing is limited."""
222        result = self.doSearch("objectClass=pykotaAccount", ["pykotaLimitBy"], base=userid, scope=ldap.SCOPE_BASE)
223        if result :
224            return result[0][1]["pykotaLimitBy"][0]
225       
226    def getGroupLimitBy(self, groupquotaid) :   
227        """Returns the way in which group printing is limited."""
228        # first get the group's name from the group quota id
229        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName"], base=groupquotaid, scope=ldap.SCOPE_BASE)
230        if result :
231            groupname = result[0][1]["pykotaGroupName"][0]
232            result = self.doSearch("(&(objectClass=pykotaGroup)(pykotaGroupName=%s))" % groupname, ["pykotaLimitBy"])
233            if result :
234                return result[0][1]["pykotaLimitBy"][0]
235       
236    def setUserBalance(self, userid, balance) :   
237        """Sets the account balance for a given user to a fixed value."""
238        pass
239       
240    def limitUserBy(self, userid, limitby) :   
241        """Limits a given user based either on print quota or on account balance."""
242        pass
243       
244    def limitGroupBy(self, groupid, limitby) :   
245        """Limits a given group based either on print quota or on sum of its users' account balances."""
246        pass
247       
248    def setUserPQuota(self, userid, printerid, softlimit, hardlimit) :
249        """Sets soft and hard limits for a user quota on a specific printer given (userid, printerid)."""
250        pass
251       
252    def setGroupPQuota(self, groupid, printerid, softlimit, hardlimit) :
253        """Sets soft and hard limits for a group quota on a specific printer given (groupid, printerid)."""
254        pass
255       
256    def resetUserPQuota(self, userid, printerid) :   
257        """Resets the page counter to zero for a user on a printer. Life time page counter is kept unchanged."""
258        pass
259       
260    def resetGroupPQuota(self, groupid, printerid) :   
261        """Resets the page counter to zero for a group on a printer. Life time page counter is kept unchanged."""
262        pass
263       
264    def updateUserPQuota(self, userid, printerid, pagecount) :
265        """Updates the used user Quota information given (userid, printerid) and a job size in pages."""
266        pass
267       
268    def getUserPQuota(self, userquotaid, printerid) :
269        """Returns the Print Quota information for a given (userquotaid, printerid)."""
270        # first get the user's name from the id
271        result = self.doSearch("objectClass=pykotaUserPQuota", ["pykotaUserName", "pykotaPageCounter", "pykotaLifePageCounter", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=userquotaid, scope=ldap.SCOPE_BASE)
272        if result :
273            fields = result[0][1]
274            datelimit = fields["pykotaDateLimit"][0].strip()
275            if (not datelimit) or (datelimit.upper() == "NONE") : 
276                datelimit = None
277            return { "lifepagecounter" : int(fields["pykotaLifePageCounter"][0]), 
278                     "pagecounter" : int(fields["pykotaPageCounter"][0]),
279                     "softlimit" : int(fields["pykotaSoftLimit"][0]),
280                     "hardlimit" : int(fields["pykotaHardLimit"][0]),
281                     "datelimit" : datelimit
282                   }
283       
284    def getGroupPQuota(self, grouppquotaid, printerid) :
285        """Returns the Print Quota information for a given (grouppquotaid, printerid)."""
286        result = self.doSearch("objectClass=pykotaGroupPQuota", ["pykotaGroupName", "pykotaSoftLimit", "pykotaHardLimit", "pykotaDateLimit"], base=grouppquotaid, scope=ldap.SCOPE_BASE)
287        if result :
288            fields = result[0][1]
289            groupname = fields["pykotaGroupName"][0]
290            datelimit = fields["pykotaDateLimit"][0].strip()
291            if (not datelimit) or (datelimit.upper() == "NONE") : 
292                datelimit = None
293            quota = {
294                      "softlimit" : int(fields["pykotaSoftLimit"][0]),
295                      "hardlimit" : int(fields["pykotaHardLimit"][0]),
296                      "datelimit" : datelimit
297                    }
298            members = self.getGroupMembersNames(groupname)
299            pagecounter = lifepagecounter = 0
300            printerusers = self.getPrinterUsers(printerid)
301            if printerusers :
302                for (userid, username) in printerusers :
303                    if username in members :
304                        userpquota = self.getUserPQuota(userid, printerid)
305                        if userpquota :
306                            pagecounter += userpquota["pagecounter"]
307                            lifepagecounter += userpquota["lifepagecounter"]
308            quota.update({"pagecounter": pagecounter, "lifepagecounter": lifepagecounter})               
309            return quota
310       
311    def setUserDateLimit(self, userid, printerid, datelimit) :
312        """Sets the limit date for a soft limit to become an hard one given (userid, printerid)."""
313        pass
314       
315    def setGroupDateLimit(self, groupid, printerid, datelimit) :
316        """Sets the limit date for a soft limit to become an hard one given (groupid, printerid)."""
317        pass
318       
319    def addJobToHistory(self, jobid, userid, printerid, pagecounter, action) :
320        """Adds a job to the history: (jobid, userid, printerid, last page counter taken from requester)."""
321        pass
322   
323    def updateJobSizeInHistory(self, historyid, jobsize) :
324        """Updates a job size in the history given the history line's id."""
325        pass
326   
327    def getPrinterPageCounter(self, printerid) :
328        """Returns the last page counter value for a printer given its id, also returns last username, last jobid and history line id."""
329        return # TODO
330        result = self.doSearch("objectClass=pykotaPrinterJob", ["pykotaJobHistoryId", "pykotaJobId", "uid", "pykotaPrinterPageCounter", "pykotaJobSize", "pykotaAction", "pykotaJobDate"], base=printerid)
331        if result :
332            pass # TODO
333       
334    def addUserToGroup(self, userid, groupid) :   
335        """Adds an user to a group."""
336        pass
337       
338    def deleteUser(self, userid) :   
339        """Completely deletes an user from the Quota Storage."""
340        pass
341       
342    def deleteGroup(self, groupid) :   
343        """Completely deletes an user from the Quota Storage."""
344        pass
345       
346    def computePrinterJobPrice(self, printerid, jobsize) :   
347        """Returns the price for a job on a given printer."""
348        # TODO : create a base class with things like this
349        prices = self.getPrinterPrices(printerid)
350        if prices is None :
351            perpage = perjob = 0.0
352        else :   
353            (perpage, perjob) = prices
354        return perjob + (perpage * jobsize)
Note: See TracBrowser for help on using the browser.