Пример #1
0
def participant1_username(request, test_session, participant1_user):
    """A username for participant1_user"""
    from assembl.models import Username
    username = Username(user=participant1_user, username="******")
    test_session.add(username)
    test_session.flush()

    def fin():
        print "finalizer participant1_username"
        test_session.delete(username)
        test_session.flush()

    request.addfinalizer(fin)
    return username
Пример #2
0
def add_user(name,
             email,
             password,
             role,
             force=False,
             username=None,
             localrole=None,
             discussion=None,
             change_old_password=True,
             **kwargs):
    from assembl.models import Discussion, Username
    db = Discussion.default_db
    # refetch within transaction
    all_roles = {r.name: r for r in Role.default_db.query(Role).all()}
    user = None
    created_user = True
    if discussion and localrole:
        if isinstance(discussion, (str, unicode)):
            discussion_ob = db.query(Discussion).filter_by(
                slug=discussion).first()
            assert discussion_ob,\
                "Discussion with slug %s does not exist" % (discussion,)
        elif isinstance(discussion, int):
            discussion_ob = db.query(Discussion).get(discussion)
        discussion = discussion_ob
        assert discussion
    existing_email = db.query(EmailAccount).filter(
        EmailAccount.email_ci == email).first()
    assert force or not existing_email,\
        "User with email %s already exists" % (email,)
    if username:
        existing_username = db.query(Username).filter_by(
            username=username).first()
        assert force or not existing_username,\
            "User with username %s already exists" % (username,)
        assert not existing_email or not existing_username or \
            existing_username.user == existing_email.profile,\
            "Two different users already exist with "\
            "username %s and email %s." % (username, email)
    if existing_email:
        user = existing_email.profile
    elif username and existing_username:
        user = existing_username.user
    old_user = isinstance(user, User)
    if old_user:
        user.preferred_email = email
        user.name = name
        user.verified = True
        created_user = False
        if change_old_password:
            if password is None:
                user.password = None
            else:
                user.password_p = password
        if username:
            if user.username:
                user.username.username = username
            else:
                db.add(Username(username=username, user=user))
    else:
        if user:
            # Profile may have come from userless existing AgentProfile
            user = user.change_class(User,
                                     None,
                                     preferred_email=email,
                                     verified=True,
                                     creation_date=datetime.utcnow())
            if password is not None:
                user.password_p = password
        else:
            user = User(name=name,
                        preferred_email=email,
                        verified=True,
                        password=password,
                        creation_date=datetime.utcnow())
            db.add(user)
        if username:
            db.add(Username(username=username, user=user))
    for account in user.accounts:
        if isinstance(account, EmailAccount) and account.email_ci == email:
            account.verified = True
            account.preferred = True
            break
    else:
        account = EmailAccount(profile=user,
                               email=email,
                               preferred=True,
                               verified=True)
        db.add(account)
    if role:
        role = all_roles[role]
        ur = None
        if old_user:
            ur = db.query(UserRole).filter_by(user=user, role=role).first()
        if not ur:
            db.add(UserRole(user=user, role=role))
    created_localrole = False
    if localrole:
        localrole = all_roles[localrole]
        lur = None
        if old_user:
            lur = db.query(LocalUserRole).filter_by(user=user,
                                                    discussion=discussion,
                                                    role=localrole).first()
        if not lur:
            created_localrole = True
            db.add(
                LocalUserRole(user=user, role=localrole,
                              discussion=discussion))
    # Do this at login
    # if discussion:
    #     user.get_notification_subscriptions(discussion.id)
    db.flush()
    return (user, created_user, created_localrole)
Пример #3
0
def assembl_profile(request):
    session = AgentProfile.default_db
    localizer = request.localizer
    profile = get_profile(request)
    id_type = request.matchdict.get('type').strip()
    logged_in = authenticated_userid(request)
    save = request.method == 'POST'
    # if some other user
    if not profile or not logged_in or logged_in != profile.id:
        if save:
            raise HTTPUnauthorized()
        # Add permissions to view a profile?
        return render_to_response(
            'assembl:templates/view_profile.jinja2',
            dict(get_default_context(request),
                 profile=profile,
                 user=logged_in and session.query(User).get(logged_in)))

    confirm_email = request.params.get('confirm_email', None)
    if confirm_email:
        return HTTPTemporaryRedirect(location=request.route_url(
            'confirm_emailid_sent', email_account_id=int(confirm_email)))
    errors = []
    if save:
        user_id = profile.id
        redirect = False
        username = request.params.get('username', '').strip()
        if username and (
                profile.username is None
                or username != profile.username.username):
            # check if exists
            if session.query(Username).filter_by(username=username).count():
                errors.append(localizer.translate(_(
                    'The username %s is already used')) % (username,))
            else:
                old_username = profile.username
                if old_username is not None:
                    # free existing username
                    session.delete(old_username)
                    session.flush()
                # add new username
                session.add(Username(username=username, user=profile))

                if id_type == 'u':
                    redirect = True
        name = request.params.get('name', '').strip()
        if name:
            profile.name = name
        p1, p2 = (request.params.get('password1', '').strip(),
                  request.params.get('password2', '').strip())
        if p1 != p2:
            errors.append(localizer.translate(_(
                'The passwords are not identical')))
        elif p1:
            profile.password_p = p1
        add_email = request.params.get('add_email', '').strip()
        if add_email:
            if not is_email(add_email):
                return dict(get_default_context(request),
                            error=localizer.translate(_(
                                "This is not a valid email")))
            # No need to check presence since not validated yet
            email = EmailAccount(
                email=add_email, profile=profile)
            session.add(email)
        if redirect:
            return HTTPFound(location=request.route_url(
                'profile_user', type='u', identifier=username))
        profile = session.query(User).get(user_id)
    unverified_emails = [
        (ea, session.query(AbstractAgentAccount).filter_by(
            email_ci=ea.email_ci, verified=True).first())
        for ea in profile.email_accounts if not ea.verified]
    get_route = create_get_route(request)
    providers = get_provider_data(get_route)
    return render_to_response(
        'assembl:templates/profile.jinja2',
        dict(get_default_context(request),
             error='<br />'.join(errors),
             unverified_emails=unverified_emails,
             providers=providers,
             providers_json=json.dumps(providers),
             google_consumer_key=request.registry.settings.get(
                 'google.consumer_key', ''),
             the_user=profile,
             user=session.query(User).get(logged_in)))
Пример #4
0
def velruse_login_complete_view(request):
    # TODO: Write tests. Situations are a combinatorics of the folloing:
    # 1. User action:
    #     A. Social login
    #     B. Logged in, add social account
    #     C. Logged in, add email account (does not happen here)
    # 2. Is there an existing account with that email?
    #     A. No.
    #     B. The social account already exists
    #     C. A valid email account
    #     D. An invalid email account, sole account of profile
    #     E. An invalid email account, but profile has other accounts
    #     F. A social account from a different provider
    # 3. When we're logged in (1B, 1C), is the existing account
    #     on the logged in profile or another?
    # 4. If gmail account, is it an enterprise account?

    session = AgentProfile.default_db
    context = request.context
    now = datetime.utcnow()
    velruse_profile = context.profile
    discussion = None
    slug = request.session.get('discussion', None)
    if not slug:
        discussion = discussion_from_request(request)
        if discussion:
            slug = discussion.slug
    if slug and not discussion:
        discussion = session.query(Discussion).filter_by(slug=slug).first()
    next_view = handle_next_view(request, True)
    logged_in = authenticated_userid(request)
    if logged_in:
        logged_in = User.get(logged_in)
    base_profile = logged_in
    provider = get_identity_provider(request)
    # find or create IDP_Accounts
    idp_accounts = []
    new_idp_account = None
    velruse_accounts = velruse_profile['accounts']
    old_autoflush = session.autoflush
    # sqla mislikes creating accounts before profiles, so delay
    session.autoflush = False
    # Search for this social account
    for velruse_account in velruse_accounts:
        if 'userid' in velruse_account:
            idp_accounts.extend(
                session.query(IdentityProviderAccount).filter_by(
                    provider=provider,
                    domain=velruse_account['domain'],
                    userid=velruse_account['userid']).all())
        elif 'username' in velruse_account:
            idp_accounts.extend(
                session.query(IdentityProviderAccount).filter_by(
                    provider=provider,
                    domain=velruse_account['domain'],
                    username=velruse_account['username']).all())
        else:
            log.error("account needs username or email" + velruse_account)
            raise HTTPServerError("account needs username or userid")
    trusted_emails = set()
    if idp_accounts:
        for idp_account in idp_accounts:
            idp_account.profile_info_json = velruse_profile
        if len(idp_accounts) > 1:
            log.warn("multiple idp_accounts:" +
                     ','.join((a.id for a in idp_accounts)) + " for " +
                     velruse_accounts)
            # We will just the last one from the loop for now.
        trusted_emails.update([
            a.email for a in idp_accounts
            if a.provider.trust_emails and a.email
        ])
    else:
        # Create it if not found
        idp_class = IdentityProviderAccount
        for cls in idp_class.get_subclasses():
            if cls == idp_class:
                continue
            if cls.account_provider_name == provider.name:
                idp_class = cls
                break
        idp_account = idp_class(provider=provider,
                                profile_info_json=velruse_profile,
                                domain=velruse_account.get('domain'),
                                userid=velruse_account.get('userid'),
                                verified=True,
                                username=velruse_account.get('username'))
        idp_accounts.append(idp_account)
        new_idp_account = base_account = idp_account
        session.add(idp_account)
    for account in idp_accounts:
        if account.provider.trust_emails:
            profile = (velruse_profile if account == new_idp_account else
                       account.profile_info_json)
            email = profile.get('verifiedEmail', None)
            if email:
                if account == new_idp_account:
                    account.email = email
                trusted_emails.add(email)
            for email in profile.get('emails', ()):
                if isinstance(email, dict):
                    email = email.get('value', None)
                if isinstance(email, (str, unicode)) and email:
                    trusted_emails.add(email)
                    if account == new_idp_account and not account.email:
                        account.email = email
        # else we have created an email-less account. Treat accordingly.
    conflicting_profiles = {a.profile for a in idp_accounts if a.profile}
    # Are there other accounts/profiles than the ones we know?
    conflicting_accounts = set()
    for email in trusted_emails:
        other_accounts = session.query(AbstractAgentAccount).filter_by(
            email=email)
        for account in other_accounts:
            conflicting_accounts.add(account)
            if account.verified or len(account.profile.accounts) == 1:
                conflicting_profiles.add(account.profile)
    # choose best known profile for base_account
    # prefer profiles with verified users, then users, then oldest profiles
    profile_list = list(conflicting_profiles)
    profile_list.sort(key=lambda p: (not (isinstance(p, User) and p.verified),
                                     not isinstance(p, User), p.id))
    if new_idp_account and profile_list:
        base_profile = profile_list[0]
    elif not new_idp_account:
        # Take first appropriate. Should be the first, somehow not.
        for profile in profile_list:
            accounts = [a for a in idp_accounts if a.profile == profile]
            if accounts:
                base_account = accounts[0]
                break
        if not logged_in:
            base_profile = base_account.profile
    new_profile = None
    if new_idp_account:
        if not base_profile:
            # Create a new user
            base_profile = new_profile = User(name=velruse_profile.get(
                'displayName', ''),
                                              verified=True,
                                              creation_date=now)
            session.add(new_profile)
        # Upgrade a AgentProfile
        if not isinstance(base_profile, User):
            base_profile = base_profile.change_class(User, None, verified=True)
        new_idp_account.profile = base_profile
        base_profile.last_login = now
        base_profile.verified = True
        if not base_profile.name:
            base_profile.name = velruse_profile.get('displayName', None)
        # TODO (needs parsing)
        # base_profile.timezone=velruse_profile['utcOffset']
    # Now all accounts have a profile
    session.autoflush = old_autoflush
    session.flush()
    # Merge other profiles with the same (validated) email
    # TODO: Ask the user about doing this.
    conflicting_profiles.discard(base_profile)
    conflicting_accounts.discard(base_account)
    for conflicting_profile in conflicting_profiles:
        base_profile.merge(conflicting_profile)
        session.delete(conflicting_profile)

    # If base_profile is still an AgentProfile at this point
    # then it needs to be upgraded to a User
    if not isinstance(base_profile, User):
        base_profile = base_profile.change_class(User,
                                                 None,
                                                 verified=True,
                                                 last_login=now)
    # Set username
    if not base_profile.username:
        username = None
        usernames = set((a['preferredUsername'] for a in velruse_accounts
                         if 'preferredUsername' in a))
        for u in usernames:
            if not session.query(Username).filter_by(username=u).count():
                username = u
                break
        if username:
            session.add(Username(username=username, user=base_profile))
    # Create AgentStatusInDiscussion
    if new_profile and discussion:
        agent_status = AgentStatusInDiscussion(
            agent_profile=base_profile,
            discussion=discussion,
            user_created_on_this_discussion=True)
        session.add(agent_status)
    if maybe_auto_subscribe(base_profile, discussion):
        next_view = "/%s/" % (slug, )
    # Delete other (email) accounts
    if base_account.provider.trust_emails:
        for account in conflicting_accounts:
            # Merge may have been confusing
            session.expire(account)
            account = AbstractAgentAccount.get(account.id)
            if account.profile == base_profile:
                if account.email == base_account.email:
                    if isinstance(account, EmailAccount):
                        account.delete()
                        if account.verified and account.preferred:
                            base_account.preferred = True
                    elif isinstance(account, IdentityProviderAccount):
                        if account.provider_id == base_account.provider_id:
                            log.error("This should have been caught earlier")
                            account.delete()
                        else:
                            log.warning("Two accounts with same email," +
                                        "different provider: %d, %d" %
                                        (account.id, base_account.id))
            else:
                # If they're verified, they should have been merged.
                if account.verified:
                    log.error("account %d should not exist: " % (account.id, ))
                else:
                    other_profile = account.profile
                    account.delete()
                    session.flush()
                    session.expire(other_profile, ["accounts"])
                    if not len(other_profile.accounts):
                        log.warning("deleting profile %d" % other_profile.id)
                        other_profile.delete()
    session.expire(base_profile, ['accounts', 'email_accounts'])
    # create an email account for other emails.
    known_emails = {a.email for a in base_profile.accounts}
    for email in trusted_emails:
        if email not in known_emails:
            email = EmailAccount(email=email,
                                 profile=base_profile,
                                 verified=base_account.provider.trust_emails)
            session.add(email)

    session.flush()

    base_profile.last_login = now
    headers = remember(request, base_profile.id)
    request.response.headerlist.extend(headers)
    if discussion:
        request.session['discussion'] = discussion.slug
    return HTTPFound(location=next_view)
Пример #5
0
def add_user(name,
             email,
             password=None,
             role=R_SYSADMIN,
             force=False,
             username=None,
             localrole=None,
             discussion=None,
             change_old_password=True,
             send_password_change=False,
             resend_if_not_logged_in=False,
             text_message=None,
             html_message=None,
             sender_name=None,
             message_subject=None,
             db=None,
             request=None,
             flush=True,
             **kwargs):
    from assembl.models import Discussion, Username
    db = db or Discussion.default_db
    # refetch within transaction
    all_roles = {r.name: r for r in db.query(Role).all()}
    user = None
    created_user = True
    if discussion and not isinstance(discussion, Discussion):
        if isinstance(discussion, (str, unicode)):
            discussion = db.query(Discussion).filter_by(
                slug=discussion).first()
            assert discussion,\
                "Discussion with slug %s does not exist" % (discussion,)
        elif isinstance(discussion, int):
            discussion = db.query(Discussion).get(discussion)
            assert discussion

    existing_email = None
    if email:
        existing_email = db.query(EmailAccount).filter(
            EmailAccount.email_ci == email).first()
        assert force or not existing_email,\
            "User with email %s already exists" % (email,)

    if username:
        existing_username = db.query(Username).filter_by(
            username=username).first()
        assert force or not existing_username,\
            "User with username %s already exists" % (username,)
        assert not existing_email or not existing_username or \
            existing_username.user == existing_email.profile,\
            "Two different users already exist with "\
            "username %s and email %s." % (username, email)

    if existing_email:
        user = existing_email.profile
    elif username and existing_username:
        user = existing_username.user

    old_user = isinstance(user, User)
    if old_user:
        user.preferred_email = email
        user.name = name
        user.verified = True
        created_user = False
        if change_old_password:
            if password is None:
                user.password = None
            else:
                user.password_p = password
        if username:
            if user.username:
                user.username.username = username
            else:
                db.add(Username(username=username, user=user))
    else:
        if user:
            # Profile may have come from userless existing AgentProfile
            user = user.change_class(User,
                                     None,
                                     preferred_email=email,
                                     verified=True,
                                     creation_date=datetime.utcnow(),
                                     is_machine=kwargs.get(
                                         'is_machine', False))
            if password is not None:
                user.password_p = password
        else:
            user = User(name=name,
                        preferred_email=email,
                        verified=True,
                        password=password,
                        creation_date=datetime.utcnow(),
                        is_machine=kwargs.get('is_machine', False))
            db.add(user)
        if username:
            db.add(Username(username=username, user=user))

    for account in user.accounts:
        if isinstance(account, EmailAccount) and account.email_ci == email:
            account.verified = True
            account.preferred = True
            break
    else:
        account = EmailAccount(profile=user,
                               email=email,
                               preferred=True,
                               verified=True)
        db.add(account)

    if role:
        role = all_roles[role]
        ur = None
        if old_user:
            ur = db.query(UserRole).filter_by(user=user, role=role).first()
        if not ur:
            db.add(UserRole(user=user, role=role))

    created_localrole = False
    if localrole and discussion:
        localrole = all_roles[localrole]
        lur = None
        if old_user:
            lur = db.query(LocalUserRole).filter_by(user=user,
                                                    discussion=discussion,
                                                    role=localrole).first()
        if not lur:
            created_localrole = True
            db.add(
                LocalUserRole(user=user, role=localrole,
                              discussion=discussion))

    if flush:
        db.flush()

    status_in_discussion = None
    if resend_if_not_logged_in and discussion and not (created_user
                                                       or created_localrole):
        status_in_discussion = user.get_status_in_discussion(discussion.id)
    if send_password_change and (created_user or created_localrole or
                                 (resend_if_not_logged_in and
                                  (status_in_discussion is None
                                   or not status_in_discussion.first_visit))):
        from assembl.views.auth.views import send_change_password_email
        closer = None
        request = request or get_current_request()
        if not request:
            request, closer = _make_fake_request(discussion)

        send_change_password_email(request,
                                   user,
                                   email,
                                   subject=message_subject,
                                   text_body=text_message,
                                   html_body=html_message,
                                   discussion=discussion,
                                   sender_name=sender_name,
                                   welcome=True)
        if closer:
            closer()

    return (user, created_user, created_localrole)