Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user to system #151

Merged
merged 3 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kiwiproject.champagne.dao;

import org.apache.commons.lang3.BooleanUtils;
import org.jdbi.v3.sqlobject.config.RegisterRowMapper;
import org.jdbi.v3.sqlobject.customizer.Bind;
import org.jdbi.v3.sqlobject.customizer.BindBean;
Expand All @@ -8,6 +9,7 @@
import org.jdbi.v3.sqlobject.statement.SqlUpdate;
import org.kiwiproject.champagne.dao.mappers.DeployableSystemForUserMapper;
import org.kiwiproject.champagne.dao.mappers.DeployableSystemMapper;
import org.kiwiproject.champagne.dao.mappers.SystemUserMapper;
import org.kiwiproject.champagne.model.DeployableSystem;

import java.util.List;
Expand All @@ -29,6 +31,10 @@ public interface DeployableSystemDao {
@SqlQuery("select count(*) from deployable_systems")
long countDeployableSystems();

@SqlQuery("select * from users_deployable_systems where deployable_system_id = :systemId")
@RegisterRowMapper(SystemUserMapper.class)
List<DeployableSystem.SystemUser> findUsersForSystem(@Bind("systemId") long systemId);

@SqlUpdate("update deployable_systems set dev_environment_id = :envId where id = :id")
int updateDevEnvironment(@Bind("id") long id, @Bind("envId") long envId);

Expand All @@ -42,5 +48,22 @@ public interface DeployableSystemDao {
boolean isUserAdminOfSystem(@Bind("userId") long userId, @Bind("systemId") long systemId);

@SqlQuery("select true from users_deployable_systems uds join users u on u.id = uds.user_id join deployable_systems ds on ds.id = uds.deployable_system_id where u.system_identifier = :userName and ds.id = :systemId")
boolean isUserBySystemIdentifierInSystem(@Bind("userName") String systemIdentifier, @Bind("systemId") long systemId);
Boolean isUserBySystemIdentifierInSystem(@Bind("userName") String systemIdentifier, @Bind("systemId") long systemId);

@SqlQuery("select true from users_deployable_systems where deployable_system_id = :systemId and user_id = :userId")
Boolean isUserInSystem(@Bind("userId") long userId, @Bind("systemId") long systemId);

default void insertOrUpdateSystemUser(long systemId, long userId, boolean isAdmin) {
if (BooleanUtils.isTrue(isUserInSystem(userId, systemId))) {
updateAdminStatusForUserInSystem(systemId, userId, isAdmin);
} else {
addUserToSystem(systemId, userId, isAdmin);
}
}

@SqlUpdate("update users_deployable_systems set system_admin = :admin where deployable_system_id = :systemId and user_id = :userId")
void updateAdminStatusForUserInSystem(@Bind("systemId") long systemId, @Bind("userId") long userId, @Bind("admin") boolean isAdmin);

@SqlUpdate("insert into users_deployable_systems (deployable_system_id, user_id, system_admin) values (:systemId, :userId, :admin)")
void addUserToSystem(@Bind("systemId") long systemId, @Bind("userId") long userId, @Bind("admin") boolean isAdmin);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.kiwiproject.champagne.dao.mappers;

import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import org.kiwiproject.champagne.model.DeployableSystem;

import java.sql.ResultSet;
import java.sql.SQLException;

public class SystemUserMapper implements RowMapper<DeployableSystem.SystemUser> {

@Override
public DeployableSystem.SystemUser map(ResultSet rs, StatementContext ctx) throws SQLException {
return DeployableSystem.SystemUser.builder()
.userId(rs.getLong("user_id"))
.admin(rs.getBoolean("system_admin"))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.kiwiproject.champagne.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Builder;
import lombok.ToString;
import lombok.Value;
import lombok.With;

import java.time.Instant;
import java.util.List;
import javax.validation.constraints.NotBlank;

@Builder
Expand All @@ -27,4 +30,19 @@ public class DeployableSystem {
*/
@With
boolean admin;

/**
* Transitive property that is the list of users assigned to this system and if they are an admin
*/
@With
List<SystemUser> users;

@Builder
@Value
@JsonIgnoreProperties(ignoreUnknown = true)
@ToString
public static class SystemUser {
Long userId;
boolean admin;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.kiwiproject.champagne.dao.DeployableSystemDao;
import org.kiwiproject.champagne.dao.UserDao;
import org.kiwiproject.champagne.model.DeployableSystem;
import org.kiwiproject.champagne.model.DeployableSystem.SystemUser;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorDao;
import org.kiwiproject.jaxrs.exception.JaxrsNotAuthorizedException;
import org.kiwiproject.spring.data.KiwiPage;
Expand Down Expand Up @@ -73,7 +74,10 @@ public Response listAllSystems(@QueryParam("pageNumber") @DefaultValue("1") int

var offset = zeroBasedOffset(pageNumber, pageSize);

var systems = deployableSystemDao.findPagedDeployableSystems(offset, pageSize);
var systems = deployableSystemDao.findPagedDeployableSystems(offset, pageSize).stream()
.map(system -> system.withUsers(deployableSystemDao.findUsersForSystem(system.getId())))
.toList();

var total = deployableSystemDao.countDeployableSystems();

var page = KiwiPage.of(pageNumber, pageSize, total, systems);
Expand Down Expand Up @@ -152,4 +156,14 @@ public Response deleteSystem(@PathParam("id") Long id) {

return Response.noContent().build();
}

@POST
@Path("/{id}/users")
@Timed
@ExceptionMetered
@RolesAllowed({ "admin" })
public Response addUsersToSystem(@PathParam("id") long systemId, List<SystemUser> users) {
users.forEach(user -> deployableSystemDao.insertOrUpdateSystemUser(systemId, user.getUserId(), user.isAdmin()));
return Response.accepted().build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kiwiproject.champagne.resource.filter;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.kiwiproject.champagne.dao.DeployableSystemDao;
import org.kiwiproject.champagne.model.DeployableSystemThreadLocal;
Expand All @@ -24,7 +25,7 @@ public void filter(ContainerRequestContext requestContext) {
if (StringUtils.isNotBlank(system)) {
var userName = requestContext.getSecurityContext().getUserPrincipal().getName();

if (deployableSystemDao.isUserBySystemIdentifierInSystem(userName, Long.parseLong(system))) {
if (BooleanUtils.isTrue(deployableSystemDao.isUserBySystemIdentifierInSystem(userName, Long.parseLong(system)))) {
DeployableSystemThreadLocal.setCurrentDeployableSystem(Long.valueOf(system));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,77 @@ void shouldReturnFalseWhenUserIsNotAnAdminForSystem() {
assertThat(result).isFalse();
}
}

@Nested
class FindUsersForSystem {

@Test
void shouldReturnListOfUsersForASystem() {
var userId = insertUserRecord(handle, "jdoe");
var deployableSystemId = insertDeployableSystem(handle, "system1");
insertUserToDeployableSystemLink(handle, userId, deployableSystemId, true);

var users = dao.findUsersForSystem(deployableSystemId);

assertThat(users).extracting("userId", "admin").contains(tuple(userId, true));
}
}

@Nested
class IsUserInSystem {

@Test
void shouldReturnTrueWhenUserIsAssignedToSystem() {
var userId = insertUserRecord(handle, "jdoe");
var deployableSystemId = insertDeployableSystem(handle, "system1");
insertUserToDeployableSystemLink(handle, userId, deployableSystemId, true);

var result = dao.isUserInSystem(userId, deployableSystemId);

assertThat(result).isTrue();
}

@Test
void shouldReturnNullWhenUserIsNotAssignedToSystem() {
var userId = insertUserRecord(handle, "jdoe");
var deployableSystemId = insertDeployableSystem(handle, "system1");
insertUserToDeployableSystemLink(handle, userId, deployableSystemId, true);

var result = dao.isUserInSystem(userId+1, deployableSystemId);

assertThat(result).isNull();
}
}

@Nested
class InsertOrUpdateSystemUser {

@Test
void shouldInsertNewUserSystemLinkWhenDoesNotExist() {
var userId = insertUserRecord(handle, "jdoe");
var deployableSystemId = insertDeployableSystem(handle, "system1");

assertThat(dao.isUserInSystem(userId, deployableSystemId)).isNull();

dao.insertOrUpdateSystemUser(deployableSystemId, userId, false);

assertThat(dao.isUserInSystem(userId, deployableSystemId)).isTrue();
}

@Test
void shouldUpdateUserSystemLinkWhenExists() {
var userId = insertUserRecord(handle, "jdoe");
var deployableSystemId = insertDeployableSystem(handle, "system1");
insertUserToDeployableSystemLink(handle, userId, deployableSystemId, true);

var systemUsers = dao.findUsersForSystem(deployableSystemId);
assertThat(systemUsers).extracting("userId", "admin").contains(tuple(userId, true));

dao.insertOrUpdateSystemUser(deployableSystemId, userId, false);

systemUsers = dao.findUsersForSystem(deployableSystemId);
assertThat(systemUsers).extracting("userId", "admin").contains(tuple(userId, false));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,14 @@ void shouldReturnPagedListOfDeployableSystems() {
.environmentPromotionOrder("2,3,4")
.build();

var systemUser = DeployableSystem.SystemUser.builder()
.userId(1L)
.admin(true)
.build();

when(DEPLOYABLE_SYSTEM_DAO.findPagedDeployableSystems(0, 10)).thenReturn(List.of(system));
when(DEPLOYABLE_SYSTEM_DAO.countDeployableSystems()).thenReturn(1L);
when(DEPLOYABLE_SYSTEM_DAO.findUsersForSystem(1L)).thenReturn(List.of(systemUser));

var token = generateJwt(true);
var response = RESOURCES.client()
Expand All @@ -151,6 +157,7 @@ void shouldReturnPagedListOfDeployableSystems() {

verify(DEPLOYABLE_SYSTEM_DAO).findPagedDeployableSystems(0, 10);
verify(DEPLOYABLE_SYSTEM_DAO).countDeployableSystems();
verify(DEPLOYABLE_SYSTEM_DAO).findUsersForSystem(1L);

verifyNoMoreInteractions(DEPLOYABLE_SYSTEM_DAO);
}
Expand All @@ -164,8 +171,14 @@ void shouldReturnPagedListOfReleasesWithDefaultPaging() {
.environmentPromotionOrder("2,3,4")
.build();

var systemUser = DeployableSystem.SystemUser.builder()
.userId(1L)
.admin(true)
.build();

when(DEPLOYABLE_SYSTEM_DAO.findPagedDeployableSystems(0, 25)).thenReturn(List.of(system));
when(DEPLOYABLE_SYSTEM_DAO.countDeployableSystems()).thenReturn(1L);
when(DEPLOYABLE_SYSTEM_DAO.findUsersForSystem(1L)).thenReturn(List.of(systemUser));

var token = generateJwt(true);
var response = RESOURCES.client()
Expand All @@ -184,6 +197,7 @@ void shouldReturnPagedListOfReleasesWithDefaultPaging() {

verify(DEPLOYABLE_SYSTEM_DAO).findPagedDeployableSystems(0, 25);
verify(DEPLOYABLE_SYSTEM_DAO).countDeployableSystems();
verify(DEPLOYABLE_SYSTEM_DAO).findUsersForSystem(1L);

verifyNoMoreInteractions(DEPLOYABLE_SYSTEM_DAO);
}
Expand Down Expand Up @@ -336,7 +350,7 @@ void shouldUpdateTheEnvOrderForTheGivenSystem() {
.target("/systems/2/order")
.request()
.cookie("sessionToken", token)
.put(json(List.of(1,2,3)));
.put(json(List.of(1, 2, 3)));

assertAcceptedResponse(response);

Expand All @@ -363,7 +377,7 @@ void shouldNotAuditActionWhenNothingChanges() {
.target("/systems/2/order")
.request()
.cookie("sessionToken", token)
.put(json(List.of(1,2,3)));
.put(json(List.of(1, 2, 3)));

assertAcceptedResponse(response);

Expand All @@ -389,7 +403,7 @@ void shouldThrow403WhenUserIsNotAdminInSystem() {
.target("/systems/2/order")
.request()
.cookie("sessionToken", token)
.put(json(List.of(1,2,3)));
.put(json(List.of(1, 2, 3)));

assertUnauthorizedResponse(response);

Expand All @@ -409,7 +423,7 @@ void shouldThrow403WhenUserIsNotFound() {
.target("/systems/2/order")
.request()
.cookie("sessionToken", token)
.put(json(List.of(1,2,3)));
.put(json(List.of(1, 2, 3)));

assertUnauthorizedResponse(response);

Expand Down Expand Up @@ -462,4 +476,27 @@ void shouldNotAuditIfDeleteDoesNotChangeDB() {
verifyNoInteractions(AUDIT_RECORD_DAO);
}
}

@Nested
class AddUsersToSystem {

@Test
void shouldAddGivenUsersToGivenSystem() {
var systemUser = DeployableSystem.SystemUser.builder()
.userId(2L)
.admin(false)
.build();

var token = generateJwt(true);
var response = RESOURCES.client().target("/systems/{id}/users")
.resolveTemplate("id", 1L)
.request()
.cookie("sessionToken", token)
.post(json(List.of(systemUser)));

assertAcceptedResponse(response);

verify(DEPLOYABLE_SYSTEM_DAO).insertOrUpdateSystemUser(1L, 2L, false);
}
}
}
Loading