Changeset 1252
- Timestamp:
- 04/26/06 15:18:30 (3 years ago)
- Files:
-
- branches/1.0/CHANGELOG.txt (modified) (2 diffs)
- branches/1.0/CONTRIBUTORS.txt (modified) (1 diff)
- branches/1.0/plugins/json/turbojson/jsonify.py (modified) (2 diffs)
- branches/1.0/turbogears/command/quickstart.py (modified) (9 diffs)
- branches/1.0/turbogears/identity/__init__.py (modified) (3 diffs)
- branches/1.0/turbogears/identity/soprovider.py (modified) (13 diffs)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl (modified) (6 diffs)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/controllers.py_tmpl (modified) (3 diffs)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/json.py_tmpl (added)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/model.py_tmpl (modified) (2 diffs)
- branches/1.0/turbogears/qstemplates/quickstart/+package+/tests/test_model.py_tmpl (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/1.0/CHANGELOG.txt
r1231 r1252 16 16 permissionId to be user\_name, group\_name, and permission_name. 17 17 * visit\_id has been deprecated in favor of visit_key 18 19 *Changes* 20 21 * Identity model classes are now placed directly into the model.py of 22 a quickstarted project. This new setup is much easier to change, 23 since requirements for the identity model vary dramatically. Another 24 advantage is that quickstart projects that don't need identity 25 start off with cleaner code, and projects that do need identity 26 need almost no additional configuration or setup. 27 * quickstart projects include a "json.py" file as a home for JSON 28 view code. 18 29 19 30 *Fixes* … … 35 46 36 47 Alberto Valverde González, Jeff Watkins, Max Ischenko, Michele Cella, 37 Simon Belak, Jorge Godoy, Jo ost Moesker, Joseph Tate, Andrey Lebedev,38 Brian Beck, Roger Demetrescu.48 Simon Belak, Jorge Godoy, Jorge Vargas, Joost Moesker, Joseph Tate, 49 Andrey Lebedev, Brian Beck, Roger Demetrescu. 39 50 40 51 0.9a4 (April 5, 2006) branches/1.0/CONTRIBUTORS.txt
r903 r1252 18 18 * Alberto Valverde 19 19 * Lee McFadden 20 * Jorge Godoy 20 21 * Ondrej Zara (author of WWW SQL Designer) 21 22 branches/1.0/plugins/json/turbojson/jsonify.py
r1203 r1252 32 32 result['id'] = obj.id 33 33 for name in obj.sqlmeta.columns.keys(): 34 result[name] = jsonify(getattr(obj, name))34 result[name] = getattr(obj, name) 35 35 return result 36 36 jsonify_sqlobject = jsonify.when( … … 48 48 49 49 def jsonify_select_results(obj): 50 return jsonify_list(obj)50 return list(obj) 51 51 jsonify_select_results = jsonify.when( 52 52 'isinstance(obj, sqlobject.SQLObject.SelectResultsClass)')( branches/1.0/turbogears/command/quickstart.py
r1076 r1252 40 40 "quickstart") 41 41 summary = "web framework" 42 use_cheetah = True 42 43 43 44 … … 88 89 package = None 89 90 templates = "turbogears" 91 identity = None 90 92 91 93 def __init__(self, version): 92 parser = optparse.OptionParser(usage="%prog quickstart [options] [project name]", 93 version="%prog " + version) 94 parser.add_option("-p", "--package", help="package name for the code", 94 parser = optparse.OptionParser( 95 usage="%prog quickstart [options] [project name]", 96 version="%prog " + version) 97 parser.add_option("-p", "--package", 98 help="package name for the code", 95 99 dest="package") 96 parser.add_option("--dry-run", help="dry run (don't actually do anything)", 100 parser.add_option("--dry-run", 101 help="dry run (don't actually do anything)", 97 102 action="store_true", dest="dry_run") 98 parser.add_option("-t", "--templates", help="user specific templates", 103 parser.add_option("-t", "--templates", 104 help="user specific templates", 99 105 dest="templates", default = self.templates) 106 parser.add_option("-i", "--identity", 107 help="identity provider to use (sqlobject (default)," 108 " sqlalchemy, none)", 109 dest="identity", default = self.identity) 110 100 111 (options, args) = parser.parse_args() 101 112 self.__dict__.update(options.__dict__) … … 118 129 self.package = package 119 130 131 while not self.identity: 132 self.identity = raw_input("Choose an identity provider sqlobject, sqlalchemy or none [sqlobject]: ").lower() 133 if not self.identity: 134 self.identity = "sqlobject" 135 if self.identity not in ["sqlobject", "sqlalchemy", "none"]: 136 print "Please enter one of 'sqlobject', 'sqlalchemy' or " \ 137 " 'none'" 138 self.identity = "" 139 continue 140 120 141 self.name = pkg_resources.safe_name(self.name) 121 142 … … 138 159 print("A directory called '%s' already exists. Exiting." 139 160 % self.name) 140 return 141 161 return 162 163 142 164 command = create_distro.CreateDistroCommand("create") 143 165 cmd_args = [] … … 146 168 cmd_args.append(self.name) 147 169 cmd_args.append("package=%s" %self.package) 170 cmd_args.append("identity=%s" %self.identity) 148 171 if self.dry_run: 149 172 cmd_args.append("--simulate") … … 175 198 name = None 176 199 templates = "turbogears" 200 identity = None 177 201 178 202 def __init__(self, version): … … 181 205 parser.add_option("-t", "--templates", help="user specific templates", 182 206 dest="templates", default=self.templates) 207 parser.add_option("-i", "--identity", 208 help="identity provider to use (sqlobject (default)," 209 " sqlalchemy, none)", 210 dest="identity", default = self.identity) 183 211 (options, args) = parser.parse_args() 184 212 self.__dict__.update(options.__dict__) … … 189 217 self.name = turbogears.util.get_project_name() 190 218 self.package = turbogears.util.get_package_name() 219 if not self.identity: 220 self.identity = turbogears.config.get("identity.provider", 221 "none") 191 222 currentdir = os.path.basename(os.getcwd()) 192 223 if not currentdir == self.name: … … 205 236 cmd_args.append(self.name) 206 237 cmd_args.append("package=%s" %self.package) 238 cmd_args.append("identity=%s" %self.identity) 207 239 command.run(cmd_args) 208 240 branches/1.0/turbogears/identity/__init__.py
r1037 r1252 13 13 from turbogears.util import request_available 14 14 from turbogears.identity.exceptions import * 15 16 15 17 16 def create_default_provider(): … … 107 106 from turbogears.identity.conditions import * 108 107 108 def encrypt_password(cleartext): 109 # this next one ultimately needs to change to support SQLAlchemy 110 from turbogears.identity.soprovider import encrypt_password 111 return encrypt_password(cleartext) 112 109 113 # declare what should be exported 110 114 __all__ = [ "IdentityManagementNotEnabledException", … … 114 118 "set_current_identity", "set_current_provider", 115 119 "set_identity_errors", "get_identity_errors", 116 "was_login_attempted" ]120 "was_login_attempted", "encrypt_password" ] branches/1.0/turbogears/identity/soprovider.py
r1128 r1252 3 3 import random 4 4 5 from turbojson.jsonify import *5 from turbojson.jsonify import jsonify_sqlobject, jsonify 6 6 from sqlobject import * 7 7 from sqlobject.inheritance import InheritableSQLObject … … 49 49 group_class= None 50 50 permission_class= None 51 visit_class = None 51 52 52 53 class SqlObjectIdentity(object): … … 65 66 # a _user attribute, even if the value is None. 66 67 try: 67 visit= TG_VisitIdentity.by_visit_key( self.visit_key )68 visit= visit_class.by_visit_key( self.visit_key ) 68 69 except SQLObjectNotFound: 69 70 # The visit ID is invalid … … 122 123 return 123 124 try: 124 visit= TG_VisitIdentity.by_visit_key(self.visit_key)125 visit= visit_class.by_visit_key(self.visit_key) 125 126 visit.destroySelf() 126 127 # Clear the current identity … … 141 142 get=turbogears.config.get 142 143 143 global user_class, group_class, permission_class 144 global user_class, group_class, permission_class, visit_class 144 145 145 146 user_class_path= get( "identity.soprovider.model.user", … … 150 151 if user_class: 151 152 log.info("Succesfully loaded \"%s\"" % user_class_path) 153 152 154 group_class_path= get( "identity.soprovider.model.group", 153 155 __name__ + ".TG_Group" ) … … 155 157 if group_class: 156 158 log.info("Succesfully loaded \"%s\"" % group_class_path) 159 157 160 permission_class_path= get( "identity.soprovider.model.permission", 158 161 __name__ + ".TG_Permission" ) … … 160 163 if permission_class: 161 164 log.info("Succesfully loaded \"%s\"" % permission_class_path) 165 166 visit_class_path= get( "visit.soprovider.model", 167 __name__ + ".TG_VisitIdentity" ) 168 visit_class= load_class(visit_class_path) 169 if visit_class: 170 log.info("Succesfully loaded \"%s\"" % visit_class_path) 171 162 172 163 173 # Default encryption algorithm is to use plain text passwords … … 177 187 group_class.createTable(ifNotExists=True) 178 188 permission_class.createTable(ifNotExists=True) 179 TG_VisitIdentity.createTable(ifNotExists=True)189 visit_class.createTable(ifNotExists=True) 180 190 hub.commit() 181 191 hub.end() … … 204 214 # Link the user to the visit 205 215 try: 206 link= TG_VisitIdentity.by_visit_key( visit_key )216 link= visit_class.by_visit_key( visit_key ) 207 217 link.user_id= user.id 208 218 except SQLObjectNotFound: 209 link= TG_VisitIdentity( visit_key=visit_key, user_id=user.id )219 link= visit_class( visit_key=visit_key, user_id=user.id ) 210 220 return SqlObjectIdentity( visit_key, user ) 211 221 … … 275 285 def jsonify_group(obj): 276 286 result = jsonify_sqlobject( obj ) 277 result["users"]= jsonify( [u.user_name for u in obj.users] )278 result["permissions"]= jsonify( [p.permission_name for p in obj.permissions] )287 result["users"]= [u.user_name for u in obj.users] 288 result["permissions"]= [p.permission_name for p in obj.permissions] 279 289 return result 280 290 … … 334 344 result = jsonify_sqlobject( obj ) 335 345 del result['password'] 336 result["groups"]= jsonify( [g.group_name for g in obj.groups] )337 result["permissions"]= jsonify( [p.permission_name for p in obj.permissions] )346 result["groups"]= [g.group_name for g in obj.groups] 347 result["permissions"]= [p.permission_name for p in obj.permissions] 338 348 return result 339 349 … … 358 368 def jsonify_permission(obj): 359 369 result = jsonify_sqlobject( obj ) 360 result["groups"]= jsonify( [g.group_name for g in obj.groups] )370 result["groups"]= [g.group_name for g in obj.groups] 361 371 return result 362 372 363 373 jsonify_permission = jsonify.when( 364 374 'isinstance(obj, TG_Permission)')(jsonify_permission) 375 376 def encrypt_password(cleartext_password): 377 try: 378 hash = identity.current_provider.\ 379 encrypt_password(cleartext_password) 380 except identity.exceptions.RequestRequiredException: 381 # Creating identity provider just to encrypt password 382 # (so we don't reimplement the encryption step). 383 ip = SqlObjectIdentityProvider() 384 hash = ip.encrypt_password(cleartext_password) 385 if hash == cleartext_password: 386 log.info("Identity provider not enabled, and no encryption " 387 "algorithm " 388 "specified in config. Setting password as plaintext.") 389 return hash branches/1.0/turbogears/qstemplates/quickstart/+package+/config/app.cfg_tmpl
r1175 r1252 34 34 # tg.mochikit_all = False 35 35 36 #if $identity != 'none' 36 37 # VISIT TRACKING 37 38 # Each visit to your application will be assigned a unique visit ID tracked via … … 40 41 41 42 # Enable Visit tracking 42 # visit.on=False43 visit.on=True 43 44 44 45 # Number of minutes a visit may be idle before it expires. … … 58 59 59 60 # The name of the VisitManager plugin to use for visitor tracking. 60 # visit.manager="sqlobject"61 visit.manager="${identity}" 61 62 63 #if $identity == "sqlobject" 64 # Database class to use for visit tracking 65 visit.soprovider.model = "${package}.model.VisitIdentity" 66 #else if $identity == "sqlalchemy" 67 # Database class to use for visit tracking 68 visit.saprovider.model = "${package}.model.VisitIdentity" 69 #end if 62 70 63 71 # IDENTITY … … 66 74 67 75 # Switch to turn on or off the Identity management module 68 # identity.on=False76 identity.on=True 69 77 70 78 # [REQUIRED] URL to which CherryPy will internally redirect when an access 71 79 # control check fails. If Identity management is turned on, a value for this 72 80 # option must be specified. 73 # identity.failure_url=None 81 identity.failure_url="/login" 74 82 75 # The IdentityProvider to use -- defaults to the SqlObjectIdentityProvider which 76 # pulls User, Group, and Permission data out of your model database. 77 # identity.provider="sqlobject" 83 # identity.provider='${identity}' 78 84 79 85 # The names of the fields on the login form containing the visitor's user ID … … 90 96 # identity.source="form,http_auth,visit" 91 97 92 98 #if $identity=='sqlobject' 93 99 # SqlObjectIdentityProvider 94 100 # Configuration options for the default IdentityProvider 95 101 # ------------------------- 96 102 97 # The classes you wish to use for your Identity model. Leave these commented out 98 # to use the default classes for SqlObjectIdentityProvider. Or set them to the 99 # classes in your model. NOTE: These aren't TG_* because the TG prefix is 100 # reserved for classes created by TurboGears. Also remember to not use reserved 103 # The classes you wish to use for your Identity model. Remember to not use reserved 101 104 # SQL keywords for class names (at least unless you specify a different table 102 105 # name using sqlmeta). 103 # identity.soprovider.model.user="${package}.model.MyUserClass"104 # identity.soprovider.model.group="${package}.model.MyGroupClass"105 # identity.soprovider.model.permission="${package}.model.MyPermissionClass"106 identity.soprovider.model.user="${package}.model.User" 107 identity.soprovider.model.group="${package}.model.Group" 108 identity.soprovider.model.permission="${package}.model.Permission" 106 109 107 110 # The password encryption algorithm used when comparing passwords against what's … … 117 120 118 121 # identity.soprovider.encryption_algorithm=None 122 #else 123 # SqlAlchemyIdentityProvider 124 # Configuration options for the default IdentityProvider 125 # ------------------------- 119 126 127 # The classes you wish to use for your Identity model. Remember to not use reserved 128 # SQL keywords for class names (at least unless you specify a different table 129 # name using sqlmeta). 130 identity.saprovider.model.user="${package}.model.User" 131 identity.saprovider.model.group="${package}.model.Group" 132 identity.saprovider.model.permission="${package}.model.Permission" 133 134 # The password encryption algorithm used when comparing passwords against what's 135 # stored in the database. Valid values are 'md5' or 'sha1'. If you do not 136 # specify an encryption algorithm, passwords are expected to be clear text. 137 # 138 # The SqlAlchemyProvider *will* encrypt passwords supplied as part of your login 139 # form. If you set the password through the password property, like: 140 # my_user.password = 'secret' 141 # the password will be encrypted in the database, provided identity is up and 142 # running, or you have loaded the configuration specifying what encryption to 143 # use (in situations where identity may not yet be running, like tests). 144 145 # identity.saprovider.encryption_algorithm=None 146 #end if 147 #end if 120 148 [/static] 121 149 static_filter.on = True branches/1.0/turbogears/qstemplates/quickstart/+package+/controllers.py_tmpl
r1108 r1252 3 3 from turbogears import controllers, expose, redirect 4 4 from turbogears import identity 5 6 from ${package} import json 5 7 6 8 class Root(controllers.RootController): … … 9 11 import time 10 12 return dict(now=time.ctime()) 13 #if $identity != "none" 11 14 12 15 @expose(template="${package}.templates.login") … … 37 40 identity.current.logout() 38 41 raise redirect("/") 42 #end if branches/1.0/turbogears/qstemplates/quickstart/+package+/model.py_tmpl
r710 r1252 1 #if $identity != "none" 2 from datetime import datetime 3 4 #end if 1 5 from sqlobject import * 2 6 from turbogears.database import PackageHub 3 # Uncomment the following line if you wish to use Identity and SO_Provider 4 # from turbogears.identity.soprovider import TG_User, TG_Group, TG_Permission 7 #if $identity == "sqlobject" 8 from turbogears import identity 9 #end if 5 10 6 11 hub = PackageHub("${package}") … … 9 14 # class YourDataClass(SQLObject): 10 15 # pass 16 17 18 #if $identity=="sqlobject" 19 20 class VisitIdentity(SQLObject): 21 visit_key = StringCol( length=40, alternateID=True, 22 alternateMethodName="by_visit_key" ) 23 user_id = IntCol() 24 25 26 class Group(SQLObject): 27 """ 28 An ultra-simple group definition. 29 """ 30 31 # names like "Group" and "Order" are reserved words in SQL 32 # so we set the name to something safe for SQL 33 class sqlmeta: 34 table="tg_group" 35 36 group_name = UnicodeCol( length=16, alternateID=True, 37 alternateMethodName="by_group_name" ) 38 display_name = UnicodeCol( length=255 ) 39 created = DateTimeCol( default=datetime.now ) 40 41 # collection of all users belonging to this group 42 users = RelatedJoin( "User", intermediateTable="user_group", 43 joinColumn="group_id", otherColumn="user_id" ) 44 45 # collection of all permissions for this group 46 permissions = RelatedJoin( "Permission", joinColumn="group_id", 47 intermediateTable="group_permission", 48 otherColumn="permission_id" ) 49 50 51 class User(SQLObject): 52 """ 53 Reasonably basic User definition. Probably would want additional attributes. 54 """ 55 user_name = UnicodeCol( length=16, alternateID=True, 56 alternateMethodName="by_user_name" ) 57 email_address = UnicodeCol( length=255, alternateID=True, 58 alternateMethodName="by_email_address" ) 59 display_name = UnicodeCol( length=255 ) 60 password = UnicodeCol( length=40 ) 61 created = DateTimeCol( default=datetime.now ) 62 63 # groups this user belongs to 64 groups = RelatedJoin( "Group", intermediateTable="user_group", 65 joinColumn="user_id", otherColumn="group_id" ) 66 67 def _get_permissions( self ): 68 perms = set() 69 for g in self.groups: 70 perms = perms | set(g.permissions) 71 return perms 72 73 def _set_password( self, cleartext_password ): 74 "Runs cleartext_password through the hash algorithm before saving." 75 hash = identity.encrypt_password(cleartext_password) 76 self._SO_set_password(hash) 77 78 def set_password_raw( self, password ): 79 "Saves the password as-is to the database." 80 self._SO_set_password(password) 81 82 83 84 class Permission(SQLObject): 85 permission_name = UnicodeCol( length=16, alternateID=True, 86 alternateMethodName="by_permission_name" ) 87 description = UnicodeCol( length=255 ) 88 89 groups = RelatedJoin( "Group", 90 intermediateTable="group_permission", 91 joinColumn="permission_id", 92 otherColumn="group_id" ) 93 94 95 #else if $identity=="sqlalchemy" 96 from sqlalchemy.ext.activemapper import * 97 98 # tables for SQLAlchemy identity 99 user_group = Table( "user_group", __engine__, 100 Column( "user_id", Integer, 101 ForeignKey("user.user_id"), 102 primary_key=True ), 103 Column( "group_id", Integer, 104 ForeignKey("group.group_id"), 105 primary_key=True ) ) 106 107 group_permission = Table( "group_permission", __engine__, 108 Column( "group_id", Integer, 109 ForeignKey("group.group_id"), 110 primary_key=True ), 111 Column( "permission_id", Integer, 112 ForeignKey("permission.permission_id"), 113 primary_key=True ) ) 114 115 116 class VisitIdentity(ActiveMapper): 117 class mapping: 118 __table__="visit_identity" 119 visit_key = column( String, # foreign_key="visit.visit_key", 120 primary_key=True ) 121 user_id = column( Integer, foreign_key="user.user_id", index=True ) 122 123 124 class Group(ActiveMapper): 125 """ 126 An ultra-simple group definition. 127 """ 128 class mapping: 129 __table__="tg_group" 130 group_id = column( Integer, primary_key=True ) 131 group_name = column( Unicode(16), unique=True ) 132 display_name = column( Unicode(255) ) 133 created = column( DateTime, default=datetime.now ) 134 135 users = many_to_many( "User", user_group, backref="groups" ) 136 permissions = many_to_many( "Permission", group_permission, 137 backref="groups" ) 138 139 140 class User(ActiveMapper): 141 """ 142 Reasonably basic User definition. Probably would want additional attributes. 143 """ 144 class mapping: 145 __table__="user" 146 user_id = column( Integer, primary_key=True ) 147 user_name = column( Unicode(16), unique=True ) 148 email_address = column( Unicode(255), unique=True ) 149 display_name = column( Unicode(255) ) 150 password = column( Unicode(40) ) 151 created = column( DateTime, default=datetime.now ) 152 153 groups = many_to_many( "Group", user_group, backref="users" ) 154 155 @property 156 def permissions( self ): 157 perms = set() 158 for g in self.groups: 159 perms = perms | set(g.permissions) 160 return perms 161 162 163 class Permission(ActiveMapper): 164 class mapping: 165 __table__="permission" 166 permission_id = column( Integer, primary_key=True ) 167 permission_name = column( Unicode(16), unique=True ) 168 description = column( Unicode(255) ) 169 170 groups = many_to_many( "Group", group_permission, 171 backref="permmissions" ) 172 #end if branches/1.0/turbogears/qstemplates/quickstart/+package+/tests/test_model.py_tmpl
r1107 r1252 6 6 7 7 from turbogears import testutil 8 #from ${package}.model import YourDataClass 9 #from turbogears.identity.soprovider import TG_User 8 # from ${package}.model import YourDataClass, User 10 9 11 10 # database.set_db_uri("sqlite:///:memory:") … … 13 12 # class testTG_User(testutil.DBTest): 14 13 # def get_model(self): 15 # return TG_User14 # return User 16 15 # 17 16 # def test_creation(self): 18 17 # "Object creation should set the name" 19 # obj = TG_User(user_name = "creosote",18 # obj = User(user_name = "creosote", 20 19 # email_address = "spam@python.not", 21 20 # display_name = "Mr Creosote",