def get_user_by_email(email, create_pending=False): """finds a user based on his email address. :param email: The email address of the user. :param create_pending: If True, this function searches for external users and creates a new pending User in case no existing user was found. :return: A :class:`.User` instance or ``None`` if not exactly one user was found. """ email = email.lower().strip() if not email: return None if not create_pending: res = User.find_all(~User.is_deleted, User.all_emails.contains(email)) else: res = search_users(exact=True, include_pending=True, external=True, email=email) if len(res) != 1: return None user_or_identity = next(iter(res)) if isinstance(user_or_identity, User): return user_or_identity elif not create_pending: return None # Create a new pending user data = user_or_identity.data user = User(first_name=data.get('first_name') or '', last_name=data.get('last_name') or '', email=data['email'], address=data.get('address', ''), phone=data.get('phone', ''), affiliation=data.get('affiliation', ''), is_pending=True) db.session.add(user) db.session.flush() return user
def test_deletion_no_primary_email(): # this tests setting the is_deleted property on a user with no primary email # very unlikely case but let's make sure we never try to set the deleted # flag on a None primary email. user = User() assert user.email is None user.is_deleted = True
def _original_user(self): # A proper user, with an id that can be mapped directly to sqlalchemy if isinstance(self.id, int) or self.id.isdigit(): return User.get(int(self.id)) # A user who had no real fossir account but an ldap identifier/email. # In this case we try to find his real user and replace the ID of this object # with that user's ID. data = self.id.split(':') # TODO: Once everything is in SQLAlchemy this whole thing needs to go away! user = None if data[0] == 'LDAP': identifier = data[1] email = data[2] # You better have only one ldap provider or at least different identifiers ;) identity = Identity.find_first(Identity.provider != 'fossir', Identity.identifier == identifier) if identity: user = identity.user elif data[0] == 'Nice': email = data[1] else: return None if not user: user = User.find_first(User.all_emails.contains(email)) if user: self._old_id = self.id self.id = str(user.id) logger.info("Updated legacy user id (%s => %s)", self._old_id, self.id) return user
def test_title(db): user = User(first_name='Guinea', last_name='Pig') db.session.add(user) db.session.flush() assert user.title == '' user.title = UserTitle.prof assert user.title == UserTitle.prof.title assert is_lazy_string(user.title) assert User.find_one(title=UserTitle.prof) == user
def test_emails(db): user = User(first_name='Guinea', last_name='Pig') db.session.add(user) db.session.flush() assert user.email is None assert not user.secondary_emails user.email = '*****@*****.**' db.session.flush() assert user.all_emails == {'*****@*****.**'} user.secondary_emails.add('*****@*****.**') db.session.flush() assert user.all_emails == {'*****@*****.**', '*****@*****.**'}
def test_deletion(db): user = User(first_name='Guinea', last_name='Pig', email='*****@*****.**', secondary_emails=['[email protected]']) db.session.add(user) db.session.flush() assert not user.is_deleted assert all(not ue.is_user_deleted for ue in user._all_emails) user.is_deleted = True db.session.flush() assert all(ue.is_user_deleted for ue in user._all_emails)
def test_get_full_name_empty_names(first_name, last_name): user = User(first_name=first_name, last_name=last_name, title=UserTitle.none) for last_name_first, last_name_upper, abbrev_first_name in itertools.product( (True, False), repeat=3): # Just make sure it doesn't fail. We don't really care about the output. # It's only allowed for pending users so in most cases it only shows up # in the ``repr`` of such a user. user.get_full_name(last_name_first=last_name_first, last_name_upper=last_name_upper, abbrev_first_name=abbrev_first_name)
def create_user(email, data, identity=None, settings=None, other_emails=None, from_moderation=True): """Create a new user. This may also convert a pending user to a proper user in case the email address matches such a user. :param email: The primary email address of the user. :param data: The data used to populate the user. :param identity: An `Identity` to associate with the user. :param settings: A dict containing user settings. :param other_emails: A set of email addresses that are also used to check for a pending user. They will also be added as secondary emails to the user. :param from_moderation: Whether the user was created through the moderation process or manually by an admin. """ if other_emails is None: other_emails = set() if settings is None: settings = {} settings.setdefault('timezone', config.DEFAULT_TIMEZONE) settings.setdefault('lang', config.DEFAULT_LOCALE) settings.setdefault('suggest_categories', False) # Get a pending user if there is one user = User.find_first( ~User.is_deleted, User.is_pending, User.all_emails.contains(db.func.any(list({email} | set(other_emails))))) if not user: user = User() if email in user.secondary_emails: # This can happen if there's a pending user who has a secondary email # for some weird reason which should now become the primary email... user.make_email_primary(email) else: user.email = email user.populate_from_dict(data) user.is_pending = False user.secondary_emails |= other_emails user.favorite_users.add(user) if identity is not None: user.identities.add(identity) db.session.add(user) user.settings.set_multi(settings) db.session.flush() signals.users.registered.send(user, from_moderation=from_moderation, identity=identity) db.session.flush() return user
def _process_args(self): if not session.user: return self.user = session.user if 'user_id' in request.view_args: self.user = User.get(request.view_args['user_id']) if self.user is None: raise NotFound('This user does not exist') elif request.method == 'GET' and not request.is_xhr and self.flash_user_status: # Show messages about the user's status if it's a simple GET request if self.user.is_deleted: if self.user.merged_into_id is not None: msg = _( 'This user has been merged into <a href="{url}">another user</a>.' ) flash( Markup(msg).format(url=url_for( request.endpoint, self.user.merged_into_user)), 'warning') else: flash(_('This user is marked as deleted.'), 'warning') if self.user.is_pending: flash( _('This user is marked as pending, i.e. it has been attached to something but never ' 'logged in.'), 'warning') if not self.allow_system_user and self.user.is_system: return redirect(url_for('users.user_profile'))
def _process(self): users = [User.get(int(id_)) for id_ in request.form.getlist('user_id')] self.user.favorite_users |= set(filter(None, users)) tpl = get_template_module('users/_favorites.html') return jsonify(success=True, users=[serialize_user(user) for user in users], html=tpl.favorite_users_list(self.user))
def category_cleanup(): from fossir.modules.events import Event janitor_user = User.get_system_user() logger.debug("Checking whether any categories should be cleaned up") for categ_id, days in config.CATEGORY_CLEANUP.iteritems(): try: category = Category.get(int(categ_id), is_deleted=False) except KeyError: logger.warning("Category %s does not exist!", categ_id) continue now = now_utc() to_delete = Event.query.with_parent(category).filter( Event.created_dt < (now - timedelta(days=days))).all() if not to_delete: continue logger.info( "Category %s: %s events were created more than %s days ago and will be deleted", categ_id, len(to_delete), days) for i, event in enumerate(to_delete, 1): logger.info("Deleting %s", event) event.delete('Cleaning up category', janitor_user) if i % 100 == 0: db.session.commit() db.session.commit()
def _get_breadcrumbs(self): if 'user_id' in request.view_args: user = User.get(request.view_args['user_id']) profile_breadcrumb = _('Profile of {name}').format( name=user.full_name) else: profile_breadcrumb = _('My Profile') return render_breadcrumbs(profile_breadcrumb)
def _process(self): user = User.get(int(request.view_args['fav_user_id'])) self.user.favorite_users.discard(user) try: db.session.flush() except StaleDataError: # Deleted in another transaction db.session.rollback() return jsonify(success=True)
def export_user(self, user): if not user: raise HTTPAPIError('You need to be logged in', 403) user = User.get(self._user_id, is_deleted=False) if not user: raise HTTPAPIError('Requested user not found', 404) if not user.can_be_modified(user): raise HTTPAPIError('You do not have access to that info', 403) return [user.as_avatar.fossilize()]
def test_can_be_modified(): user = User() # user can modify himself assert user.can_be_modified(user) # admin can modify anyone assert user.can_be_modified(User(is_admin=True)) # normal users can't assert not user.can_be_modified(User())
def test_acls_invalid(): user = User() proxy = SettingsProxy('foo', {'reg': None}, acls={'acl'}) pytest.raises(ValueError, proxy.get, 'acl') pytest.raises(ValueError, proxy.set, 'acl', 'foo') pytest.raises(ValueError, proxy.acls.get, 'reg') pytest.raises(ValueError, proxy.acls.set, 'reg', {user}) pytest.raises(ValueError, proxy.acls.contains_user, 'reg', user) pytest.raises(ValueError, proxy.acls.add_principal, 'reg', user) pytest.raises(ValueError, proxy.acls.remove_principal, 'reg', user)
def _process(self): form = SearchForm(obj=FormDefaults(exact=True)) form_data = form.data search_results = None num_of_users = User.query.count() num_deleted_users = User.find(is_deleted=True).count() if form.validate_on_submit(): search_results = [] exact = form_data.pop('exact') include_deleted = form_data.pop('include_deleted') include_pending = form_data.pop('include_pending') external = form_data.pop('external') form_data = { k: v for (k, v) in form_data.iteritems() if v and v.strip() } matches = search_users(exact=exact, include_deleted=include_deleted, include_pending=include_pending, external=external, allow_system_user=True, **form_data) for entry in matches: if isinstance(entry, User): search_results.append( UserEntry(profile_url=url_for('.user_profile', entry), user=entry, **{ k: getattr(entry, k) for k in IDENTITY_ATTRIBUTES })) else: search_results.append( UserEntry(profile_url=None, user=None, full_name="{first_name} {last_name}".format( **entry.data.to_dict()), **{ k: entry.data.get(k) for k in (IDENTITY_ATTRIBUTES - {'full_name'}) })) search_results.sort(key=attrgetter('first_name', 'last_name')) num_reg_requests = RegistrationRequest.query.count() return WPUsersAdmin.render_template( 'users_admin.html', 'users', form=form, search_results=search_results, num_of_users=num_of_users, num_deleted_users=num_deleted_users, num_reg_requests=num_reg_requests)
def _process_args(self): self.identity_info = load_identity_info() if not self.identity_info or self.identity_info['fossir_user_id'] is None: # Just redirect to the front page or whereever we wanted to go. # Probably someone simply used his browser's back button. flash('There is no pending login.', 'warning') return multipass.redirect_success() self.user = User.get(self.identity_info['fossir_user_id']) self.emails = sorted(self.user.all_emails & set(self.identity_info['data'].getlist('email'))) self.verification_email_sent = self.identity_info.get('verification_email_sent', False) self.email_verified = self.identity_info['email_verified'] self.must_choose_email = len(self.emails) != 1 and not self.email_verified
def get_form_defaults(self): email = session.get('register_verified_email') existing_user_id = session.get('register_pending_user') existing_user = User.get(existing_user_id) if existing_user_id else None data = {'email': email} if existing_user: data.update(first_name=existing_user.first_name, last_name=existing_user.last_name, affiliation=existing_user.affiliation) return FormDefaults(**data)
def test_make_email_primary(db): user = User(first_name='Guinea', last_name='Pig', email='*****@*****.**') db.session.add(user) db.session.flush() with pytest.raises(ValueError): user.make_email_primary('*****@*****.**') user.secondary_emails = {'*****@*****.**', '*****@*****.**'} db.session.flush() user.make_email_primary('*****@*****.**') db.session.expire(user) assert user.email == '*****@*****.**' assert user.secondary_emails == {'*****@*****.**', '*****@*****.**'}
def undo_impersonate_user(): """Undo an admin impersonation login and revert to the old user""" from fossir.modules.auth import logger from fossir.modules.users import User try: entry = session.pop('login_as_orig_user') except KeyError: # The user probably already switched back from another tab return user = User.get_one(entry['user_id']) logger.info('Admin %r stopped impersonating user %r', user, session.user) session.user = user session.update(entry['session_data'])
def _make_idref(self, column, value, incoming=False, target_column=None): """Generate a ID reference. When generating an incoming ID reference, `column` must be a PK and point to the column that is referenced by FKs. In this case the `value` is ignored since it will be auto-generated by the db when the new row is isnerted. Otherwise, exactly one of `column` or `target_column` must be set. `column` is the column in the current table that has a FK referencing some other column. `target_column` is already the column that is referenced by a FK in the current table. """ assert (column is None) != (target_column is None) if value is None: return None if incoming: assert column.primary_key assert target_column is None fullname = '{}.{}'.format(column.table.fullname, column.name) type_ = 'idref_set' else: if target_column is not None: fullname = '{}.{}'.format(target_column.table.fullname, target_column.name) else: fk = _get_single_fk(column) fullname = fk.target_fullname target_column = fk.column if target_column is User.__table__.c.id and value is not None: type_ = 'userref' else: type_ = 'idref' uuid = self.id_map[fullname].setdefault(value, self._get_uuid()) if type_ == 'userref' and uuid not in self.users: user = User.get(value) self.users[uuid] = None if user.is_system else { 'first_name': user.first_name, 'last_name': user.last_name, 'title': user._title, 'affiliation': user.affiliation, 'phone': user.phone, 'address': user.address, 'email': user.email, 'all_emails': list(user.all_emails) } return type_, uuid
def _get_user_data(self): user_id = request.args.get('user') if user_id is None: return {} elif user_id.isdigit(): # existing fossir user user = User.find_first(id=user_id, is_deleted=False) user_data = {t.name: getattr(user, t.name, None) if user else '' for t in PersonalDataType} else: # non-fossir user data = GenericCache('pending_identities').get(user_id, {}) user_data = {t.name: data.get(t.name) for t in PersonalDataType} user_data['title'] = get_title_uuid(self.regform, user_data['title']) return user_data
def grant_admin(user_id): """Grants administration rights to a given user""" user = User.get(user_id) if user is None: print(cformat("%{red}This user does not exist")) return _print_user_info(user) if user.is_admin: print(cformat("%{yellow}This user already has administration rights")) return if click.confirm( cformat("%{yellow}Grant administration rights to this user?")): user.is_admin = True db.session.commit() print(cformat("%{green}Administration rights granted successfully"))
def revoke_admin(user_id): """Revokes administration rights from a given user""" user = User.get(user_id) if user is None: print(cformat("%{red}This user does not exist")) return _print_user_info(user) if not user.is_admin: print( cformat("%{yellow}This user does not have administration rights")) return if click.confirm( cformat("%{yellow}Revoke administration rights from this user?")): user.is_admin = False db.session.commit() print(cformat("%{green}Administration rights revoked successfully"))
def test_iter_acl(): user = User() user_p = MagicMock(principal=user, spec=['principal']) ipn = IPNetworkGroup() ipn_p = MagicMock(principal=ipn, spec=['principal']) local_group = GroupProxy(123, _group=MagicMock()) local_group_p = MagicMock(principal=local_group, spec=['principal']) remote_group = GroupProxy('foo', 'bar') remote_group_p = MagicMock(principal=remote_group, spec=['principal']) acl = [ ipn, user_p, remote_group, local_group_p, user, local_group, remote_group_p, ipn_p ] assert list(iter_acl(iter(acl))) == [ user_p, user, ipn, ipn_p, local_group_p, local_group, remote_group, remote_group_p ]
def create(grant_admin): """Creates a new user""" user_type = 'user' if not grant_admin else 'admin' while True: email = prompt_email() if email is None: return email = email.lower() if not User.find(User.all_emails.contains(email), ~User.is_deleted, ~User.is_pending).count(): break print(cformat('%{red}Email already exists')) first_name = click.prompt("First name").strip() last_name = click.prompt("Last name").strip() affiliation = click.prompt("Affiliation", '').strip() print() while True: username = click.prompt("Enter username").lower().strip() if not Identity.find(provider='fossir', identifier=username).count(): break print(cformat('%{red}Username already exists')) password = prompt_pass() if password is None: return identity = Identity(provider='fossir', identifier=username, password=password) user = create_user( email, { 'first_name': to_unicode(first_name), 'last_name': to_unicode(last_name), 'affiliation': to_unicode(affiliation) }, identity) user.is_admin = grant_admin _print_user_info(user) if click.confirm(cformat("%{yellow}Create the new {}?").format(user_type), default=True): db.session.add(user) db.session.commit() print( cformat("%{green}New {} created successfully with ID: %{green!}{}" ).format(user_type, user.id))
def _create_user(id_, first_name=u'Guinea', last_name=u'Pig', rb_admin=False, admin=False, email=None, groups=None, legacy=False): user = User.get(id_) if user: return user.as_avatar if legacy else user user = User() user.id = id_ user.first_name = first_name user.last_name = last_name user.email = email or u'{}@example.com'.format(id_) user.is_admin = admin user.local_groups = {g.group for g in (groups or ())} db.session.add(user) db.session.flush() if rb_admin: rb_settings.acls.add_principal('admin_principals', user) db.session.flush() return user.as_avatar if legacy else user
def _process(self): if session.user: return redirect(url_for_index()) handler = MultipassRegistrationHandler(self) if self.identity_info else LocalRegistrationHandler(self) verified_email, prevalidated = self._get_verified_email() if verified_email is not None: handler.email_verified(verified_email) if prevalidated: flash(_("You may change your email address after finishing the registration process."), 'info') else: flash(_('You have successfully validated your email address and can now proceeed with the ' 'registration.'), 'success') return redirect(url_for('.register', provider=self.provider_name)) form = handler.create_form() if not handler.moderate_registrations and not handler.must_verify_email: del form.comment # Check for pending users if we have verified emails pending = None if not handler.must_verify_email: pending = User.find_first(~User.is_deleted, User.is_pending, User.all_emails.contains(db.func.any(list(handler.get_all_emails(form))))) if form.validate_on_submit(): if handler.must_verify_email: return self._send_confirmation(form.email.data) elif handler.moderate_registrations: return self._create_registration_request(form, handler) else: return self._create_user(form, handler) elif not form.is_submitted() and pending: # If we have a pending user, populate empty fields with data from that user for field in form: value = getattr(pending, field.short_name, '') if value and not field.data: field.data = value if pending: flash(_("There is already some information in fossir that concerns you. " "We are going to link it automatically."), 'info') return WPAuth.render_template('register.html', form=form, local=(not self.identity_info), must_verify_email=handler.must_verify_email, widget_attrs=handler.widget_attrs, email_sent=session.pop('register_verification_email_sent', False), moderate_accounts=handler.moderate_registrations)
def __init__(self, source_file, category_id=0, create_users=None, verbose=False, force=False): self.source_file = source_file self.category_id = category_id self.create_users = create_users self.verbose = verbose self.force = force self.archive = tarfile.open(fileobj=source_file) self.data = yaml.load(self.archive.extractfile('data.yaml')) self.id_map = {} self.user_map = {} self.event_id = None self.system_user_id = User.get_system_user().id self.spec = self._load_spec() self.deferred_idrefs = defaultdict(set)