add the autoComplete link to the index resource

This commit is contained in:
Mohamed Karray
2018-10-15 08:41:46 +02:00
parent c7b8a3fedd
commit 27ca8860d3
9 changed files with 147 additions and 34 deletions

View File

@@ -15,7 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class AutoCompleteITCase { public class AutoCompleteITCase {
public static final String CREATED_USER_PREFIX = "user"; public static final String CREATED_USER_PREFIX = "user_";
public static final String CREATED_GROUP_PREFIX = "group_"; public static final String CREATED_GROUP_PREFIX = "group_";
@Before @Before
@@ -28,9 +28,10 @@ public class AutoCompleteITCase {
createUsers(); createUsers();
ScmRequests.start() ScmRequests.start()
.given() .given()
.url(TestData.getUsersAutoCompleteUrl("user*")) .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN)
.usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) .assertStatusCode(200)
.getAutoCompleteResource() .usingIndexResponse()
.requestAutoCompleteUsers("user*")
.assertStatusCode(200) .assertStatusCode(200)
.usingAutoCompleteResponse() .usingAutoCompleteResponse()
.assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX));
@@ -44,9 +45,10 @@ public class AutoCompleteITCase {
createUsers(); createUsers();
ScmRequests.start() ScmRequests.start()
.given() .given()
.url(TestData.getUsersAutoCompleteUrl("user*")) .requestIndexResource(username,password)
.usernameAndPassword(username, password) .assertStatusCode(200)
.getAutoCompleteResource() .usingIndexResponse()
.requestAutoCompleteUsers("user*")
.assertStatusCode(200) .assertStatusCode(200)
.usingAutoCompleteResponse() .usingAutoCompleteResponse()
.assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX)); .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_USER_PREFIX));
@@ -57,9 +59,10 @@ public class AutoCompleteITCase {
createGroups(); createGroups();
ScmRequests.start() ScmRequests.start()
.given() .given()
.url(TestData.getGroupsAutoCompleteUrl("group*")) .requestIndexResource(TestData.USER_SCM_ADMIN,TestData.USER_SCM_ADMIN)
.usernameAndPassword(TestData.USER_SCM_ADMIN, TestData.USER_SCM_ADMIN) .assertStatusCode(200)
.getAutoCompleteResource() .usingIndexResponse()
.applyAutoCompleteGroups("group*")
.assertStatusCode(200) .assertStatusCode(200)
.usingAutoCompleteResponse() .usingAutoCompleteResponse()
.assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX));
@@ -73,9 +76,10 @@ public class AutoCompleteITCase {
createGroups(); createGroups();
ScmRequests.start() ScmRequests.start()
.given() .given()
.url(TestData.getGroupsAutoCompleteUrl("group*")) .requestIndexResource(username,password)
.usernameAndPassword(username, password) .assertStatusCode(200)
.getAutoCompleteResource() .usingIndexResponse()
.applyAutoCompleteGroups("group*")
.assertStatusCode(200) .assertStatusCode(200)
.usingAutoCompleteResponse() .usingAutoCompleteResponse()
.assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX)); .assertAutoCompleteResults(assertAutoCompleteResult(CREATED_GROUP_PREFIX));

View File

@@ -46,24 +46,46 @@ public class ScmRequests {
* @return the response of the GET request using the given link * @return the response of the GET request using the given link
*/ */
private Response applyGETRequestFromLink(Response response, String linkPropertyName) { private Response applyGETRequestFromLink(Response response, String linkPropertyName) {
return applyGETRequest(response return applyGETRequestFromLinkWithParams(response, linkPropertyName, "");
.then()
.extract()
.path(linkPropertyName));
} }
/**
* Apply a GET Request to the extracted url from the given link
*
* @param linkPropertyName the property name of link
* @param response the response containing the link
* @param queryParams query params eg. ?q=xyz&count=12
* @return the response of the GET request using the given link
*/
private Response applyGETRequestFromLinkWithParams(Response response, String linkPropertyName, String queryParams) {
return applyGETRequestWithQueryParams(response
.then()
.extract()
.path(linkPropertyName), queryParams);
}
/**
* Apply a GET Request to the given <code>url</code> and return the response.
*
* @param url the url of the GET request
* @param htmlQueryParams query params eg. ?q=xyz&count=12
* @return the response of the GET request using the given <code>url</code>
*/
private Response applyGETRequestWithQueryParams(String url, String htmlQueryParams) {
return RestAssured.given()
.auth().preemptive().basic(username, password)
.when()
.get(url + htmlQueryParams);
}
/** /**
* Apply a GET Request to the given <code>url</code> and return the response. * Apply a GET Request to the given <code>url</code> and return the response.
* *
* @param url the url of the GET request * @param url the url of the GET request
* @return the response of the GET request using the given <code>url</code> * @return the response of the GET request using the given <code>url</code>
*/ **/
private Response applyGETRequest(String url) { private Response applyGETRequest(String url) {
return RestAssured.given() return applyGETRequestWithQueryParams(url, "");
.auth().preemptive().basic(username, password)
.when()
.get(url);
} }
@@ -133,6 +155,12 @@ public class ScmRequests {
return new GivenUrl(); return new GivenUrl();
} }
public AppliedIndexResource requestIndexResource(String username, String password) {
setUsername(username);
setPassword(password);
return new AppliedIndexResource(applyGETRequest(RestUtil.REST_BASE_URL.toString()));
}
public GivenUrl url(URI url) { public GivenUrl url(URI url) {
setUrl(url.toString()); setUrl(url.toString());
return new GivenUrl(); return new GivenUrl();
@@ -480,17 +508,46 @@ public class ScmRequests {
} }
public class AutoCompleteResponse extends ModelResponse<AutoCompleteResponse>{ public class AutoCompleteResponse extends ModelResponse<AutoCompleteResponse> {
public AutoCompleteResponse(Response response) { public AutoCompleteResponse(Response response) {
super(response); super(response);
} }
public AutoCompleteResponse assertAutoCompleteResults(Consumer<List<Map>> checker){ public AutoCompleteResponse assertAutoCompleteResults(Consumer<List<Map>> checker) {
List<Map> result = response.then().extract().path(""); List<Map> result = response.then().extract().path("");
checker.accept(result); checker.accept(result);
return this; return this;
} }
} }
public class AppliedIndexResource extends AppliedRequest<AppliedIndexResource> {
public AppliedIndexResource(Response response) {
super(response);
}
public IndexResponse usingIndexResponse() {
return new IndexResponse(super.response);
}
}
public class IndexResponse extends ModelResponse<IndexResponse> {
public static final String AUTOCOMPLETE_USERS = "_links.autocompleteUsers.href";
public static final String AUTOCOMPLETE_GROUPS = "_links.autocompleteGroups.href";
public IndexResponse(Response response) {
super(response);
}
public AppliedAutoCompleteRequest requestAutoCompleteUsers(String q) {
return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_USERS, "?q="+q));
}
public AppliedAutoCompleteRequest applyAutoCompleteGroups(String q) {
return new AppliedAutoCompleteRequest(applyGETRequestFromLinkWithParams(response, AUTOCOMPLETE_GROUPS, "?q="+q));
}
}
} }

View File

@@ -14,8 +14,8 @@ import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -50,7 +50,7 @@ public class AutoCompleteResource {
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user:autocomplete\" privilege"), @ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user:autocomplete\" privilege"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
public Response searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { public List<ReducedObjectModelDto> searchUser(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
return map(userManager.autocomplete(filter)); return map(userManager.autocomplete(filter));
} }
@@ -64,16 +64,15 @@ public class AutoCompleteResource {
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group:autocomplete\" privilege"), @ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group:autocomplete\" privilege"),
@ResponseCode(code = 500, condition = "internal server error") @ResponseCode(code = 500, condition = "internal server error")
}) })
public Response searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) { public List<ReducedObjectModelDto> searchGroup(@NotEmpty(message = PARAMETER_IS_REQUIRED) @Size(min = MIN_SEARCHED_CHARS, message = INVALID_PARAMETER_LENGTH) @QueryParam("q") String filter) {
return map(groupManager.autocomplete(filter)); return map(groupManager.autocomplete(filter));
} }
private <T extends ReducedModelObject> Response map(Collection<T> autocomplete) { private <T extends ReducedModelObject> List<ReducedObjectModelDto> map(Collection<T> autocomplete) {
return Response.ok(autocomplete return autocomplete
.stream() .stream()
.map(mapper::map) .map(mapper::map)
.collect(Collectors.toList())) .collect(Collectors.toList());
.build();
} }

View File

@@ -34,6 +34,12 @@ public class IndexDtoGenerator {
if (UserPermissions.list().isPermitted()) { if (UserPermissions.list().isPermitted()) {
builder.single(link("users", resourceLinks.userCollection().self())); builder.single(link("users", resourceLinks.userCollection().self()));
} }
if (UserPermissions.autocomplete().isPermitted()) {
builder.single(link("autocompleteUsers", resourceLinks.autoComplete().users()));
}
if (GroupPermissions.autocomplete().isPermitted()) {
builder.single(link("autocompleteGroups", resourceLinks.autoComplete().groups()));
}
if (GroupPermissions.list().isPermitted()) { if (GroupPermissions.list().isPermitted()) {
builder.single(link("groups", resourceLinks.groupCollection().self())); builder.single(link("groups", resourceLinks.groupCollection().self()));
} }

View File

@@ -142,6 +142,26 @@ class ResourceLinks {
} }
} }
AutoCompleteLinks autoComplete() {
return new AutoCompleteLinks (scmPathInfoStore.get());
}
static class AutoCompleteLinks {
private final LinkBuilder linkBuilder;
AutoCompleteLinks (ScmPathInfo pathInfo) {
linkBuilder = new LinkBuilder(pathInfo, AutoCompleteResource.class);
}
String users() {
return linkBuilder.method("searchUser").parameters().href();
}
String groups() {
return linkBuilder.method("searchGroup").parameters().href();
}
}
ConfigLinks config() { ConfigLinks config() {
return new ConfigLinks(scmPathInfoStore.get()); return new ConfigLinks(scmPathInfoStore.get());
} }

View File

@@ -50,7 +50,6 @@ import sonia.scm.SCMContextProvider;
import sonia.scm.TransformFilter; import sonia.scm.TransformFilter;
import sonia.scm.search.SearchRequest; import sonia.scm.search.SearchRequest;
import sonia.scm.search.SearchUtil; import sonia.scm.search.SearchUtil;
import sonia.scm.user.UserPermissions;
import sonia.scm.util.CollectionAppender; import sonia.scm.util.CollectionAppender;
import sonia.scm.util.Util; import sonia.scm.util.Util;
@@ -245,7 +244,7 @@ public class DefaultGroupManager extends AbstractGroupManager
@Override @Override
public Collection<Group> autocomplete(String filter) { public Collection<Group> autocomplete(String filter) {
UserPermissions.autocomplete().check(); GroupPermissions.autocomplete().check();
SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT); SearchRequest searchRequest = new SearchRequest(filter, true, DEFAULT_LIMIT);
return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null); return SearchUtil.search(searchRequest, groupDAO.getAll(), group -> matches(searchRequest,group)?group:null);
} }

View File

@@ -13,7 +13,7 @@ import java.util.Optional;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@SubjectAware(configuration = "classpath:sonia/scm/shiro-001.ini") @SubjectAware(configuration = "classpath:sonia/scm/shiro-002.ini")
public class IndexResourceTest { public class IndexResourceTest {
@Rule @Rule
@@ -94,6 +94,24 @@ public class IndexResourceTest {
Assertions.assertThat(index.getLinks().getLinkBy("config")).matches(o -> !o.isPresent()); Assertions.assertThat(index.getLinks().getLinkBy("config")).matches(o -> !o.isPresent());
} }
@Test
@SubjectAware(username = "trillian", password = "secret")
public void shouldRenderAutoCompleteLinks() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(Optional::isPresent);
Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(Optional::isPresent);
}
@Test
@SubjectAware(username = "user_without_autocomplete_permission", password = "secret")
public void userWithoutAutocompletePermissionShouldNotSeeAutoCompleteLinks() {
IndexDto index = indexResource.getIndex();
Assertions.assertThat(index.getLinks().getLinkBy("autocompleteUsers")).matches(o -> !o.isPresent());
Assertions.assertThat(index.getLinks().getLinkBy("autocompleteGroups")).matches(o -> !o.isPresent());
}
@Test @Test
@SubjectAware(username = "dent", password = "secret") @SubjectAware(username = "dent", password = "secret")
public void shouldRenderAdminLinksIfAuthorized() { public void shouldRenderAdminLinksIfAuthorized() {

View File

@@ -16,6 +16,7 @@ public class ResourceLinksMock {
when(resourceLinks.user()).thenReturn(userLinks); when(resourceLinks.user()).thenReturn(userLinks);
when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(uriInfo,userLinks)); when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(uriInfo,userLinks));
when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo)); when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo));
when(resourceLinks.autoComplete()).thenReturn(new ResourceLinks.AutoCompleteLinks(uriInfo));
when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(uriInfo)); when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(uriInfo));
when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(uriInfo)); when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(uriInfo));
when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(uriInfo)); when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(uriInfo));

View File

@@ -0,0 +1,9 @@
[users]
user_without_autocomplete_permission = secret
trillian = secret, user_ac, group_ac
dent = secret, admin
[roles]
admin = *
user_ac = user:autocomplete
group_ac = group:autocomplete