@@ -51,45 +51,60 @@ class UserAction(Action):
5151 A sequence of commands to perform on a single user.
5252 """
5353
54+ def _validate (self , email = None , username = None , domain = None ):
55+ local_regex = r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+([.][a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+)*"
56+ dns_regex = r"[a-zA-Z0-9-]+([.][a-zA-Z0-9-]+)+"
57+ email_regex = r"^" + local_regex + r"@" + dns_regex + r"$"
58+ username_regex = r"^" + local_regex + r"$"
59+ domain_regex = r"^" + dns_regex + r"$"
60+ if email and not re .match (email_regex , email ):
61+ raise ValueError ("Illegal email format (must not be quoted or contain comments)" )
62+ if domain and not re .match (domain_regex , domain ):
63+ raise ValueError ("Illegal domain format" )
64+ if username and not re .match (username_regex , username ):
65+ raise ValueError ("Illegal username format: must be the unquoted local part of an email" )
66+
5467 def __init__ (self , id_type = IdentityTypes .adobeID , email = None , username = None , domain = None , ** kwargs ):
5568 """
5669 Create an Action for a user identified either by email or by username and domain.
5770 There is never a reason to specify both email and username.
71+ :param id_type: IdentityTypes enum value (or the name of one), defaults to adobeID
5872 :param username: string, username in the Adobe domain (might be email)
5973 :param domain: string, required if the username is not an email address
6074 :param kwargs: other key/value pairs for the action, such as requestID
6175 """
76+ if str (id_type ) in IdentityTypes .__members__ :
77+ id_type = IdentityTypes [id_type ]
6278 if id_type not in IdentityTypes :
6379 raise ValueError ("Identity type ({}}) must be one of {}}" .format (id_type , [i .name for i in IdentityTypes ]))
80+ self .id_type = id_type
81+ self .email = None
82+ self .domain = None
83+ if username :
84+ if email and username .lower () == email .lower ():
85+ # ignore the username if it's the same as the email (policy default)
86+ username = None
87+ elif id_type is not IdentityTypes .federatedID :
88+ raise ValueError ("Username must match email except for Federated ID" )
89+ else :
90+ self ._validate (username = username )
91+ if domain :
92+ self ._validate (domain = domain )
93+ self .domain = domain
6494 if email :
65- if not re .match (r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+([.][a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+)*"
66- r"@"
67- r"[a-zA-Z0-9-]+([.][a-zA-Z0-9-]+)+$" , email ):
68- raise ValueError ("Illegal email format (must not be quoted or contain comments)" )
69- if username and id_type is not IdentityTypes .federatedID :
70- raise ValueError ("Only in Federated ID can username be specified" )
71- self .id_type = id_type
72- self .email = str (email )
73- atpos = email .index ('@' )
74- self .username = str (username ) if username else email [0 :atpos ]
75- self .domain = email [atpos + 1 :]
76- if domain and (str (domain ).lower () != str (self .domain ).lower ()):
77- raise ValueError ("Specified domain ({}) does not match email domain ({})" .format (domain , self .domain ))
78- Action .__init__ (self , user = email , ** kwargs )
95+ self ._validate (email = email )
96+ self .email = email
97+ if not self .domain :
98+ atpos = email .index ('@' )
99+ self .domain = email [atpos + 1 :]
100+ elif not username :
101+ raise ValueError ("No user identity specified." )
102+ elif not domain :
103+ raise ValueError ("Both username and domain must be specified" )
104+ if username :
105+ Action .__init__ (self , user = username , domain = self .domain , ** kwargs )
79106 else :
80- if not username or not domain :
81- raise ValueError ("Either email or both username and domain must be specified" )
82- if id_type is not IdentityTypes .federatedID :
83- raise ValueError ("Only in Federated ID can username be specified" )
84- if not re .match (r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+([.][a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+)*$" , username ):
85- raise ValueError ("Illegal username format: must be the unquoted local part of an email" )
86- if not re .match (r"^[a-zA-Z0-9-]+([.][a-zA-Z0-9-]+)+$" , domain ):
87- raise ValueError ("Illegal domain format" )
88- self .id_type = id_type
89- self .email = None
90- self .username = str (username )
91- self .domain = str (domain )
92- Action .__init__ (self , user = username , domain = domain , ** kwargs )
107+ Action .__init__ (self , user = email , ** kwargs )
93108
94109 def create (self , first_name = None , last_name = None , country = None , email = None ,
95110 on_conflict = IfAlreadyExistsOptions .errorIfAlreadyExists ):
@@ -99,25 +114,20 @@ def create(self, first_name=None, last_name=None, country=None, email=None,
99114 :param last_name: (optional) user last name
100115 :param country: (optional except for Federated ID) user 2-letter ISO country code
101116 :param email: user email, if not already specified at create time
102- :param on_conflict: how to handle users who already exist on the back end
117+ :param on_conflict: IfAlreadyExistsOption (or string name thereof) controlling creation of existing users
103118 :return: the User, so you can do User(...).create(...).add_group(...)
104119 """
105120 # all types handle email and on_conflict similarly
106121 create_params = {}
107122 if email is None :
108123 email = self .email
109124 elif self .email is None :
110- email = str (email )
111- if not re .match (r"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+([.][a-zA-Z0-9!#$%&'*+/=?^_`{|}~;-]+)*"
112- r"@"
113- r"[a-zA-Z0-9-]+([.][a-zA-Z0-9-]+)+$" , email ):
114- raise ValueError ("Illegal email format (must not be quoted or contain comments)" )
125+ self ._validate (email = email )
115126 self .email = email
116- atpos = email .index ('@' )
117- if self .domain .lower () != email [atpos + 1 :].lower ():
118- raise ValueError ("User's email ({}) doesn't match domain ({})" , email , self .domain )
119- elif self .email .lower () != str (email ).lower ():
127+ elif self .email .lower () != email .lower ():
120128 raise ValueError ("Specified email ({}) doesn't match user's email({})" , email , self .email )
129+ if str (on_conflict ) in IfAlreadyExistsOptions .__members__ :
130+ on_conflict = IfAlreadyExistsOptions [on_conflict ]
121131 if on_conflict not in IfAlreadyExistsOptions :
122132 raise ValueError ("on_conflict must be one of {}" .format ([o .name for o in IfAlreadyExistsOptions ]))
123133 if on_conflict != IfAlreadyExistsOptions .errorIfAlreadyExists :
@@ -157,8 +167,9 @@ def update(self, email=None, username=None, first_name=None, last_name=None, cou
157167 """
158168 if self .id_type is IdentityTypes .adobeID :
159169 raise ValueError ("You cannot update any attributes of an Adobe ID." )
160- if username and self .id_type is not IdentityTypes .federatedID :
161- raise ValueError ("You can only update the username attribute of a Federated ID" )
170+ if email : self ._validate (email = email )
171+ if username and self .id_type is IdentityTypes .enterpriseID :
172+ self ._validate (email = username )
162173 updates = {}
163174 for k , v in six .iteritems (dict (email = email , username = username ,
164175 firstName = first_name , lastName = last_name ,
0 commit comments