def deserialize_contributors(node, user_dicts, auth, validate=False): """View helper that returns a list of User objects from a list of serialized users (dicts). The users in the list may be registered or unregistered users. e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..}, {'id': None, 'registered': False, 'fullname'...}, {'id': '123ab', 'registered': False, 'fullname': ...}] If a dict represents an unregistered user without an ID, creates a new unregistered User record. :param Node node: The node to add contributors to :param list(dict) user_dicts: List of serialized users in the format above. :param Auth auth: :param bool validate: Whether to validate and sanitize fields (if necessary) """ # Add the registered contributors contribs = [] for contrib_dict in user_dicts: fullname = contrib_dict['fullname'] visible = contrib_dict['visible'] email = contrib_dict.get('email') if validate is True: # Validate and sanitize inputs as needed. Email will raise error if invalid. # TODO Edge case bug: validation and saving are performed in same loop, so all in list # up to the invalid entry will be saved. (communicate to the user what needs to be retried) fullname = sanitize.strip_html(fullname) if not fullname: raise ValidationError('Full name field cannot be empty') if email: validate_email(email) # Will raise a ValidationError if email invalid if contrib_dict['id']: contributor = OSFUser.load(contrib_dict['id']) else: try: contributor = OSFUser.create_unregistered( fullname=fullname, email=email) contributor.save() except ValidationError: ## FIXME: This suppresses an exception if ID not found & new validation fails; get_user will return None contributor = get_user(email=email) # Add unclaimed record if necessary if not contributor.is_registered: contributor.add_unclaimed_record(node, referrer=auth.user, given_name=fullname, email=email) contributor.save() contribs.append({ 'user': contributor, 'visible': visible, 'permissions': expand_permissions(contrib_dict.get('permission')) }) return contribs
def add_unconfirmed_email(self, email, expiration=None): """Add an email verification token for a given email.""" # TODO: This is technically not compliant with RFC 822, which requires # that case be preserved in the "local-part" of an address. From # a practical standpoint, the vast majority of email servers do # not preserve case. # ref: https://tools.ietf.org/html/rfc822#section-6 email = email.lower().strip() if email in self.emails: raise ValueError("Email already confirmed to this user.") utils.validate_email(email) # If the unconfirmed email is already present, refresh the token if email in self.unconfirmed_emails: self.remove_unconfirmed_email(email) token = generate_confirm_token() # handle when email_verifications is None if not self.email_verifications: self.email_verifications = {} self.email_verifications[token] = {'email': email} self._set_email_token_expiration(token, expiration=expiration) return token
def invite_contributor_post(node, **kwargs): """API view for inviting an unregistered user. Performs validation, but does not actually invite the user. Expects JSON arguments with 'fullname' (required) and email (not required). """ fullname = request.json.get('fullname').strip() email = request.json.get('email') # Validate and sanitize inputs as needed. Email will raise error if invalid. fullname = sanitize.strip_html(fullname) if email: email = email.lower().strip() try: validate_email(email) except ValidationError as e: return {'status': 400, 'message': e.message}, 400 if not fullname: return { 'status': 400, 'message': 'Full name field cannot be empty' }, 400 # Check if email is in the database user = get_user(email=email) if user: if user.is_registered: msg = 'User is already in database. Please go back and try your search again.' return {'status': 400, 'message': msg}, 400 elif node.is_contributor(user): msg = 'User with this email address is already a contributor to this project.' return {'status': 400, 'message': msg}, 400 elif not user.is_confirmed: serialized = profile_utils.serialize_unregistered(fullname, email) else: serialized = profile_utils.add_contributor_json(user) # use correct display name serialized['fullname'] = fullname serialized['email'] = email else: # Create a placeholder serialized = profile_utils.serialize_unregistered(fullname, email) return {'status': 'success', 'contributor': serialized}
def invite_contributor_post(node, **kwargs): """API view for inviting an unregistered user. Performs validation, but does not actually invite the user. Expects JSON arguments with 'fullname' (required) and email (not required). """ fullname = request.json.get('fullname').strip() email = request.json.get('email') # Validate and sanitize inputs as needed. Email will raise error if invalid. fullname = sanitize.strip_html(fullname) if email: email = email.lower().strip() try: validate_email(email) except ValidationError as e: return {'status': 400, 'message': e.message}, 400 if not fullname: return {'status': 400, 'message': 'Full name field cannot be empty'}, 400 # Check if email is in the database user = get_user(email=email) if user: if user.is_registered: msg = 'User is already in database. Please go back and try your search again.' return {'status': 400, 'message': msg}, 400 elif node.is_contributor(user): msg = 'User with this email address is already a contributor to this project.' return {'status': 400, 'message': msg}, 400 elif not user.is_confirmed: serialized = profile_utils.serialize_unregistered(fullname, email) else: serialized = profile_utils.add_contributor_json(user) # use correct display name serialized['fullname'] = fullname serialized['email'] = email else: # Create a placeholder serialized = profile_utils.serialize_unregistered(fullname, email) return {'status': 'success', 'contributor': serialized}