import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.Paging;
-import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentQuery;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.component.index.ComponentIndex;
+import org.sonar.server.component.index.ComponentQuery;
+import org.sonar.server.es.SearchIdResult;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.organization.DefaultOrganizationProvider;
-import org.sonar.server.user.UserSession;
import org.sonar.server.ws.WsUtils;
import org.sonarqube.ws.WsComponents;
import org.sonarqube.ws.WsComponents.SearchWsResponse;
import static org.sonar.core.util.stream.MoreCollectors.toHashSet;
import static org.sonar.server.util.LanguageParamUtils.getExampleValue;
import static org.sonar.server.util.LanguageParamUtils.getLanguageKeys;
-import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
+import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS;
public class SearchAction implements ComponentsWsAction {
+ private final ComponentIndex componentIndex;
private final DbClient dbClient;
private final ResourceTypes resourceTypes;
private final I18n i18n;
- private final UserSession userSession;
private final Languages languages;
private final DefaultOrganizationProvider defaultOrganizationProvider;
- public SearchAction(DbClient dbClient, ResourceTypes resourceTypes, I18n i18n, UserSession userSession,
- Languages languages, DefaultOrganizationProvider defaultOrganizationProvider) {
+ public SearchAction(ComponentIndex componentIndex, DbClient dbClient, ResourceTypes resourceTypes, I18n i18n, Languages languages,
+ DefaultOrganizationProvider defaultOrganizationProvider) {
+ this.componentIndex = componentIndex;
this.dbClient = dbClient;
this.resourceTypes = resourceTypes;
this.i18n = i18n;
- this.userSession = userSession;
this.languages = languages;
this.defaultOrganizationProvider = defaultOrganizationProvider;
}
private SearchWsResponse doHandle(SearchWsRequest request) {
try (DbSession dbSession = dbClient.openSession(false)) {
- ComponentQuery query = buildQuery(request);
OrganizationDto organization = getOrganization(dbSession, request);
- Paging paging = buildPaging(dbSession, request, organization, query);
- List<ComponentDto> components = searchComponents(dbSession, organization, query, paging);
+ ComponentQuery esQuery = buildEsQuery(organization, request);
+ SearchIdResult<String> results = componentIndex.search(esQuery, new SearchOptions().setPage(request.getPage(), request.getPageSize()));
+
+ List<ComponentDto> components = dbClient.componentDao().selectByUuids(dbSession, results.getIds());
Map<String, String> projectKeysByUuids = searchProjectsKeysByUuids(dbSession, components);
- return buildResponse(components, organization, projectKeysByUuids, paging);
+ return buildResponse(components, organization, projectKeysByUuids,
+ Paging.forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal((int) results.getTotal()));
}
}
return projects.stream().collect(toMap(ComponentDto::uuid, ComponentDto::getDbKey));
}
- private static ComponentQuery buildQuery(SearchWsRequest request) {
- List<String> qualifiers = request.getQualifiers();
- return ComponentQuery.builder()
- .setNameOrKeyQuery(request.getQuery())
- .setLanguage(request.getLanguage())
- .setQualifiers(qualifiers.toArray(new String[qualifiers.size()]))
- .build();
- }
-
private OrganizationDto getOrganization(DbSession dbSession, SearchWsRequest request) {
String organizationKey = Optional.ofNullable(request.getOrganization())
.orElseGet(defaultOrganizationProvider.get()::getKey);
"No organizationDto with key '%s'", organizationKey);
}
- private Paging buildPaging(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, ComponentQuery query) {
- int total = dbClient.componentDao().countByQuery(dbSession, organization.getUuid(), query);
- return Paging.forPageIndex(request.getPage())
- .withPageSize(request.getPageSize())
- .andTotal(total);
- }
-
- private List<ComponentDto> searchComponents(DbSession dbSession, OrganizationDto organization, ComponentQuery query, Paging paging) {
- List<ComponentDto> componentDtos = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize());
- return userSession.keepAuthorizedComponents(UserRole.USER, componentDtos);
+ private static ComponentQuery buildEsQuery(OrganizationDto organization, SearchWsRequest request) {
+ return ComponentQuery.builder()
+ .setQuery(request.getQuery())
+ .setOrganization(organization.getUuid())
+ .setLanguage(request.getLanguage())
+ .setQualifiers(request.getQualifiers())
+ .build();
}
private static SearchWsResponse buildResponse(List<ComponentDto> components, OrganizationDto organization, Map<String, String> projectKeysByUuids, Paging paging) {
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
+import org.sonar.server.component.index.ComponentIndex;
+import org.sonar.server.component.index.ComponentIndexDefinition;
+import org.sonar.server.component.index.ComponentIndexer;
+import org.sonar.server.es.EsTester;
import org.sonar.server.i18n.I18nRule;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.permission.index.AuthorizationTypeSupport;
+import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.client.component.SearchWsRequest;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create(System2.INSTANCE);
+ @Rule
+ public EsTester es = new EsTester(new ComponentIndexDefinition(new MapSettings().asConfig()));
private I18nRule i18n = new I18nRule();
-
private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private ResourceTypesRule resourceTypes = new ResourceTypesRule();
private Languages languages = mock(Languages.class);
+ private ComponentIndexer indexer = new ComponentIndexer(db.getDbClient(), es.client());
+ private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, indexer);
+ private ComponentIndex index = new ComponentIndex(es.client(), new AuthorizationTypeSupport(userSession));
+
private UserDto user;
private WsActionTester ws;
public void setUp() {
resourceTypes.setAllQualifiers(PROJECT, MODULE, DIRECTORY, FILE);
when(languages.all()).thenReturn(javaLanguage());
- ws = new WsActionTester(new SearchAction(db.getDbClient(), resourceTypes, i18n, userSession, languages, defaultOrganizationProvider));
+ ws = new WsActionTester(new SearchAction(index, db.getDbClient(), resourceTypes, i18n, languages, defaultOrganizationProvider));
user = db.users().insertUser("john");
userSession.logIn(user);
ComponentDto file1 = newFileDto(project).setDbKey("file1");
ComponentDto file2 = newFileDto(project).setDbKey("file2");
db.components().insertComponents(project, file1, file2);
- setBrowsePermissionOnUser(project);
+ setBrowsePermissionOnUserAndIndex(project);
SearchWsResponse response = call(new SearchWsRequest().setQuery(file1.getDbKey()).setQualifiers(singletonList(FILE)));
ComponentDto project2 = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization());
ComponentDto file3 = newFileDto(project2).setDbKey("file3");
db.components().insertComponents(project1, file1, file2, project2, file3);
- setBrowsePermissionOnUser(project1);
+ setBrowsePermissionOnUserAndIndex(project1);
SearchWsResponse response = call(new SearchWsRequest().setQualifiers(singletonList(FILE)));
- assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(file1.getDbKey(), file2.getDbKey());
+ assertThat(response.getComponentsList()).extracting(Component::getKey)
+ .containsExactlyInAnyOrder(file1.getDbKey(), file2.getDbKey());
+ assertThat(response.getPaging().getTotal()).isEqualTo(2);
}
@Test
ComponentDto file2 = newFileDto(module).setDbKey("file2");
ComponentDto file3 = newFileDto(project).setDbKey("file3");
db.components().insertComponents(project, module, file1, file2, file3);
+ setBrowsePermissionOnUserAndIndex(project);
SearchWsResponse response = call(new SearchWsRequest().setQualifiers(asList(PROJECT, MODULE, FILE)));
tuple(file3.getDbKey(), project.getDbKey()));
}
- @Test
- public void do_not_verify_permissions_if_user_is_root() throws IOException {
- OrganizationDto org = db.organizations().insert();
- ComponentDto project1 = ComponentTesting.newPrivateProjectDto(org);
- ComponentDto file1 = newFileDto(project1);
- ComponentDto project2 = ComponentTesting.newPrivateProjectDto(org);
- ComponentDto file2 = newFileDto(project2);
- db.components().insertComponents(project1, file1, project2, file2);
-
- SearchWsRequest request = new SearchWsRequest().setQualifiers(singletonList(FILE)).setOrganization(org.getKey());
-
- userSession.logIn().setNonRoot();
- assertThat(call(request).getComponentsCount()).isZero();
-
- userSession.logIn().setRoot();
- assertThat(call(request).getComponentsList()).extracting(Component::getKey).containsOnly(file1.getDbKey(), file2.getDbKey());
- }
-
@Test
public void does_not_return_branches() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
- userSession.logIn().setRoot();
+ setBrowsePermissionOnUserAndIndex(project, branch);
SearchWsResponse response = call(new SearchWsRequest().setQualifiers(asList(PROJECT, MODULE, FILE)));
ComponentDto directory = newDirectory(module, "path/to/directoy").setUuid("directory-uuid").setDbKey("directory-key").setName("Directory Name");
db.components().insertComponents(project, module, directory,
newFileDto(module, directory, "file-uuid").setDbKey("file-key").setLanguage("java").setName("File Name"));
- userSession.addProjectPermission(UserRole.USER, project);
+ setBrowsePermissionOnUserAndIndex(project);
String response = ws.newRequest()
.setMediaType(MediaTypes.JSON)
private void insertProjectsAuthorizedForUser(ComponentDto... projects) {
db.components().insertComponents(projects);
- setBrowsePermissionOnUser(projects);
+ setBrowsePermissionOnUserAndIndex(projects);
db.commit();
}
- private void setBrowsePermissionOnUser(ComponentDto... projects) {
- Arrays.stream(projects).forEach(project -> userSession.addProjectPermission(UserRole.USER, project));
+ private void setBrowsePermissionOnUserAndIndex(ComponentDto... projects) {
+ index();
+ Arrays.stream(projects).forEach(project -> authorizationIndexerTester.allowOnlyUser(project, user));
}
private SearchWsResponse call(SearchWsRequest wsRequest) {
return request.executeProtobuf(SearchWsResponse.class);
}
+ private void index() {
+ indexer.indexOnStartup(emptySet());
+ }
+
private static Language[] javaLanguage() {
return new Language[] {new Language() {
@Override