mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-14 11:27:58 +00:00
Merge pull request #966 from open-metadata/issue965
Fixed 965 Add versioning API support for Team Entity
This commit is contained in:
commit
328db526a6
@ -247,13 +247,13 @@ public interface CollectionDAO {
|
|||||||
//
|
//
|
||||||
@SqlQuery("SELECT toId, toEntity FROM entity_relationship " +
|
@SqlQuery("SELECT toId, toEntity FROM entity_relationship " +
|
||||||
"WHERE fromId = :fromId AND relation = :relation " +
|
"WHERE fromId = :fromId AND relation = :relation " +
|
||||||
"ORDER BY fromId")
|
"ORDER BY toId")
|
||||||
@RegisterRowMapper(ToEntityReferenceMapper.class)
|
@RegisterRowMapper(ToEntityReferenceMapper.class)
|
||||||
List<EntityReference> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation);
|
List<EntityReference> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation);
|
||||||
|
|
||||||
@SqlQuery("SELECT toId FROM entity_relationship " +
|
@SqlQuery("SELECT toId FROM entity_relationship " +
|
||||||
"WHERE fromId = :fromId AND relation = :relation AND toEntity = :toEntity " +
|
"WHERE fromId = :fromId AND relation = :relation AND toEntity = :toEntity " +
|
||||||
"ORDER BY fromId")
|
"ORDER BY toId")
|
||||||
List<String> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation,
|
List<String> findTo(@Bind("fromId") String fromId, @Bind("relation") int relation,
|
||||||
@Bind("toEntity") String toEntity);
|
@Bind("toEntity") String toEntity);
|
||||||
|
|
||||||
|
@ -31,9 +31,11 @@ import org.openmetadata.catalog.util.EntityUtil.Fields;
|
|||||||
import org.openmetadata.catalog.util.JsonUtils;
|
import org.openmetadata.catalog.util.JsonUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -194,6 +196,9 @@ public class TeamRepository extends EntityRepository<Team> {
|
|||||||
@Override
|
@Override
|
||||||
public Date getUpdatedAt() { return entity.getUpdatedAt(); }
|
public Date getUpdatedAt() { return entity.getUpdatedAt(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI getHref() { return entity.getHref(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityReference getEntityReference() {
|
public EntityReference getEntityReference() {
|
||||||
return new EntityReference().withId(getId()).withName(getFullyQualifiedName()).withDescription(getDescription())
|
return new EntityReference().withId(getId()).withName(getFullyQualifiedName()).withDescription(getDescription())
|
||||||
@ -226,6 +231,9 @@ public class TeamRepository extends EntityRepository<Team> {
|
|||||||
entity.setChangeDescription(changeDescription);
|
entity.setChangeDescription(changeDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChangeDescription getChangeDescription() { return entity.getChangeDescription(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTags(List<TagLabel> tags) { }
|
public void setTags(List<TagLabel> tags) { }
|
||||||
}
|
}
|
||||||
@ -244,18 +252,26 @@ public class TeamRepository extends EntityRepository<Team> {
|
|||||||
if (updated.getEntity().getDeleted() != original.getEntity().getDeleted()) {
|
if (updated.getEntity().getDeleted() != original.getEntity().getDeleted()) {
|
||||||
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute("Team", "deleted"));
|
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute("Team", "deleted"));
|
||||||
}
|
}
|
||||||
|
recordChange("profile", original.getEntity().getProfile(), updated.getEntity().getProfile());
|
||||||
updateUsers(original.getEntity(), updated.getEntity());
|
updateUsers(original.getEntity(), updated.getEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUsers(Team origTeam, Team updatedTeam) {
|
private void updateUsers(Team origTeam, Team updatedTeam) {
|
||||||
|
List<EntityReference> origUsers = Optional.ofNullable(origTeam.getUsers()).orElse(Collections.emptyList());
|
||||||
|
List<EntityReference> updatedUsers = Optional.ofNullable(updatedTeam.getUsers()).orElse(Collections.emptyList());
|
||||||
|
|
||||||
// Remove users from original and add users from updated
|
// Remove users from original and add users from updated
|
||||||
dao.relationshipDAO().deleteFrom(origTeam.getId().toString(), Relationship.CONTAINS.ordinal(), "user");
|
dao.relationshipDAO().deleteFrom(origTeam.getId().toString(), Relationship.CONTAINS.ordinal(), "user");
|
||||||
|
// Add relationships
|
||||||
for (EntityReference user : Optional.ofNullable(updatedTeam.getUsers()).orElse(Collections.emptyList())) {
|
for (EntityReference user : updatedUsers) {
|
||||||
dao.relationshipDAO().insert(updatedTeam.getId().toString(), user.getId().toString(),
|
dao.relationshipDAO().insert(updatedTeam.getId().toString(), user.getId().toString(),
|
||||||
"team", "user", Relationship.CONTAINS.ordinal());
|
"team", "user", Relationship.CONTAINS.ordinal());
|
||||||
}
|
}
|
||||||
recordChange("users", origTeam.getUsers(), updatedTeam.getUsers());
|
|
||||||
|
// Sort by user Id as string (as done in the database)
|
||||||
|
updatedUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
|
origUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
|
recordChange("users", origUsers.isEmpty() ? null : origUsers, updatedUsers.isEmpty() ? null : updatedUsers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,6 @@ public class UserRepository extends EntityRepository<User> {
|
|||||||
private void assignTeams(User user, List<EntityReference> teams) {
|
private void assignTeams(User user, List<EntityReference> teams) {
|
||||||
// Query - add team to the user
|
// Query - add team to the user
|
||||||
teams = Optional.ofNullable(teams).orElse(Collections.emptyList());
|
teams = Optional.ofNullable(teams).orElse(Collections.emptyList());
|
||||||
teams.sort(Comparator.comparing(EntityReference::getId)); // Sort team order to the query order
|
|
||||||
for (EntityReference team : teams) {
|
for (EntityReference team : teams) {
|
||||||
dao.relationshipDAO().insert(team.getId().toString(), user.getId().toString(),
|
dao.relationshipDAO().insert(team.getId().toString(), user.getId().toString(),
|
||||||
"team", "user", CONTAINS.ordinal());
|
"team", "user", CONTAINS.ordinal());
|
||||||
@ -301,19 +300,13 @@ public class UserRepository extends EntityRepository<User> {
|
|||||||
dao.relationshipDAO().deleteTo(origUser.getId().toString(), CONTAINS.ordinal(), "team");
|
dao.relationshipDAO().deleteTo(origUser.getId().toString(), CONTAINS.ordinal(), "team");
|
||||||
assignTeams(updatedUser, updatedUser.getTeams());
|
assignTeams(updatedUser, updatedUser.getTeams());
|
||||||
|
|
||||||
List<EntityReference> origTeams = origUser.getTeams();
|
List<EntityReference> origTeams = Optional.ofNullable(origUser.getTeams()).orElse(Collections.emptyList());
|
||||||
List<EntityReference> updatedTeams = updatedUser.getTeams();
|
List<EntityReference> updatedTeams = Optional.ofNullable(updatedUser.getTeams()).orElse(Collections.emptyList());
|
||||||
if (origTeams == null || origTeams.isEmpty()) {
|
|
||||||
origTeams = null;
|
// Sort by team Id as string (as done in the database)
|
||||||
} else {
|
origTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
origTeams.sort(Comparator.comparing(EntityReference::getId));
|
updatedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
}
|
recordChange("teams", origTeams.isEmpty() ? null : origTeams, updatedTeams.isEmpty() ? null : updatedTeams);
|
||||||
if (updatedTeams == null || updatedTeams.isEmpty()) {
|
|
||||||
updatedTeams = null;
|
|
||||||
} else {
|
|
||||||
updatedTeams.sort(Comparator.comparing(EntityReference::getId));
|
|
||||||
}
|
|
||||||
recordChange("teams", origTeams, updatedTeams);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import org.openmetadata.catalog.jdbi3.TeamRepository;
|
|||||||
import org.openmetadata.catalog.resources.Collection;
|
import org.openmetadata.catalog.resources.Collection;
|
||||||
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
import org.openmetadata.catalog.security.CatalogAuthorizer;
|
||||||
import org.openmetadata.catalog.security.SecurityUtil;
|
import org.openmetadata.catalog.security.SecurityUtil;
|
||||||
|
import org.openmetadata.catalog.type.EntityHistory;
|
||||||
import org.openmetadata.catalog.type.EntityReference;
|
import org.openmetadata.catalog.type.EntityReference;
|
||||||
import org.openmetadata.catalog.util.EntityUtil;
|
import org.openmetadata.catalog.util.EntityUtil;
|
||||||
import org.openmetadata.catalog.util.RestUtil;
|
import org.openmetadata.catalog.util.RestUtil;
|
||||||
@ -48,6 +49,7 @@ import javax.ws.rs.DELETE;
|
|||||||
import javax.ws.rs.DefaultValue;
|
import javax.ws.rs.DefaultValue;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.PathParam;
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
@ -106,7 +108,7 @@ public class TeamResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String FIELDS = "profile,users,owns";
|
public static final String FIELDS = "profile,users,owns";
|
||||||
public static final List<String> FIELD_LIST = Arrays.asList(FIELDS.replaceAll(" ", "")
|
public static final List<String> FIELD_LIST = Arrays.asList(FIELDS.replaceAll(" ", "")
|
||||||
.split(","));
|
.split(","));
|
||||||
@GET
|
@GET
|
||||||
@ -150,6 +152,22 @@ public class TeamResource {
|
|||||||
return teams;
|
return teams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}/versions")
|
||||||
|
@Operation(summary = "List team versions", tags = "teams",
|
||||||
|
description = "Get a list of all the versions of a team identified by `id`",
|
||||||
|
responses = {@ApiResponse(responseCode = "200", description = "List of team versions",
|
||||||
|
content = @Content(mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = EntityHistory.class)))
|
||||||
|
})
|
||||||
|
public EntityHistory listVersions(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@Parameter(description = "team Id", schema = @Schema(type = "string"))
|
||||||
|
@PathParam("id") String id)
|
||||||
|
throws IOException, ParseException, GeneralSecurityException {
|
||||||
|
return dao.listVersions(id);
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Valid
|
@Valid
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
@ -192,6 +210,27 @@ public class TeamResource {
|
|||||||
return addHref(uriInfo, dao.getByName(name, fields));
|
return addHref(uriInfo, dao.getByName(name, fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}/versions/{version}")
|
||||||
|
@Operation(summary = "Get a version of the team", tags = "teams",
|
||||||
|
description = "Get a version of the team by given `id`",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "team",
|
||||||
|
content = @Content(mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = Team.class))),
|
||||||
|
@ApiResponse(responseCode = "404", description = "Team for instance {id} and version {version} is " +
|
||||||
|
"not found")
|
||||||
|
})
|
||||||
|
public Team getVersion(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@Parameter(description = "Team Id", schema = @Schema(type = "string"))
|
||||||
|
@PathParam("id") String id,
|
||||||
|
@Parameter(description = "Team version number in the form `major`.`minor`",
|
||||||
|
schema = @Schema(type = "string", example = "0.1 or 1.1"))
|
||||||
|
@PathParam("version") String version) throws IOException, ParseException {
|
||||||
|
return dao.getVersion(id, version);
|
||||||
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Operation(summary = "Create a team", tags = "teams",
|
@Operation(summary = "Create a team", tags = "teams",
|
||||||
description = "Create a new team.",
|
description = "Create a new team.",
|
||||||
@ -205,15 +244,30 @@ public class TeamResource {
|
|||||||
@Context SecurityContext securityContext,
|
@Context SecurityContext securityContext,
|
||||||
@Valid CreateTeam ct) throws IOException, ParseException {
|
@Valid CreateTeam ct) throws IOException, ParseException {
|
||||||
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
|
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
|
||||||
Team team = new Team().withId(UUID.randomUUID()).withName(ct.getName()).withDescription(ct.getDescription())
|
Team team = getTeam(ct, securityContext);
|
||||||
.withDisplayName(ct.getDisplayName()).withProfile(ct.getProfile())
|
|
||||||
.withUpdatedBy(securityContext.getUserPrincipal().getName())
|
|
||||||
.withUpdatedAt(new Date())
|
|
||||||
.withUsers(dao.getUsers(ct.getUsers()));
|
|
||||||
addHref(uriInfo, dao.create(team));
|
addHref(uriInfo, dao.create(team));
|
||||||
return Response.created(team.getHref()).entity(team).build();
|
return Response.created(team.getHref()).entity(team).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Operation(summary = "Create or Update a team", tags = "teams",
|
||||||
|
description = "Create or Update a team.",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "The team ",
|
||||||
|
content = @Content(mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = CreateTeam.class))),
|
||||||
|
@ApiResponse(responseCode = "400", description = "Bad request")
|
||||||
|
})
|
||||||
|
public Response createOrUpdateTeam(@Context UriInfo uriInfo,
|
||||||
|
@Context SecurityContext securityContext,
|
||||||
|
@Valid CreateTeam ct) throws IOException, ParseException {
|
||||||
|
SecurityUtil.checkAdminOrBotRole(authorizer, securityContext);
|
||||||
|
Team team = getTeam(ct, securityContext);
|
||||||
|
RestUtil.PutResponse<Team> response = dao.createOrUpdate(team);
|
||||||
|
team = addHref(uriInfo, response.getEntity());
|
||||||
|
return Response.status(response.getStatus()).entity(team).build();
|
||||||
|
}
|
||||||
|
|
||||||
@PATCH
|
@PATCH
|
||||||
@Valid
|
@Valid
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
@ -252,4 +306,12 @@ public class TeamResource {
|
|||||||
dao.delete(UUID.fromString(id));
|
dao.delete(UUID.fromString(id));
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Team getTeam(CreateTeam ct, SecurityContext securityContext) throws IOException {
|
||||||
|
return new Team().withId(UUID.randomUUID()).withName(ct.getName()).withDescription(ct.getDescription())
|
||||||
|
.withDisplayName(ct.getDisplayName()).withProfile(ct.getProfile())
|
||||||
|
.withUpdatedBy(securityContext.getUserPrincipal().getName())
|
||||||
|
.withUpdatedAt(new Date())
|
||||||
|
.withUsers(dao.getUsers(ct.getUsers()));
|
||||||
|
}
|
||||||
}
|
}
|
@ -176,7 +176,6 @@ public class UserResource {
|
|||||||
return dao.listVersions(id);
|
return dao.listVersions(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Valid
|
@Valid
|
||||||
@Path("/{id}")
|
@Path("/{id}")
|
||||||
|
@ -55,7 +55,8 @@
|
|||||||
},
|
},
|
||||||
"users" : {
|
"users" : {
|
||||||
"description": "Users that are part of the team.",
|
"description": "Users that are part of the team.",
|
||||||
"$ref": "../../type/entityReference.json#/definitions/entityReferenceList"
|
"$ref": "../../type/entityReference.json#/definitions/entityReferenceList",
|
||||||
|
"default": null
|
||||||
},
|
},
|
||||||
"owns" : {
|
"owns" : {
|
||||||
"description": "List of entities owned by the team.",
|
"description": "List of entities owned by the team.",
|
||||||
|
@ -26,15 +26,18 @@ import org.openmetadata.catalog.api.teams.CreateTeam;
|
|||||||
import org.openmetadata.catalog.entity.teams.Team;
|
import org.openmetadata.catalog.entity.teams.Team;
|
||||||
import org.openmetadata.catalog.entity.teams.User;
|
import org.openmetadata.catalog.entity.teams.User;
|
||||||
import org.openmetadata.catalog.exception.CatalogExceptionMessage;
|
import org.openmetadata.catalog.exception.CatalogExceptionMessage;
|
||||||
|
import org.openmetadata.catalog.jdbi3.TeamRepository.TeamEntityInterface;
|
||||||
import org.openmetadata.catalog.jdbi3.UserRepository.UserEntityInterface;
|
import org.openmetadata.catalog.jdbi3.UserRepository.UserEntityInterface;
|
||||||
|
import org.openmetadata.catalog.resources.EntityResourceTest;
|
||||||
import org.openmetadata.catalog.resources.databases.TableResourceTest;
|
import org.openmetadata.catalog.resources.databases.TableResourceTest;
|
||||||
import org.openmetadata.catalog.resources.teams.TeamResource.TeamList;
|
import org.openmetadata.catalog.resources.teams.TeamResource.TeamList;
|
||||||
|
import org.openmetadata.catalog.type.ChangeDescription;
|
||||||
import org.openmetadata.catalog.type.EntityReference;
|
import org.openmetadata.catalog.type.EntityReference;
|
||||||
import org.openmetadata.catalog.type.ImageList;
|
import org.openmetadata.catalog.type.ImageList;
|
||||||
import org.openmetadata.catalog.type.Profile;
|
import org.openmetadata.catalog.type.Profile;
|
||||||
|
import org.openmetadata.catalog.util.EntityInterface;
|
||||||
import org.openmetadata.catalog.util.JsonUtils;
|
import org.openmetadata.catalog.util.JsonUtils;
|
||||||
import org.openmetadata.catalog.util.TestUtils;
|
import org.openmetadata.catalog.util.TestUtils;
|
||||||
import org.openmetadata.catalog.util.TestUtils.UpdateType;
|
|
||||||
import org.openmetadata.common.utils.JsonSchemaUtil;
|
import org.openmetadata.common.utils.JsonSchemaUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -45,6 +48,7 @@ import java.net.URI;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -62,17 +66,20 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||||||
import static org.openmetadata.catalog.exception.CatalogExceptionMessage.entityNotFound;
|
import static org.openmetadata.catalog.exception.CatalogExceptionMessage.entityNotFound;
|
||||||
import static org.openmetadata.catalog.resources.teams.UserResourceTest.createUser;
|
import static org.openmetadata.catalog.resources.teams.UserResourceTest.createUser;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.UpdateType.MINOR_UPDATE;
|
import static org.openmetadata.catalog.util.TestUtils.UpdateType.MINOR_UPDATE;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.UpdateType.NO_CHANGE;
|
|
||||||
import static org.openmetadata.catalog.util.TestUtils.adminAuthHeaders;
|
import static org.openmetadata.catalog.util.TestUtils.adminAuthHeaders;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.assertEntityPagination;
|
import static org.openmetadata.catalog.util.TestUtils.assertEntityPagination;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
|
import static org.openmetadata.catalog.util.TestUtils.assertResponse;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.authHeaders;
|
import static org.openmetadata.catalog.util.TestUtils.authHeaders;
|
||||||
import static org.openmetadata.catalog.util.TestUtils.validateEntityReference;
|
import static org.openmetadata.catalog.util.TestUtils.validateEntityReference;
|
||||||
|
|
||||||
public class TeamResourceTest extends CatalogApplicationTest {
|
public class TeamResourceTest extends EntityResourceTest<Team> {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TeamResourceTest.class);
|
private static final Logger LOG = LoggerFactory.getLogger(TeamResourceTest.class);
|
||||||
final Profile PROFILE = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
|
final Profile PROFILE = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
|
||||||
|
|
||||||
|
public TeamResourceTest() {
|
||||||
|
super(Team.class, "teams", TeamResource.FIELDS);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void post_teamWithLongName_400_badRequest(TestInfo test) {
|
public void post_teamWithLongName_400_badRequest(TestInfo test) {
|
||||||
// Create team with mandatory name field empty
|
// Create team with mandatory name field empty
|
||||||
@ -102,19 +109,19 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
public void post_validTeams_as_admin_200_OK(TestInfo test) throws HttpResponseException {
|
public void post_validTeams_as_admin_200_OK(TestInfo test) throws HttpResponseException {
|
||||||
// Create team with different optional fields
|
// Create team with different optional fields
|
||||||
CreateTeam create = create(test, 1);
|
CreateTeam create = create(test, 1);
|
||||||
createAndCheckTeam(create, adminAuthHeaders());
|
createAndCheckEntity(create, adminAuthHeaders());
|
||||||
|
|
||||||
create = create(test, 2).withDisplayName("displayName");
|
create = create(test, 2).withDisplayName("displayName");
|
||||||
createAndCheckTeam(create, adminAuthHeaders());
|
createAndCheckEntity(create, adminAuthHeaders());
|
||||||
|
|
||||||
create = create(test, 3).withDescription("description");
|
create = create(test, 3).withDescription("description");
|
||||||
createAndCheckTeam(create, adminAuthHeaders());
|
createAndCheckEntity(create, adminAuthHeaders());
|
||||||
|
|
||||||
create = create(test, 4).withProfile(PROFILE);
|
create = create(test, 4).withProfile(PROFILE);
|
||||||
createAndCheckTeam(create, adminAuthHeaders());
|
createAndCheckEntity(create, adminAuthHeaders());
|
||||||
|
|
||||||
create = create(test, 5).withDisplayName("displayName").withDescription("description").withProfile(PROFILE);
|
create = create(test, 5).withDisplayName("displayName").withDescription("description").withProfile(PROFILE);
|
||||||
createAndCheckTeam(create, adminAuthHeaders());
|
createAndCheckEntity(create, adminAuthHeaders());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -122,7 +129,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
// Create team with different optional fields
|
// Create team with different optional fields
|
||||||
Map<String, String> authHeaders = authHeaders("test@open-metadata.org");
|
Map<String, String> authHeaders = authHeaders("test@open-metadata.org");
|
||||||
CreateTeam create = create(test, 1);
|
CreateTeam create = create(test, 1);
|
||||||
HttpResponseException exception = assertThrows(HttpResponseException.class, () -> createAndCheckTeam(create,
|
HttpResponseException exception = assertThrows(HttpResponseException.class, () -> createAndCheckEntity(create,
|
||||||
authHeaders));
|
authHeaders));
|
||||||
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
||||||
}
|
}
|
||||||
@ -137,7 +144,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
List<UUID> users = Arrays.asList(user1.getId(), user2.getId());
|
List<UUID> users = Arrays.asList(user1.getId(), user2.getId());
|
||||||
CreateTeam create = create(test).withDisplayName("displayName").withDescription("description")
|
CreateTeam create = create(test).withDisplayName("displayName").withDescription("description")
|
||||||
.withProfile(PROFILE).withUsers(users);
|
.withProfile(PROFILE).withUsers(users);
|
||||||
Team team = createAndCheckTeam(create, adminAuthHeaders());
|
Team team = createAndCheckEntity(create, adminAuthHeaders());
|
||||||
|
|
||||||
// Make sure the user entity has relationship to the team
|
// Make sure the user entity has relationship to the team
|
||||||
user1 = UserResourceTest.getUser(user1.getId(), "teams", authHeaders("test@open-metadata.org"));
|
user1 = UserResourceTest.getUser(user1.getId(), "teams", authHeaders("test@open-metadata.org"));
|
||||||
@ -293,7 +300,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
User user1 = createUser(UserResourceTest.create(test, 1), adminAuthHeaders());
|
User user1 = createUser(UserResourceTest.create(test, 1), adminAuthHeaders());
|
||||||
List<UUID> users = Collections.singletonList(user1.getId());
|
List<UUID> users = Collections.singletonList(user1.getId());
|
||||||
CreateTeam create = create(test).withUsers(users);
|
CreateTeam create = create(test).withUsers(users);
|
||||||
Team team = createAndCheckTeam(create, adminAuthHeaders());
|
Team team = createAndCheckEntity(create, adminAuthHeaders());
|
||||||
deleteTeam(team.getId(), adminAuthHeaders());
|
deleteTeam(team.getId(), adminAuthHeaders());
|
||||||
|
|
||||||
// Make sure team is no longer there
|
// Make sure team is no longer there
|
||||||
@ -312,7 +319,7 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
authHeaders("test@open-metadata.org"));
|
authHeaders("test@open-metadata.org"));
|
||||||
List<UUID> users = Collections.singletonList(user1.getId());
|
List<UUID> users = Collections.singletonList(user1.getId());
|
||||||
CreateTeam create = create(test).withUsers(users);
|
CreateTeam create = create(test).withUsers(users);
|
||||||
Team team = createAndCheckTeam(create, adminAuthHeaders());
|
Team team = createAndCheckEntity(create, adminAuthHeaders());
|
||||||
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
|
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
|
||||||
deleteTeam(team.getId(), authHeaders("test@open-metadata.org")));
|
deleteTeam(team.getId(), authHeaders("test@open-metadata.org")));
|
||||||
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
||||||
@ -340,7 +347,9 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void patch_teamAttributes_as_admin_200_ok(TestInfo test)
|
public void patch_teamAttributes_as_admin_200_ok(TestInfo test)
|
||||||
throws HttpResponseException, JsonProcessingException {
|
throws HttpResponseException, JsonProcessingException {
|
||||||
|
//
|
||||||
// Create table without any attributes
|
// Create table without any attributes
|
||||||
|
//
|
||||||
Team team = createTeam(create(test), adminAuthHeaders());
|
Team team = createTeam(create(test), adminAuthHeaders());
|
||||||
assertNull(team.getDisplayName());
|
assertNull(team.getDisplayName());
|
||||||
assertNull(team.getDescription());
|
assertNull(team.getDescription());
|
||||||
@ -356,80 +365,50 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
new UserEntityInterface(user2).getEntityReference());
|
new UserEntityInterface(user2).getEntityReference());
|
||||||
Profile profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
|
Profile profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
|
||||||
|
|
||||||
|
//
|
||||||
// Add previously absent attributes
|
// Add previously absent attributes
|
||||||
team = patchTeamAttributesAndCheck(team, "displayName", "description", profile, users,
|
//
|
||||||
adminAuthHeaders(), MINOR_UPDATE);
|
String originalJson = JsonUtils.pojoToJson(team);
|
||||||
|
team.withDisplayName("displayName").withDescription("description").withProfile(profile).withUsers(users);
|
||||||
|
ChangeDescription change = getChangeDescription(team.getVersion())
|
||||||
|
.withFieldsAdded(Arrays.asList("displayName", "description", "profile", "users"));
|
||||||
|
team = patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
|
||||||
|
team.getUsers().get(0).setHref(null);
|
||||||
|
team.getUsers().get(1).setHref(null);
|
||||||
|
|
||||||
|
//
|
||||||
// Replace the attributes
|
// Replace the attributes
|
||||||
|
//
|
||||||
users = Arrays.asList(new UserEntityInterface(user1).getEntityReference(),
|
users = Arrays.asList(new UserEntityInterface(user1).getEntityReference(),
|
||||||
new UserEntityInterface(user3).getEntityReference()); // user2 dropped and user3 is added
|
new UserEntityInterface(user3).getEntityReference()); // user2 dropped and user3 is added
|
||||||
profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image1.com")));
|
profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image1.com")));
|
||||||
team = patchTeamAttributesAndCheck(team, "displayName1", "description1", profile, users,
|
|
||||||
adminAuthHeaders(), MINOR_UPDATE);
|
originalJson = JsonUtils.pojoToJson(team);
|
||||||
|
team.withDisplayName("displayName1").withDescription("description1").withProfile(profile).withUsers(users);
|
||||||
|
change = getChangeDescription(team.getVersion())
|
||||||
|
.withFieldsUpdated(Arrays.asList("displayName", "description", "profile", "users"));
|
||||||
|
team = patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
|
||||||
|
|
||||||
// Remove the attributes
|
// Remove the attributes
|
||||||
patchTeamAttributesAndCheck(team, null, null, null, null,
|
originalJson = JsonUtils.pojoToJson(team);
|
||||||
adminAuthHeaders(), MINOR_UPDATE);
|
team.withDisplayName(null).withDescription(null).withProfile(null).withUsers(null);
|
||||||
|
change = getChangeDescription(team.getVersion())
|
||||||
|
.withFieldsDeleted(Arrays.asList("displayName", "description", "profile", "users"));
|
||||||
|
patchEntityAndCheck(team, originalJson, adminAuthHeaders(), MINOR_UPDATE, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patch_teamAttributes_as_non_admin_401(TestInfo test) throws HttpResponseException {
|
public void patch_teamAttributes_as_non_admin_403(TestInfo test) throws HttpResponseException,
|
||||||
|
JsonProcessingException {
|
||||||
// Create table without any attributes
|
// Create table without any attributes
|
||||||
Team team = createTeam(create(test), adminAuthHeaders());
|
Team team = createTeam(create(test), adminAuthHeaders());
|
||||||
assertNull(team.getDisplayName());
|
// Patching as a non-admin should is disallowed
|
||||||
assertNull(team.getDescription());
|
String originalJson = JsonUtils.pojoToJson(team);
|
||||||
assertNull(team.getProfile());
|
team.setDisplayName("newDisplayName");
|
||||||
assertNull(team.getDeleted());
|
|
||||||
assertNull(team.getUsers());
|
|
||||||
|
|
||||||
User user1 = createUser(UserResourceTest.create(test, 1), authHeaders("test@open-metadata.org"));
|
|
||||||
User user2 = createUser(UserResourceTest.create(test, 2), authHeaders("test@open-metadata.org"));
|
|
||||||
User user3 = createUser(UserResourceTest.create(test, 3), authHeaders("test@open-metadata.org"));
|
|
||||||
|
|
||||||
List<EntityReference> users = Arrays.asList(new UserEntityInterface(user1).getEntityReference(),
|
|
||||||
new UserEntityInterface(user2).getEntityReference(),
|
|
||||||
new UserEntityInterface(user3).getEntityReference());
|
|
||||||
|
|
||||||
Profile profile = new Profile().withImages(new ImageList().withImage(URI.create("http://image.com")));
|
|
||||||
|
|
||||||
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
|
HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
|
||||||
patchTeamAttributesAndCheck(team, "displayName", "description", profile, users,
|
patchTeam(team.getId(), originalJson, team, authHeaders("test@open-metadata.org")));
|
||||||
authHeaders("test@open-metadata.org"), NO_CHANGE));
|
|
||||||
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
assertResponse(exception, FORBIDDEN, "Principal: CatalogPrincipal{name='test'} is not admin");
|
||||||
}
|
}
|
||||||
// @Test
|
|
||||||
// public void patch_updateInvalidUsers_404_notFound(TestInfo test) throws HttpResponseException {
|
|
||||||
// CreateTeam create = create(test);
|
|
||||||
// Team team = createAndCheckTeam(create);
|
|
||||||
//
|
|
||||||
// // User patch to add team to user relationship to an invalid user
|
|
||||||
// List<UUID> users = Collections.singletonList(UUID.randomUUID() /* invalid userId */);
|
|
||||||
// UpdateTeam update = new UpdateTeam().withUsers(users);
|
|
||||||
// HttpResponseException exception = assertThrows(HttpResponseException.class, () ->
|
|
||||||
// updateTeam(team.getId(), update));
|
|
||||||
// assertEquals(Response.Status.NOT_FOUND.getStatusCode(), exception.getStatusCode());
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static Team createAndCheckTeam(CreateTeam create, Map<String, String> authHeaders)
|
|
||||||
throws HttpResponseException {
|
|
||||||
String updatedBy = TestUtils.getPrincipal(authHeaders);
|
|
||||||
Team team = createTeam(create, authHeaders);
|
|
||||||
assertEquals(0.1, team.getVersion());
|
|
||||||
List<EntityReference> expectedUsers = new ArrayList<>();
|
|
||||||
for (UUID teamId : Optional.ofNullable(create.getUsers()).orElse(Collections.emptyList())) {
|
|
||||||
expectedUsers.add(new EntityReference().withId(teamId).withType(Entity.USER));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(team.getName(), create.getName());
|
|
||||||
validateTeam(team, create.getDescription(), create.getDisplayName(), create.getProfile(), expectedUsers, updatedBy);
|
|
||||||
|
|
||||||
// Get the newly created team and validate it
|
|
||||||
Team getTeam = getTeam(team.getId(), "profile,users", authHeaders);
|
|
||||||
assertEquals(team.getName(), create.getName());
|
|
||||||
validateTeam(getTeam, create.getDescription(), create.getDisplayName(), create.getProfile(), expectedUsers,
|
|
||||||
updatedBy);
|
|
||||||
return team;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Team createTeam(CreateTeam create, Map<String, String> authHeaders) throws HttpResponseException {
|
public static Team createTeam(CreateTeam create, Map<String, String> authHeaders) throws HttpResponseException {
|
||||||
return TestUtils.post(CatalogApplicationTest.getResource("teams"), create, Team.class, authHeaders);
|
return TestUtils.post(CatalogApplicationTest.getResource("teams"), create, Team.class, authHeaders);
|
||||||
@ -521,30 +500,6 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
return patchTeam(updated.getId(), originalJson, updated, authHeaders);
|
return patchTeam(updated.getId(), originalJson, updated, authHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Team patchTeamAttributesAndCheck(Team before, String displayName, String description, Profile profile,
|
|
||||||
List<EntityReference> users, Map<String, String> authHeaders, UpdateType updateType)
|
|
||||||
throws JsonProcessingException, HttpResponseException {
|
|
||||||
String updatedBy = TestUtils.getPrincipal(authHeaders);
|
|
||||||
Optional.ofNullable(before.getUsers()).orElse(Collections.emptyList()).forEach(t -> t.setHref(null)); // Remove href
|
|
||||||
String tableJson = JsonUtils.pojoToJson(before);
|
|
||||||
|
|
||||||
// Update the table attributes
|
|
||||||
before.setDisplayName(displayName);
|
|
||||||
before.setDescription(description);
|
|
||||||
before.setProfile(profile);
|
|
||||||
before.setUsers(users);
|
|
||||||
|
|
||||||
// Validate information returned in patch response has the updates
|
|
||||||
Team updatedTeam = patchTeam(tableJson, before, authHeaders);
|
|
||||||
validateTeam(updatedTeam, description, displayName, profile, users, updatedBy);
|
|
||||||
TestUtils.validateUpdate(before.getVersion(), updatedTeam.getVersion(), updateType);
|
|
||||||
|
|
||||||
// GET the table and Validate information returned
|
|
||||||
Team getTeam = getTeam(before.getId(), "users,profile", authHeaders);
|
|
||||||
validateTeam(getTeam, description, displayName, profile, users, updatedBy);
|
|
||||||
return getTeam;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteTeam(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
|
public void deleteTeam(UUID id, Map<String, String> authHeaders) throws HttpResponseException {
|
||||||
TestUtils.delete(CatalogApplicationTest.getResource("teams/" + id), authHeaders);
|
TestUtils.delete(CatalogApplicationTest.getResource("teams/" + id), authHeaders);
|
||||||
}
|
}
|
||||||
@ -560,4 +515,71 @@ public class TeamResourceTest extends CatalogApplicationTest {
|
|||||||
public static String getTeamName(TestInfo test) {
|
public static String getTeamName(TestInfo test) {
|
||||||
return String.format("team_%s", test.getDisplayName());
|
return String.format("team_%s", test.getDisplayName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object createRequest(TestInfo test, String description, String displayName, EntityReference owner) {
|
||||||
|
return create(test).withDescription(description).withDisplayName(displayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateCreatedEntity(Team team, Object request, Map<String, String> authHeaders) {
|
||||||
|
CreateTeam createRequest = (CreateTeam) request;
|
||||||
|
validateCommonEntityFields(getEntityInterface(team), createRequest.getDescription(),
|
||||||
|
TestUtils.getPrincipal(authHeaders), null);
|
||||||
|
|
||||||
|
assertEquals(createRequest.getDisplayName(), team.getDisplayName());
|
||||||
|
assertEquals(createRequest.getProfile(), team.getProfile());
|
||||||
|
|
||||||
|
List<EntityReference> expectedUsers = new ArrayList<>();
|
||||||
|
for (UUID teamId : Optional.ofNullable(createRequest.getUsers()).orElse(Collections.emptyList())) {
|
||||||
|
expectedUsers.add(new EntityReference().withId(teamId).withType(Entity.USER));
|
||||||
|
}
|
||||||
|
List<EntityReference> actualUsers = Optional.ofNullable(team.getUsers()).orElse(Collections.emptyList());
|
||||||
|
if (!expectedUsers.isEmpty()) {
|
||||||
|
assertEquals(expectedUsers.size(), actualUsers.size());
|
||||||
|
for (EntityReference user : actualUsers) {
|
||||||
|
TestUtils.validateEntityReference(user);
|
||||||
|
boolean foundUser = false;
|
||||||
|
for (EntityReference expectedEntity : expectedUsers) {
|
||||||
|
if (expectedEntity.getId().equals(user.getId())) {
|
||||||
|
foundUser = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(foundUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestUtils.validateEntityReference(team.getOwns());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateUpdatedEntity(Team updatedEntity, Object request, Map<String, String> authHeaders) {
|
||||||
|
validateCreatedEntity(updatedEntity, request, authHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validatePatchedEntity(Team expected, Team updated, Map<String, String> authHeaders) {
|
||||||
|
validateCommonEntityFields(getEntityInterface(updated), expected.getDescription(),
|
||||||
|
TestUtils.getPrincipal(authHeaders), null);
|
||||||
|
|
||||||
|
assertEquals(expected.getDisplayName(), updated.getDisplayName());
|
||||||
|
assertEquals(expected.getProfile(), updated.getProfile());
|
||||||
|
|
||||||
|
List<EntityReference> expectedUsers = Optional.ofNullable(expected.getUsers()).orElse(Collections.emptyList());
|
||||||
|
List<EntityReference> actualUsers = Optional.ofNullable(updated.getUsers()).orElse(Collections.emptyList());
|
||||||
|
actualUsers.forEach(TestUtils::validateEntityReference);
|
||||||
|
actualUsers.forEach(user -> user.setHref(null));
|
||||||
|
|
||||||
|
// Note ordering is same as server side ordering by ID as string
|
||||||
|
// Patch requests work only if the same ordering of users on the server side
|
||||||
|
actualUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
|
expectedUsers.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
|
assertEquals(expectedUsers, actualUsers);
|
||||||
|
TestUtils.validateEntityReference(updated.getOwns());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityInterface<Team> getEntityInterface(Team entity) {
|
||||||
|
return new TeamEntityInterface(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -448,7 +448,9 @@ public class UserResourceTest extends EntityResourceTest<User> {
|
|||||||
.withFieldsUpdated(Arrays.asList("teams", "timezone", "profile", "isBot"));
|
.withFieldsUpdated(Arrays.asList("teams", "timezone", "profile", "isBot"));
|
||||||
user = patchEntityAndCheck(user, origJson, adminAuthHeaders(), MINOR_UPDATE, change);
|
user = patchEntityAndCheck(user, origJson, adminAuthHeaders(), MINOR_UPDATE, change);
|
||||||
|
|
||||||
|
//
|
||||||
// Remove the attributes
|
// Remove the attributes
|
||||||
|
//
|
||||||
origJson = JsonUtils.pojoToJson(user);
|
origJson = JsonUtils.pojoToJson(user);
|
||||||
user.withTeams(null).withTimezone(null).withDisplayName(null).withProfile(null)
|
user.withTeams(null).withTimezone(null).withDisplayName(null).withProfile(null)
|
||||||
.withIsBot(null).withIsAdmin(false);
|
.withIsBot(null).withIsAdmin(false);
|
||||||
@ -654,8 +656,10 @@ public class UserResourceTest extends EntityResourceTest<User> {
|
|||||||
|
|
||||||
updatedTeams.forEach(TestUtils::validateEntityReference);
|
updatedTeams.forEach(TestUtils::validateEntityReference);
|
||||||
|
|
||||||
expectedTeams.sort(Comparator.comparing(EntityReference::getName));
|
// Note ordering is same as server side ordering by ID as string
|
||||||
updatedTeams.sort(Comparator.comparing(EntityReference::getName));
|
// Patch requests work only if the same ordering of users on the server side
|
||||||
|
expectedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
|
updatedTeams.sort(Comparator.comparing(entityReference -> entityReference.getId().toString()));
|
||||||
updatedTeams.forEach(t -> t.setHref(null));
|
updatedTeams.forEach(t -> t.setHref(null));
|
||||||
assertEquals(expectedTeams, updatedTeams);
|
assertEquals(expectedTeams, updatedTeams);
|
||||||
if (expected.getProfile() != null) {
|
if (expected.getProfile() != null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user