def test_collaborator_added_email( self, pyramid_request, pyramid_config, monkeypatch): stub_user = pretend.stub( email='email', username='******', ) stub_submitter_user = pretend.stub( email='submiteremail', username='******' ) subject_renderer = pyramid_config.testing_add_renderer( 'email/collaborator-added.subject.txt' ) subject_renderer.string_response = 'Email Subject' body_renderer = pyramid_config.testing_add_renderer( 'email/collaborator-added.body.txt' ) body_renderer.string_response = 'Email Body' send_email = pretend.stub( delay=pretend.call_recorder(lambda *args, **kwargs: None) ) pyramid_request.task = pretend.call_recorder( lambda *args, **kwargs: send_email ) monkeypatch.setattr(email, 'send_email', send_email) result = email.send_collaborator_added_email( pyramid_request, user=stub_user, submitter=stub_submitter_user, project_name='test_project', role='Owner', email_recipients=[stub_user.email, stub_submitter_user.email] ) assert result == { 'username': stub_user.username, 'project': 'test_project', 'role': 'Owner', 'submitter': stub_submitter_user.username } subject_renderer.assert_() body_renderer.assert_(username=stub_user.username) body_renderer.assert_(project='test_project') body_renderer.assert_(role='Owner') body_renderer.assert_(submitter=stub_submitter_user.username) assert pyramid_request.task.calls == [ pretend.call(send_email), ] assert send_email.delay.calls == [ pretend.call( 'Email Body', 'Email Subject', bcc=[stub_user.email, stub_submitter_user.email], ), ]
def test_collaborator_added_email(self, pyramid_request, pyramid_config, monkeypatch): stub_user = pretend.stub(email="*****@*****.**", username="******", name="") stub_submitter_user = pretend.stub(email="*****@*****.**", username="******", name="") subject_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added.subject.txt") subject_renderer.string_response = "Email Subject" body_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added.body.txt") body_renderer.string_response = "Email Body" send_email = pretend.stub( delay=pretend.call_recorder(lambda *args, **kwargs: None)) pyramid_request.task = pretend.call_recorder( lambda *args, **kwargs: send_email) monkeypatch.setattr(email, "send_email", send_email) result = email.send_collaborator_added_email( pyramid_request, user=stub_user, submitter=stub_submitter_user, project_name="test_project", role="Owner", email_recipients=[stub_user, stub_submitter_user], ) assert result == { "username": stub_user.username, "project": "test_project", "role": "Owner", "submitter": stub_submitter_user.username, } subject_renderer.assert_() body_renderer.assert_(username=stub_user.username) body_renderer.assert_(project="test_project") body_renderer.assert_(role="Owner") body_renderer.assert_(submitter=stub_submitter_user.username) assert pyramid_request.task.calls == [ pretend.call(send_email), pretend.call(send_email), ] assert send_email.delay.calls == [ pretend.call("Email Subject", "Email Body", recipient="username <*****@*****.**>"), pretend.call( "Email Subject", "Email Body", recipient="submitterusername <*****@*****.**>", ), ]
def test_collaborator_added_email(self, pyramid_request, pyramid_config, monkeypatch): stub_user = pretend.stub( email='email', username='******', ) stub_submitter_user = pretend.stub(email='submiteremail', username='******') subject_renderer = pyramid_config.testing_add_renderer( 'email/collaborator-added.subject.txt') subject_renderer.string_response = 'Email Subject' body_renderer = pyramid_config.testing_add_renderer( 'email/collaborator-added.body.txt') body_renderer.string_response = 'Email Body' send_email = pretend.stub( delay=pretend.call_recorder(lambda *args, **kwargs: None)) pyramid_request.task = pretend.call_recorder( lambda *args, **kwargs: send_email) monkeypatch.setattr(email, 'send_email', send_email) result = email.send_collaborator_added_email( pyramid_request, user=stub_user, submitter=stub_submitter_user, project_name='test_project', role='Owner', email_recipients=[stub_user.email, stub_submitter_user.email]) assert result == { 'username': stub_user.username, 'project': 'test_project', 'role': 'Owner', 'submitter': stub_submitter_user.username } subject_renderer.assert_() body_renderer.assert_(username=stub_user.username) body_renderer.assert_(project='test_project') body_renderer.assert_(role='Owner') body_renderer.assert_(submitter=stub_submitter_user.username) assert pyramid_request.task.calls == [ pretend.call(send_email), ] assert send_email.delay.calls == [ pretend.call( 'Email Body', 'Email Subject', bcc=[stub_user.email, stub_submitter_user.email], ), ]
def manage_project_roles(project, request, _form_class=CreateRoleForm): user_service = request.find_service(IUserService, context=None) form = _form_class(request.POST, user_service=user_service) if request.method == "POST" and form.validate(): username = form.username.data role_name = form.role_name.data userid = user_service.find_userid(username) user = user_service.get_user(userid) if request.db.query( request.db.query(Role).filter( Role.user == user, Role.project == project, Role.role_name == role_name).exists()).scalar(): request.session.flash( f"User '{username}' already has {role_name} role for project", queue="error", ) elif user.primary_email is None or not user.primary_email.verified: request.session.flash( f"User '{username}' does not have a verified primary email " f"address and cannot be added as a {role_name} for project", queue="error", ) else: request.db.add( Role(user=user, project=project, role_name=form.role_name.data)) request.db.add( JournalEntry( name=project.name, action=f"add {role_name} {username}", submitted_by=request.user, submitted_from=request.remote_addr, )) project.record_event( tag="project:role:add", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "role_name": role_name, "target_user": username, }, ) owner_roles = (request.db.query(Role).join(Role.user).filter( Role.role_name == "Owner", Role.project == project)) owner_users = {owner.user for owner in owner_roles} # Don't send to the owner that added the new role owner_users.discard(request.user) # Don't send owners email to new user if they are now an owner owner_users.discard(user) send_collaborator_added_email( request, owner_users, user=user, submitter=request.user, project_name=project.name, role=form.role_name.data, ) send_added_as_collaborator_email( request, user, submitter=request.user, project_name=project.name, role=form.role_name.data, ) request.session.flash(f"Added collaborator '{form.username.data}'", queue="success") form = _form_class(user_service=user_service) roles = request.db.query(Role).join(User).filter( Role.project == project).all() # TODO: The following lines are a hack to handle multiple roles for a # single user and should be removed when fixing GH-2745 roles_by_user = defaultdict(list) for role in roles: roles_by_user[role.user.username].append(role) return {"project": project, "roles_by_user": roles_by_user, "form": form}
def test_collaborator_added_email_unverified(self, pyramid_request, pyramid_config, monkeypatch): stub_user = pretend.stub( username="******", name="", email="*****@*****.**", primary_email=pretend.stub(email="*****@*****.**", verified=False), ) stub_submitter_user = pretend.stub( username="******", name="", email="*****@*****.**", primary_email=pretend.stub(email="*****@*****.**", verified=True), ) subject_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/subject.txt") subject_renderer.string_response = "Email Subject" body_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/body.txt") body_renderer.string_response = "Email Body" html_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/body.html") html_renderer.string_response = "Email HTML Body" send_email = pretend.stub( delay=pretend.call_recorder(lambda *args, **kwargs: None)) pyramid_request.task = pretend.call_recorder( lambda *args, **kwargs: send_email) monkeypatch.setattr(email, "send_email", send_email) result = email.send_collaborator_added_email( pyramid_request, [stub_user, stub_submitter_user], user=stub_user, submitter=stub_submitter_user, project_name="test_project", role="Owner", ) assert result == { "username": stub_user.username, "project": "test_project", "role": "Owner", "submitter": stub_submitter_user.username, } subject_renderer.assert_() body_renderer.assert_(username=stub_user.username) body_renderer.assert_(project="test_project") body_renderer.assert_(role="Owner") body_renderer.assert_(submitter=stub_submitter_user.username) html_renderer.assert_(username=stub_user.username) html_renderer.assert_(project="test_project") html_renderer.assert_(role="Owner") html_renderer.assert_(submitter=stub_submitter_user.username) assert pyramid_request.task.calls == [pretend.call(send_email)] assert send_email.delay.calls == [ pretend.call( "submitterusername <*****@*****.**>", attr.asdict( EmailMessage( subject="Email Subject", body_text="Email Body", body_html=( "<html>\n<head></head>\n" "<body><p>Email HTML Body</p></body>\n</html>\n"), )), ) ]
def verify_project_role(request): token_service = request.find_service(ITokenService, name="email") user_service = request.find_service(IUserService, context=None) def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther(request.route_path("manage.projects")) try: token = request.params.get("token") data = token_service.loads(token) except TokenExpired: return _error(request._("Expired token: request a new project role invite")) except TokenInvalid: return _error(request._("Invalid token: request a new project role invite")) except TokenMissing: return _error(request._("Invalid token: no token supplied")) # Check whether this token is being used correctly if data.get("action") != "email-project-role-verify": return _error(request._("Invalid token: not a collaboration invitation token")) user = user_service.get_user(data.get("user_id")) if user != request.user: return _error(request._("Role invitation is not valid.")) project = ( request.db.query(Project).filter(Project.id == data.get("project_id")).one() ) desired_role = data.get("desired_role") role_invite = ( request.db.query(RoleInvitation) .filter(RoleInvitation.project == project) .filter(RoleInvitation.user == user) .one_or_none() ) if not role_invite: return _error(request._("Role invitation no longer exists.")) # Use the renderer to bring up a confirmation page # before adding as contributor if request.method == "GET": return { "project_name": project.name, "desired_role": desired_role, } elif request.method == "POST" and "decline" in request.POST: request.db.delete(role_invite) request.session.flash( request._( "Invitation for '${project_name}' is declined.", mapping={"project_name": project.name}, ), queue="success", ) return HTTPSeeOther(request.route_path("manage.projects")) request.db.add(Role(user=user, project=project, role_name=desired_role)) request.db.delete(role_invite) request.db.add( JournalEntry( name=project.name, action=f"accepted {desired_role} {user.username}", submitted_by=request.user, submitted_from=request.remote_addr, ) ) project.record_event( tag="project:role:accepted", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "role_name": desired_role, "target_user": user.username, }, ) user.record_event( tag="account:role:accepted", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "project_name": project.name, "role_name": desired_role, }, ) owner_roles = ( request.db.query(Role) .filter(Role.project == project) .filter(Role.role_name == "Owner") .all() ) owner_users = {owner.user for owner in owner_roles} # Don't send email to new user if they are now an owner owner_users.discard(user) submitter_user = user_service.get_user(data.get("submitter_id")) send_collaborator_added_email( request, owner_users, user=user, submitter=submitter_user, project_name=project.name, role=desired_role, ) send_added_as_collaborator_email( request, user, submitter=submitter_user, project_name=project.name, role=desired_role, ) request.session.flash( request._( "You are now ${role} of the '${project_name}' project.", mapping={"project_name": project.name, "role": desired_role}, ), queue="success", ) if desired_role == "Owner": return HTTPSeeOther( request.route_path("manage.project.roles", project_name=project.name) ) else: return HTTPSeeOther(request.route_path("packaging.project", name=project.name))
def manage_project_roles(project, request, _form_class=CreateRoleForm): user_service = request.find_service(IUserService, context=None) form = _form_class(request.POST, user_service=user_service) if request.method == "POST" and form.validate(): username = form.username.data role_name = form.role_name.data userid = user_service.find_userid(username) user = user_service.get_user(userid) if request.db.query( request.db.query(Role) .filter( Role.user == user, Role.project == project, Role.role_name == role_name ) .exists() ).scalar(): request.session.flash( f"User '{username}' already has {role_name} role for project", queue="error", ) elif user.primary_email is None or not user.primary_email.verified: request.session.flash( f"User '{username}' does not have a verified primary email " f"address and cannot be added as a {role_name} for project.", queue="error", ) else: request.db.add( Role(user=user, project=project, role_name=form.role_name.data) ) request.db.add( JournalEntry( name=project.name, action=f"add {role_name} {username}", submitted_by=request.user, submitted_from=request.remote_addr, ) ) owner_roles = ( request.db.query(Role) .join(Role.user) .filter(Role.role_name == "Owner", Role.project == project) ) owner_users = {owner.user for owner in owner_roles} # Don't send to the owner that added the new role owner_users.discard(request.user) # Don't send owners email to new user if they are now an owner owner_users.discard(user) send_collaborator_added_email( request, owner_users, user=user, submitter=request.user, project_name=project.name, role=form.role_name.data, ) send_added_as_collaborator_email( request, user, submitter=request.user, project_name=project.name, role=form.role_name.data, ) request.session.flash( f"Added collaborator '{form.username.data}'", queue="success" ) form = _form_class(user_service=user_service) roles = request.db.query(Role).join(User).filter(Role.project == project).all() # TODO: The following lines are a hack to handle multiple roles for a # single user and should be removed when fixing GH-2745 roles_by_user = defaultdict(list) for role in roles: roles_by_user[role.user.username].append(role) return {"project": project, "roles_by_user": roles_by_user, "form": form}
def manage_project_roles(project, request, _form_class=CreateRoleForm): user_service = request.find_service(IUserService, context=None) form = _form_class(request.POST, user_service=user_service) if request.method == "POST" and form.validate(): username = form.username.data role_name = form.role_name.data userid = user_service.find_userid(username) user = user_service.get_user(userid) if (request.db.query( request.db.query(Role).filter( Role.user == user, Role.project == project, Role.role_name == role_name, ) .exists()).scalar()): request.session.flash( f"User '{username}' already has {role_name} role for project", queue="error" ) else: request.db.add( Role(user=user, project=project, role_name=form.role_name.data) ) request.db.add( JournalEntry( name=project.name, action=f"add {role_name} {username}", submitted_by=request.user, submitted_from=request.remote_addr, ), ) owners = ( request.db.query(Role) .join(Role.user) .filter(Role.role_name == 'Owner', Role.project == project) ) owner_emails = [owner.user.email for owner in owners] owner_emails.remove(request.user.email) send_collaborator_added_email( request, user, request.user, project.name, form.role_name.data, owner_emails ) send_added_as_collaborator_email( request, request.user, project.name, form.role_name.data, user.email ) request.session.flash( f"Added collaborator '{form.username.data}'", queue="success" ) form = _form_class(user_service=user_service) roles = ( request.db.query(Role) .join(User) .filter(Role.project == project) .all() ) # TODO: The following lines are a hack to handle multiple roles for a # single user and should be removed when fixing GH-2745 roles_by_user = defaultdict(list) for role in roles: roles_by_user[role.user.username].append(role) return { "project": project, "roles_by_user": roles_by_user, "form": form, }
def test_collaborator_added_email_unverified( self, pyramid_request, pyramid_config, monkeypatch ): stub_user = pretend.stub( username="******", name="", email="*****@*****.**", primary_email=pretend.stub(email="*****@*****.**", verified=False), ) stub_submitter_user = pretend.stub( username="******", name="", email="*****@*****.**", primary_email=pretend.stub( email="*****@*****.**", verified=True ), ) subject_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/subject.txt" ) subject_renderer.string_response = "Email Subject" body_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/body.txt" ) body_renderer.string_response = "Email Body" html_renderer = pyramid_config.testing_add_renderer( "email/collaborator-added/body.html" ) html_renderer.string_response = "Email HTML Body" send_email = pretend.stub( delay=pretend.call_recorder(lambda *args, **kwargs: None) ) pyramid_request.task = pretend.call_recorder(lambda *args, **kwargs: send_email) monkeypatch.setattr(email, "send_email", send_email) result = email.send_collaborator_added_email( pyramid_request, [stub_user, stub_submitter_user], user=stub_user, submitter=stub_submitter_user, project_name="test_project", role="Owner", ) assert result == { "username": stub_user.username, "project": "test_project", "role": "Owner", "submitter": stub_submitter_user.username, } subject_renderer.assert_() body_renderer.assert_(username=stub_user.username) body_renderer.assert_(project="test_project") body_renderer.assert_(role="Owner") body_renderer.assert_(submitter=stub_submitter_user.username) html_renderer.assert_(username=stub_user.username) html_renderer.assert_(project="test_project") html_renderer.assert_(role="Owner") html_renderer.assert_(submitter=stub_submitter_user.username) assert pyramid_request.task.calls == [pretend.call(send_email)] assert send_email.delay.calls == [ pretend.call( "submitterusername <*****@*****.**>", attr.asdict( EmailMessage( subject="Email Subject", body_text="Email Body", body_html=( "<html>\n<head></head>\n" "<body><p>Email HTML Body</p></body>\n</html>\n" ), ) ), ) ]
def manage_project_roles(project, request, _form_class=CreateRoleForm): user_service = request.find_service(IUserService, context=None) form = _form_class(request.POST, user_service=user_service) if request.method == "POST" and form.validate(): username = form.username.data role_name = form.role_name.data userid = user_service.find_userid(username) user = user_service.get_user(userid) if (request.db.query( request.db.query(Role).filter( Role.user == user, Role.project == project, Role.role_name == role_name, ).exists()).scalar()): request.session.flash( f"User '{username}' already has {role_name} role for project", queue="error") else: request.db.add( Role(user=user, project=project, role_name=form.role_name.data)) request.db.add( JournalEntry( name=project.name, action=f"add {role_name} {username}", submitted_by=request.user, submitted_from=request.remote_addr, ), ) owners = (request.db.query(Role).join(Role.user).filter( Role.role_name == 'Owner', Role.project == project)) owner_emails = [owner.user.email for owner in owners] owner_emails.remove(request.user.email) send_collaborator_added_email(request, user, request.user, project.name, form.role_name.data, owner_emails) send_added_as_collaborator_email(request, request.user, project.name, form.role_name.data, user.email) request.session.flash(f"Added collaborator '{form.username.data}'", queue="success") form = _form_class(user_service=user_service) roles = (request.db.query(Role).join(User).filter( Role.project == project).all()) # TODO: The following lines are a hack to handle multiple roles for a # single user and should be removed when fixing GH-2745 roles_by_user = defaultdict(list) for role in roles: roles_by_user[role.user.username].append(role) return { "project": project, "roles_by_user": roles_by_user, "form": form, }