Mercurial > p > roundup > code
comparison doc/customizing.txt @ 2017:31d920b31642
Update customization examples too, expand upgrade notice a bit.
| author | Johannes Gijsbers <jlgijsbers@users.sourceforge.net> |
|---|---|
| date | Sat, 14 Feb 2004 17:18:01 +0000 |
| parents | 2112962f5bb1 |
| children | be047db3dd3d |
comparison
equal
deleted
inserted
replaced
| 2016:2112962f5bb1 | 2017:31d920b31642 |
|---|---|
| 1 =================== | 1 =================== |
| 2 Customising Roundup | 2 Customising Roundup |
| 3 =================== | 3 =================== |
| 4 | 4 |
| 5 :Version: $Revision: 1.114 $ | 5 :Version: $Revision: 1.115 $ |
| 6 | 6 |
| 7 .. This document borrows from the ZopeBook section on ZPT. The original is at: | 7 .. This document borrows from the ZopeBook section on ZPT. The original is at: |
| 8 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx | 8 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx |
| 9 | 9 |
| 10 .. contents:: | 10 .. contents:: |
| 890 them to :filter. | 890 them to :filter. |
| 891 | 891 |
| 892 - Also handle the ":queryname" variable and save off the query to the | 892 - Also handle the ":queryname" variable and save off the query to the |
| 893 user's query list. | 893 user's query list. |
| 894 | 894 |
| 895 Each of the actions is implemented by a corresponding ``*actionAction*`` | 895 Each of the actions is implemented by a corresponding ``*XxxAction*`` (where |
| 896 (where "action" is the name of the action) method on the | 896 "Xxx" is the name of the action) class in the ``roundup.cgi.actions`` module. |
| 897 ``roundup.cgi.Client`` class, which also happens to be available in your | 897 These classes are registered with ``roundup.cgi.client.Client`` which also |
| 898 tracker instance as ``interfaces.Client``. So if you need to define new | 898 happens to be available in your tracker instance as ``interfaces.Client``. So |
| 899 actions, you may add them there (see `defining new web actions`_). | 899 if you need to define new actions, you may add them there (see `defining new |
| 900 | 900 web actions`_). |
| 901 Each action also has a corresponding ``*actionPermission*`` (where | 901 |
| 902 "action" is the name of the action) method which determines whether the | 902 Each action class also has a ``*permission*`` method which determines whether |
| 903 action is permissible given the current user. The base permission checks | 903 the action is permissible given the current user. The base permission checks |
| 904 are: | 904 are: |
| 905 | 905 |
| 906 **login** | 906 **login** |
| 907 Determine whether the user has permission to log in. Base behaviour is | 907 Determine whether the user has permission to log in. Base behaviour is |
| 908 to check the user has "Web Access". | 908 to check the user has "Web Access". |
| 2099 def handle(self): | 2099 def handle(self): |
| 2100 ''' Perform some action. No return value is required. | 2100 ''' Perform some action. No return value is required. |
| 2101 ''' | 2101 ''' |
| 2102 | 2102 |
| 2103 The *self.client* attribute is an instance of your tracker ``instance.Client`` | 2103 The *self.client* attribute is an instance of your tracker ``instance.Client`` |
| 2104 class - thus it's mostly implemented by ``roundup.cgi.Client``. See the | 2104 class - thus it's mostly implemented by ``roundup.cgi.client.Client``. See the |
| 2105 docstring of that class for details of what it can do. | 2105 docstring of that class for details of what it can do. |
| 2106 | 2106 |
| 2107 The method will typically check the ``self.form`` variable's contents. | 2107 The method will typically check the ``self.form`` variable's contents. |
| 2108 It may then: | 2108 It may then: |
| 2109 | 2109 |
| 2824 the ``crypt`` module in your Python distribution). An example entry | 2824 the ``crypt`` module in your Python distribution). An example entry |
| 2825 would be:: | 2825 would be:: |
| 2826 | 2826 |
| 2827 admin:aamrgyQfDFSHw | 2827 admin:aamrgyQfDFSHw |
| 2828 | 2828 |
| 2829 Each user of Roundup must still have their information stored in the | 2829 Each user of Roundup must still have their information stored in the Roundup |
| 2830 Roundup database - we just use the passwd file to check their password. | 2830 database - we just use the passwd file to check their password. To do this, we |
| 2831 To do this, we add the following code to our ``Client`` class in the | 2831 need to override the standard ``verifyPassword`` method defined in |
| 2832 tracker home ``interfaces.py`` module:: | 2832 ``roundup.cgi.actions.LoginAction`` and register the new class with our |
| 2833 | 2833 ``Client`` class in the tracker home ``interfaces.py`` module:: |
| 2834 def verifyPassword(self, userid, password): | 2834 |
| 2835 # get the user's username | 2835 from roundup.cgi.actions import LoginAction |
| 2836 username = self.db.user.get(userid, 'username') | 2836 |
| 2837 | 2837 class ExternalPasswordLoginAction(LoginAction): |
| 2838 # the passwords are stored in the "passwd.txt" file in the | 2838 def verifyPassword(self, userid, password): |
| 2839 # tracker home | 2839 # get the user's username |
| 2840 file = os.path.join(self.db.config.TRACKER_HOME, 'passwd.txt') | 2840 username = self.db.user.get(userid, 'username') |
| 2841 | 2841 |
| 2842 # see if we can find a match | 2842 # the passwords are stored in the "passwd.txt" file in the |
| 2843 for ent in [line.strip().split(':') for line in | 2843 # tracker home |
| 2844 open(file).readlines()]: | 2844 file = os.path.join(self.db.config.TRACKER_HOME, 'passwd.txt') |
| 2845 if ent[0] == username: | 2845 |
| 2846 return crypt.crypt(password, ent[1][:2]) == ent[1] | 2846 # see if we can find a match |
| 2847 | 2847 for ent in [line.strip().split(':') for line in |
| 2848 # user doesn't exist in the file | 2848 open(file).readlines()]: |
| 2849 return 0 | 2849 if ent[0] == username: |
| 2850 return crypt.crypt(password, ent[1][:2]) == ent[1] | |
| 2851 | |
| 2852 # user doesn't exist in the file | |
| 2853 return 0 | |
| 2854 | |
| 2855 class Client(client.Client): | |
| 2856 actions = client.Client.actions + ( | |
| 2857 ('login', ExternalPasswordLoginAction) | |
| 2858 ) | |
| 2850 | 2859 |
| 2851 What this does is look through the file, line by line, looking for a | 2860 What this does is look through the file, line by line, looking for a |
| 2852 name that matches. | 2861 name that matches. |
| 2853 | 2862 |
| 2854 We also remove the redundant password fields from the ``user.item`` | 2863 We also remove the redundant password fields from the ``user.item`` |
| 3199 workflow). See the example `Using a UN*X passwd file as the user database`_ | 3208 workflow). See the example `Using a UN*X passwd file as the user database`_ |
| 3200 for more information about doing this. | 3209 for more information about doing this. |
| 3201 | 3210 |
| 3202 To authenticate off the LDAP store (rather than using the passwords in the | 3211 To authenticate off the LDAP store (rather than using the passwords in the |
| 3203 roundup user database) you'd use the same python-ldap module inside an | 3212 roundup user database) you'd use the same python-ldap module inside an |
| 3204 extension to the cgi interface. You'd do this by adding a method called | 3213 extension to the cgi interface. You'd do this by overriding the method called |
| 3205 "verifyPassword" to the Client class in your tracker's interfaces.py | 3214 "verifyPassword" on the LoginAction class in your tracker's interfaces.py |
| 3206 module. The method is implemented by default as:: | 3215 module (see `using an external password validation source`_). The method is |
| 3216 implemented by default as:: | |
| 3207 | 3217 |
| 3208 def verifyPassword(self, userid, password): | 3218 def verifyPassword(self, userid, password): |
| 3209 ''' Verify the password that the user has supplied | 3219 ''' Verify the password that the user has supplied |
| 3210 ''' | 3220 ''' |
| 3211 stored = self.db.user.get(self.userid, 'password') | 3221 stored = self.db.user.get(self.userid, 'password') |
