import org.sonar.core.persistence.DbSession;
import javax.annotation.CheckForNull;
+
import java.util.List;
public class MeasureDao implements ServerComponent, DaoComponent {
mapper(session).insert(measureDto);
}
+ public List<String> selectMetricKeysForSnapshot(DbSession session, Long snapshotId) {
+ return mapper(session).selectMetricKeysForSnapshot(snapshotId);
+ }
+
private MeasureMapper mapper(DbSession session) {
return session.getMapper(MeasureMapper.class);
}
import org.sonar.server.ui.JRubyI18n;
import org.sonar.server.ui.PageDecorations;
import org.sonar.server.ui.Views;
+import org.sonar.server.ui.ws.ComponentConfigurationPages;
+import org.sonar.server.ui.ws.ComponentNavigationAction;
import org.sonar.server.ui.ws.GlobalNavigationAction;
import org.sonar.server.ui.ws.NavigationWs;
import org.sonar.server.ui.ws.SettingsNavigationAction;
// UI
pico.addSingleton(GlobalNavigationAction.class);
pico.addSingleton(SettingsNavigationAction.class);
+ pico.addSingleton(ComponentConfigurationPages.class);
+ pico.addSingleton(ComponentNavigationAction.class);
pico.addSingleton(NavigationWs.class);
for (Object components : level4AddedComponents) {
import org.sonar.api.web.View;
import org.sonar.api.web.Widget;
+import javax.annotation.Nullable;
+
import java.util.List;
import java.util.Map;
import java.util.Set;
return getPages(section, null, null, null, null);
}
- public List<ViewProxy<Page>> getPages(String section, String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures) {
+ public List<ViewProxy<Page>> getPages(String section,
+ @Nullable String resourceScope, @Nullable String resourceQualifier, @Nullable String resourceLanguage, @Nullable String[] availableMeasures) {
List<ViewProxy<Page>> result = Lists.newArrayList();
for (ViewProxy<Page> proxy : pages) {
if (accept(proxy, section, resourceScope, resourceQualifier, resourceLanguage, availableMeasures)) {
return Lists.newArrayList(widgets);
}
- protected static boolean accept(ViewProxy proxy, String section, String resourceScope, String resourceQualifier, String resourceLanguage, String[] availableMeasures) {
+ protected static boolean accept(ViewProxy proxy,
+ @Nullable String section, @Nullable String resourceScope, @Nullable String resourceQualifier, @Nullable String resourceLanguage, @Nullable String[] availableMeasures) {
return acceptNavigationSection(proxy, section)
&& acceptResourceScope(proxy, resourceScope)
&& acceptResourceQualifier(proxy, resourceQualifier)
&& acceptAvailableMeasures(proxy, availableMeasures);
}
- protected static boolean acceptResourceLanguage(ViewProxy proxy, String resourceLanguage) {
+ protected static boolean acceptResourceLanguage(ViewProxy proxy, @Nullable String resourceLanguage) {
return resourceLanguage == null || ArrayUtils.isEmpty(proxy.getResourceLanguages()) || ArrayUtils.contains(proxy.getResourceLanguages(), resourceLanguage);
}
- protected static boolean acceptResourceScope(ViewProxy proxy, String resourceScope) {
+ protected static boolean acceptResourceScope(ViewProxy proxy, @Nullable String resourceScope) {
return resourceScope == null || ArrayUtils.isEmpty(proxy.getResourceScopes()) || ArrayUtils.contains(proxy.getResourceScopes(), resourceScope);
}
- protected static boolean acceptResourceQualifier(ViewProxy proxy, String resourceQualifier) {
+ protected static boolean acceptResourceQualifier(ViewProxy proxy, @Nullable String resourceQualifier) {
return resourceQualifier == null || ArrayUtils.isEmpty(proxy.getResourceQualifiers()) || ArrayUtils.contains(proxy.getResourceQualifiers(), resourceQualifier);
}
- protected static boolean acceptNavigationSection(ViewProxy proxy, String section) {
+ protected static boolean acceptNavigationSection(ViewProxy proxy, @Nullable String section) {
return proxy.isWidget() || section == null || ArrayUtils.contains(proxy.getSections(), section);
}
- protected static boolean acceptAvailableMeasures(ViewProxy proxy, String[] availableMeasures) {
+ protected static boolean acceptAvailableMeasures(ViewProxy proxy, @Nullable String[] availableMeasures) {
return availableMeasures == null || proxy.acceptsAvailableMeasures(availableMeasures);
}
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.ui;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.ui.ws;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.ResourceType;
+import org.sonar.api.resources.ResourceTypes;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.server.user.UserSession;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Locale;
+
+public class ComponentConfigurationPages implements ServerComponent {
+
+ static final String PROPERTY_COMPARABLE = "comparable";
+ static final String PROPERTY_CONFIGURABLE = "configurable";
+ static final String PROPERTY_HAS_ROLE_POLICY = "hasRolePolicy";
+ static final String PROPERTY_MODIFIABLE_HISTORY = "modifiable_history";
+ static final String PROPERTY_UPDATABLE_KEY = "updatable_key";
+ static final String PROPERTY_DELETABLE = "deletable";
+
+ private final I18n i18n;
+ private final ResourceTypes resourceTypes;
+
+ public ComponentConfigurationPages(I18n i18n, ResourceTypes resourceTypes) {
+ this.i18n = i18n;
+ this.resourceTypes = resourceTypes;
+ }
+
+ List<ConfigPage> getConfigPages(ComponentDto component, UserSession userSession) {
+ boolean isAdmin = userSession.hasProjectPermissionByUuid(UserRole.ADMIN, component.projectUuid());
+ boolean isProject = Qualifiers.PROJECT.equals(component.qualifier());
+ Locale locale = userSession.locale();
+ String componentKey = encodeComponentKey(component);
+
+ List<ConfigPage> configPages = Lists.newArrayList();
+
+ configPages.add(new ConfigPage(
+ isAdmin && componentTypeHasProperty(component, PROPERTY_CONFIGURABLE),
+ String.format("/project/settings?id=%s", componentKey),
+ i18n.message(locale, "project_settings.page", null)));
+
+ configPages.add(new ConfigPage(
+ isProject,
+ String.format("/project/profile?id=%s", componentKey),
+ i18n.message(locale, "project_quality_profiles.page", null)));
+
+ configPages.add(new ConfigPage(
+ isProject,
+ String.format("/project/qualitygate?id=%s", componentKey),
+ i18n.message(locale, "project_quality_gate.page", null)));
+
+ configPages.add(new ConfigPage(
+ isAdmin,
+ String.format("/manual_measures/index?id=%s", componentKey),
+ i18n.message(locale, "manual_measures.page", null)));
+
+ configPages.add(new ConfigPage(
+ isAdmin && isProject,
+ String.format("/action_plans/index?id=%s", componentKey),
+ i18n.message(locale, "action_plans.page", null)));
+
+ configPages.add(new ConfigPage(
+ isAdmin && isProject,
+ String.format("/project/links?id=%s", componentKey),
+ i18n.message(locale, "action_plans.page", null)));
+
+ configPages.add(new ConfigPage(
+ componentTypeHasProperty(component, PROPERTY_HAS_ROLE_POLICY),
+ String.format("/project_roles/index?id=%s", componentKey),
+ i18n.message(locale, "permissions.page", null)));
+
+ configPages.add(new ConfigPage(
+ componentTypeHasProperty(component, PROPERTY_MODIFIABLE_HISTORY),
+ String.format("/project/history?id=%s", componentKey),
+ i18n.message(locale, "project_history.page", null)));
+
+ configPages.add(new ConfigPage(
+ componentTypeHasProperty(component, PROPERTY_UPDATABLE_KEY),
+ String.format("/project/key?id=%s", componentKey),
+ i18n.message(locale, "update_key.page", null)));
+
+ configPages.add(new ConfigPage(
+ componentTypeHasProperty(component, PROPERTY_DELETABLE),
+ String.format("/project/deletion?id=%s", componentKey),
+ i18n.message(locale, "deletion.page", null)));
+
+ return configPages;
+ }
+
+ static String encodeComponentKey(ComponentDto component) {
+ String componentKey = component.getKey();
+ try {
+ componentKey = URLEncoder.encode(componentKey, Charsets.UTF_8.name());
+ } catch (UnsupportedEncodingException unknownEncoding) {
+ throw new IllegalStateException(unknownEncoding);
+ }
+ return componentKey;
+ }
+
+ boolean componentTypeHasProperty(ComponentDto component, String resourceTypeProperty) {
+ ResourceType resourceType = resourceTypes.get(component.qualifier());
+ if (resourceType != null) {
+ return resourceType.getBooleanProperty(resourceTypeProperty);
+ }
+ return false;
+ }
+
+ static class ConfigPage {
+ private final boolean visible;
+ private final String url;
+ private final String name;
+
+ ConfigPage(boolean visible, String url, String name) {
+ this.visible = visible;
+ this.url = url;
+ this.name = name;
+ }
+
+ void write(JsonWriter json) {
+ if (visible) {
+ json.beginObject()
+ .prop("url", url)
+ .prop("name", name)
+ .endObject();
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.ui.ws;
+
+import com.google.common.collect.Lists;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.Page;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.dashboard.ActiveDashboardDao;
+import org.sonar.core.dashboard.DashboardDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.core.properties.PropertyQuery;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.ui.ViewProxy;
+import org.sonar.server.ui.Views;
+import org.sonar.server.ui.ws.ComponentConfigurationPages.ConfigPage;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+public class ComponentNavigationAction implements NavigationAction {
+
+ private static final String PARAM_COMPONENT_KEY = "componentKey";
+
+ private final DbClient dbClient;
+ private final ActiveDashboardDao activeDashboardDao;
+ private final Views views;
+ private final I18n i18n;
+ private final ComponentConfigurationPages projectConfiguration;
+
+ public ComponentNavigationAction(DbClient dbClient, ActiveDashboardDao activeDashboardDao, Views views, I18n i18n,
+ ComponentConfigurationPages projectConfiguration) {
+ this.dbClient = dbClient;
+ this.activeDashboardDao = activeDashboardDao;
+ this.views = views;
+ this.i18n = i18n;
+ this.projectConfiguration = projectConfiguration;
+ }
+
+ @Override
+ public void define(NewController context) {
+ NewAction projectNavigation = context.createAction("component")
+ .setDescription("Get information concerning component navigation for the current user. " +
+ "Requires the 'Browse' permission on the component's project.")
+ .setHandler(this)
+ .setInternal(true)
+ .setResponseExample(getClass().getResource("example-component.json"))
+ .setSince("5.2");
+
+ projectNavigation.createParam(PARAM_COMPONENT_KEY)
+ .setDescription("A component key.")
+ .setExampleValue("org.codehaus.sonar:sonar")
+ .setRequired(true);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ String componentKey = request.mandatoryParam(PARAM_COMPONENT_KEY);
+
+ UserSession userSession = UserSession.get();
+ DbSession session = dbClient.openSession(false);
+
+ try {
+ ComponentDto component = dbClient.componentDao().getByKey(session, componentKey);
+
+ userSession.checkProjectUuidPermission(UserRole.USER, component.projectUuid());
+
+ SnapshotDto snapshot = dbClient.snapshotDao().getLastSnapshot(session, new SnapshotDto().setResourceId(component.getId()));
+
+ JsonWriter json = response.newJsonWriter();
+ json.beginObject();
+ writeComponent(json, session, component, snapshot, userSession);
+
+ if (userSession.hasProjectPermissionByUuid(UserRole.ADMIN, component.projectUuid()) || userSession.hasGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN)) {
+ writeConfiguration(json, component, userSession);
+ }
+
+ writeBreadCrumbs(json, session, component, snapshot);
+ json.endObject().close();
+
+ } finally {
+ session.close();
+ }
+ }
+
+ private void writeComponent(JsonWriter json, DbSession session, ComponentDto component, @Nullable SnapshotDto snapshot, UserSession userSession) {
+
+ json.prop("key", component.key())
+ .prop("uuid", component.uuid())
+ .prop("name", component.name())
+ .prop("isComparable", projectConfiguration.componentTypeHasProperty(component, ComponentConfigurationPages.PROPERTY_COMPARABLE))
+ .prop("canBeFavorite", userSession.isLoggedIn())
+ .prop("isFavorite", isFavourite(session, component, userSession));
+
+ List<DashboardDto> dashboards = activeDashboardDao.selectProjectDashboardsForUserLogin(session, userSession.login());
+ writeDashboards(json, component, dashboards, userSession.locale());
+
+ if (snapshot != null) {
+ json.prop("version", snapshot.getVersion())
+ .prop("date", DateUtils.formatDateTime(new Date(snapshot.getCreatedAt())));
+ String[] availableMeasures = dbClient.measureDao().selectMetricKeysForSnapshot(session, snapshot.getId()).toArray(new String[0]);
+ List<ViewProxy<Page>> pages = views.getPages(NavigationSection.RESOURCE, component.scope(), component.qualifier(), component.language(), availableMeasures);
+ writeExtensions(json, component, pages, userSession.locale());
+ }
+ }
+
+ private boolean isFavourite(DbSession session, ComponentDto component, UserSession userSession) {
+ PropertyQuery propertyQuery = PropertyQuery.builder()
+ .setUserId(userSession.userId())
+ .setKey("favourite")
+ .setComponentId(component.getId())
+ .build();
+ List<PropertyDto> componentFavourites = dbClient.propertiesDao().selectByQuery(propertyQuery, session);
+ return componentFavourites.size() == 1;
+ }
+
+ private void writeExtensions(JsonWriter json, ComponentDto component, List<ViewProxy<Page>> pages, Locale locale) {
+ json.name("extensions").beginArray();
+ for (ViewProxy<Page> page: pages) {
+ writePage(json, getPageUrl(page, component), i18n.message(locale, page.getId() + ".page", page.getTitle()));
+ }
+ json.endArray();
+ }
+
+ private String getPageUrl(ViewProxy<Page> page, ComponentDto component) {
+ String result = null;
+ String componentKey = ComponentConfigurationPages.encodeComponentKey(component);
+ if (page.isController()) {
+ result = String.format("%s?id=%s", page.getId(), componentKey);
+ } else {
+ result = String.format("/plugins/resource/%s?page=%s", componentKey, page.getId());
+ }
+ return result;
+ }
+
+ private void writeDashboards(JsonWriter json, ComponentDto component, List<DashboardDto> dashboards, Locale locale) {
+ json.name("dashboards").beginArray();
+ for (DashboardDto dashboard : dashboards) {
+ json.beginObject()
+ .prop("key", dashboard.getId())
+ .prop("name", i18n.message(locale, String.format("dashboard.%s.name", dashboard.getName()), dashboard.getName()))
+ .endObject();
+ }
+ json.endArray();
+ }
+
+ private void writeConfiguration(JsonWriter json, ComponentDto component, UserSession userSession) {
+ boolean isAdmin = userSession.hasProjectPermissionByUuid(UserRole.ADMIN, component.projectUuid());
+ Locale locale = userSession.locale();
+
+ json.name("configuration").beginArray();
+ for (ConfigPage page : projectConfiguration.getConfigPages(component, userSession)) {
+ page.write(json);
+ }
+
+ if (isAdmin) {
+ List<ViewProxy<Page>> configPages = views.getPages(NavigationSection.RESOURCE_CONFIGURATION, component.scope(), component.qualifier(), component.language(), null);
+ for (ViewProxy<Page> page : configPages) {
+ writePage(json, getPageUrl(page, component), i18n.message(locale, page.getId() + ".page", page.getTitle()));
+ }
+ }
+ json.endArray();
+ }
+
+ private void writePage(JsonWriter json, String url, String name) {
+ json.beginObject()
+ .prop("url", url)
+ .prop("name", name)
+ .endObject();
+ }
+
+ private void writeBreadCrumbs(JsonWriter json, DbSession session, ComponentDto component, @Nullable SnapshotDto snapshot) {
+ json.name("breadcrumbs").beginArray();
+
+ List<ComponentDto> componentPath = Lists.newArrayList(component);
+
+ if (snapshot != null) {
+ SnapshotDto currentSnapshot = snapshot;
+ while (currentSnapshot.getParentId() != null) {
+ currentSnapshot = dbClient.snapshotDao().getByKey(session, currentSnapshot.getParentId());
+ componentPath.add(0, dbClient.componentDao().getById(currentSnapshot.getResourceId(), session));
+ }
+ }
+
+ for (ComponentDto crumbComponent : componentPath) {
+ json.beginObject()
+ .prop("key", crumbComponent.key())
+ .prop("name", crumbComponent.name())
+ .prop("qualifier", crumbComponent.qualifier())
+ .endObject();
+ }
+
+ json.endArray();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.ui.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
--- /dev/null
+{
+ "id": 2865,
+ "key": "org.codehaus.sonar:sonar",
+ "uuid": "69e57151-be0d-4157-adff-c06741d88879",
+ "isComparable": true,
+ "canBeFavorite": true,
+ "isFavorite": true,
+ "version": "5.2-SNAPSHOT",
+ "snapshotDate": "2015-04-16T14:40:32+02:00",
+ "dashboards": [
+ {
+ "key": 1,
+ "name": "Main Dashboard"
+ }
+ ],
+ "extensions": [
+ {
+ "name": "My Resource Plugin",
+ "url": "/plugins/resource/2865?page=my-resource-plugin"
+ }
+ ],
+ "configuration": [
+ {
+ "name": "General Settings",
+ "url": "/project/settings/2865"
+ },
+ {
+ "name": "Action Plans",
+ "url": "/action_plans/index/2865"
+ }
+ ],
+ "breadcrumbs": [
+ {
+ "name": "SonarQube",
+ "qualifier": "TRK",
+ "key": "org.codehaus.sonar:sonar"
+ }
+ ]
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.ui.ws;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.ResourceType;
+import org.sonar.api.resources.ResourceTypes;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.ui.ws.ComponentConfigurationPages.ConfigPage;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.user.UserSession;
+
+import java.util.List;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ComponentConfigurationPagesTest {
+
+ @Mock
+ private I18n i18n;
+
+ @Mock
+ private ResourceTypes resourceTypes;
+
+ @Before
+ public void before() {
+ when(i18n.message(Matchers.any(Locale.class), Matchers.anyString(), Matchers.anyString())).thenAnswer(new Answer<String>() {
+ @Override
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ return invocation.getArgumentAt(1, String.class);
+ }
+ });
+ }
+
+ @Test
+ public void pages_for_project() throws Exception {
+ String uuid = "abcd";
+ ComponentDto component = ComponentTesting.newProjectDto(uuid).setKey("org.codehaus.sonar:sonar");
+ UserSession userSession = MockUserSession.set().setLogin("obiwan").addProjectUuidPermissions(UserRole.ADMIN, uuid);
+
+ List<ConfigPage> pages = new ComponentConfigurationPages(i18n, resourceTypes).getConfigPages(component, userSession);
+ assertThat(pages).extracting("visible").containsExactly(
+ false, true, true, true, true, true, false, false, false, false);
+ assertThat(pages).extracting("url").containsExactly(
+ "/project/settings?id=org.codehaus.sonar%3Asonar",
+ "/project/profile?id=org.codehaus.sonar%3Asonar",
+ "/project/qualitygate?id=org.codehaus.sonar%3Asonar",
+ "/manual_measures/index?id=org.codehaus.sonar%3Asonar",
+ "/action_plans/index?id=org.codehaus.sonar%3Asonar",
+ "/project/links?id=org.codehaus.sonar%3Asonar",
+ "/project_roles/index?id=org.codehaus.sonar%3Asonar",
+ "/project/history?id=org.codehaus.sonar%3Asonar",
+ "/project/key?id=org.codehaus.sonar%3Asonar",
+ "/project/deletion?id=org.codehaus.sonar%3Asonar"
+ );
+ }
+
+ @Test
+ public void pages_for_project_with_resource_type_property() throws Exception {
+ String uuid = "abcd";
+ ComponentDto component = ComponentTesting.newProjectDto(uuid);
+ UserSession userSession = MockUserSession.set().setLogin("obiwan").addProjectUuidPermissions(UserRole.ADMIN, uuid);
+ when(resourceTypes.get(component.qualifier())).thenReturn(
+ ResourceType.builder(component.qualifier()).setProperty("configurable", true).build());
+
+ List<ConfigPage> pages = new ComponentConfigurationPages(i18n, resourceTypes).getConfigPages(component, userSession);
+ assertThat(pages).extracting("visible").containsExactly(
+ true, true, true, true, true, true, false, false, false, false);
+ }
+
+ @Test
+ public void pages_for_module() throws Exception {
+ String uuid = "abcd";
+ ComponentDto project = ComponentTesting.newProjectDto(uuid);
+ ComponentDto module = ComponentTesting.newModuleDto(project);
+ UserSession userSession = MockUserSession.set().setLogin("obiwan").addProjectUuidPermissions(UserRole.ADMIN, uuid);
+
+ List<ConfigPage> pages = new ComponentConfigurationPages(i18n, resourceTypes).getConfigPages(module, userSession);
+ assertThat(pages).extracting("visible").containsExactly(
+ false, false, false, true, false, false, false, false, false, false);
+ }
+
+ @Test
+ public void pages_for_non_admin() throws Exception {
+ String uuid = "abcd";
+ ComponentDto project = ComponentTesting.newProjectDto(uuid);
+ UserSession userSession = MockUserSession.set().setLogin("obiwan").addProjectUuidPermissions(UserRole.USER, uuid);
+
+ List<ConfigPage> pages = new ComponentConfigurationPages(i18n, resourceTypes).getConfigPages(project, userSession);
+ assertThat(pages).extracting("visible").containsExactly(
+ false, true, true, false, false, false, false, false, false, false);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.ui.ws;
+
+import com.google.common.collect.Maps;
+import org.apache.commons.lang.BooleanUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.NavigationSection;
+import org.sonar.api.web.Page;
+import org.sonar.api.web.ResourceLanguage;
+import org.sonar.api.web.ResourceQualifier;
+import org.sonar.api.web.ResourceScope;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.dashboard.ActiveDashboardDao;
+import org.sonar.core.dashboard.ActiveDashboardDto;
+import org.sonar.core.dashboard.DashboardDao;
+import org.sonar.core.dashboard.DashboardDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.properties.PropertiesDao;
+import org.sonar.core.properties.PropertyDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.measure.persistence.MeasureDao;
+import org.sonar.server.ui.Views;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.user.db.UserDao;
+import org.sonar.server.ws.WsTester;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ComponentNavigationActionTest {
+
+ @ClassRule
+ public static final DbTester dbTester = new DbTester();
+
+ private DbSession session;
+
+ private WsTester wsTester;
+
+ private UserDao userDao;
+
+ private DashboardDao dashboardDao;
+
+ private ActiveDashboardDao activeDashboardDao;
+
+ private DbClient dbClient;
+
+ private I18n i18n;
+
+ private ProjectConfigurationPagesStub projectConfigurationPages;
+
+ @Before
+ public void before() throws Exception {
+ dbTester.truncateTables();
+
+ System2 system = mock(System2.class);
+ userDao = new UserDao(dbTester.myBatis(), system);
+ dashboardDao = new DashboardDao(dbTester.myBatis());
+ activeDashboardDao = new ActiveDashboardDao(dbTester.myBatis());
+ dbClient = new DbClient(
+ dbTester.database(), dbTester.myBatis(), userDao, dashboardDao, activeDashboardDao,
+ new ComponentDao(system), new SnapshotDao(system), new PropertiesDao(dbTester.myBatis()),
+ new MeasureDao());
+
+ i18n = mock(I18n.class);
+ when(i18n.message(any(Locale.class), any(String.class), any(String.class)))
+ .thenAnswer(new Answer<String>() {
+ @Override
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ return invocation.getArgumentAt(2, String.class);
+ }
+ });
+
+ projectConfigurationPages = new ProjectConfigurationPagesStub();
+
+ session = dbClient.openSession(false);
+ }
+
+ @After
+ public void after() throws Exception {
+ session.close();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void fail_on_missing_parameters() throws Exception {
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(null, null, null, null, null)));
+
+ wsTester.newGetRequest("api/navigation", "component").execute();
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void fail_on_unexistent_key() throws Exception {
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, null, null, null, null)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute();
+ }
+
+ @Test(expected = ForbiddenException.class)
+ public void fail_on_missing_permission() throws Exception {
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd").setKey("polop"));
+ session.commit();
+
+ MockUserSession.set();
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, null, null, null, null)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute();
+ }
+
+ @Test
+ public void no_snapshot_anonymous() throws Exception {
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop"));
+ session.commit();
+
+ MockUserSession.set().addProjectUuidPermissions(UserRole.USER, "abcd");
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "no_snapshot.json");
+ }
+
+ @Test
+ public void no_snapshot_connected_user_and_favorite() throws Exception {
+ int userId = 42;
+ ComponentDto project = dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop"));
+ dbClient.propertiesDao().setProperty(new PropertyDto().setKey("favourite").setResourceId(project.getId()).setUserId((long) userId), session);
+ session.commit();
+
+ MockUserSession.set().setLogin("obiwan").setUserId(userId).addProjectUuidPermissions(UserRole.USER, "abcd");
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "no_snapshot_user_favourite.json");
+ }
+
+ @Test
+ public void with_snapshot_and_connected_user() throws Exception {
+ Date snapshotDate = DateUtils.parseDateTime("2015-04-22T11:44:00+0200");
+
+ int userId = 42;
+ ComponentDto project = dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop"));
+ dbClient.snapshotDao().insert(session, new SnapshotDto().setCreatedAt(snapshotDate.getTime()).setVersion("3.14")
+ .setLast(true).setQualifier(project.qualifier()).setResourceId(project.getId()).setRootProjectId(project.getId()).setScope(project.scope()));
+ session.commit();
+
+ MockUserSession.set().setLogin("obiwan").setUserId(userId).addProjectUuidPermissions(UserRole.USER, "abcd");
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "with_snapshot_and_connected_user.json");
+ }
+
+ @Test
+ public void with_dashboards() throws Exception {
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop"));
+ DashboardDto dashboard = new DashboardDto().setGlobal(false).setName("Anon Dashboard").setShared(true).setColumnLayout("100%");
+ dashboardDao.insert(dashboard);
+ activeDashboardDao.insert(new ActiveDashboardDto().setDashboardId(dashboard.getId()));
+ session.commit();
+
+ MockUserSession.set().addProjectUuidPermissions(UserRole.USER, "abcd");
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "with_dashboards.json");
+ }
+
+ @Test
+ public void with_extensions() throws Exception {
+ final String language = "xoo";
+ ComponentDto project = dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop").setLanguage(language));
+ dbClient.snapshotDao().insert(session, new SnapshotDto()
+ .setLast(true).setQualifier(project.qualifier()).setResourceId(project.getId()).setRootProjectId(project.getId()).setScope(project.scope()));
+ session.commit();
+
+ MockUserSession.set().addProjectUuidPermissions(UserRole.USER, "abcd");
+
+ @NavigationSection(NavigationSection.RESOURCE)
+ @ResourceScope(Scopes.PROJECT)
+ @ResourceQualifier(Qualifiers.PROJECT)
+ @ResourceLanguage(language)
+ class FirstPage implements Page {
+ @Override
+ public String getTitle() {
+ return "First Page";
+ }
+
+ @Override
+ public String getId() {
+ return "first_page";
+ }
+ }
+ Page page1 = new FirstPage();
+
+ @NavigationSection(NavigationSection.RESOURCE)
+ @ResourceScope(Scopes.PROJECT)
+ @ResourceQualifier(Qualifiers.PROJECT)
+ @ResourceLanguage(language)
+ class SecondPage implements Page {
+ @Override
+ public String getTitle() {
+ return "Second Page";
+ }
+
+ @Override
+ public String getId() {
+ return "/second/page";
+ }
+ }
+ Page page2 = new SecondPage();
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(new Page[] {page1, page2}), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "with_extensions.json");
+ }
+
+ @Test
+ public void with_admin_rights() throws Exception {
+ final String language = "xoo";
+ int userId = 42;
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop").setLanguage(language));
+ session.commit();
+
+ MockUserSession.set().setLogin("obiwan").setUserId(userId)
+ .addProjectUuidPermissions(UserRole.USER, "abcd")
+ .addProjectUuidPermissions(UserRole.ADMIN, "abcd");
+
+ @NavigationSection(NavigationSection.RESOURCE_CONFIGURATION)
+ @ResourceScope(Scopes.PROJECT)
+ @ResourceQualifier(Qualifiers.PROJECT)
+ @ResourceLanguage(language)
+ class FirstPage implements Page {
+ @Override
+ public String getTitle() {
+ return "First Page";
+ }
+
+ @Override
+ public String getId() {
+ return "first_page";
+ }
+ }
+ Page page1 = new FirstPage();
+
+ @NavigationSection(NavigationSection.RESOURCE_CONFIGURATION)
+ @ResourceScope(Scopes.PROJECT)
+ @ResourceQualifier(Qualifiers.PROJECT)
+ @ResourceLanguage(language)
+ class SecondPage implements Page {
+ @Override
+ public String getTitle() {
+ return "Second Page";
+ }
+
+ @Override
+ public String getId() {
+ return "/second/page";
+ }
+ }
+ Page page2 = new SecondPage();
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(new Page[] {page1, page2}), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "with_admin_rights.json");
+ }
+
+ @Test
+ public void with_quality_profile_admin_rights() throws Exception {
+ final String language = "xoo";
+ int userId = 42;
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop").setLanguage(language));
+ session.commit();
+
+ MockUserSession.set().setLogin("obiwan").setUserId(userId)
+ .addProjectUuidPermissions(UserRole.USER, "abcd")
+ .setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+ @NavigationSection(NavigationSection.RESOURCE_CONFIGURATION)
+ class FirstPage implements Page {
+ @Override
+ public String getTitle() {
+ return "First Page";
+ }
+
+ @Override
+ public String getId() {
+ return "first_page";
+ }
+ }
+ Page page = new FirstPage();
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(new Page[] {page}), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "polop").execute().assertJson(getClass(), "quality_profile_admin.json");
+ }
+
+ @Test
+ public void bread_crumbs_on_several_levels() throws Exception {
+ ComponentDto project = ComponentTesting.newProjectDto("abcd")
+ .setKey("polop").setName("Polop");
+ ComponentDto module = ComponentTesting.newModuleDto("bcde", project)
+ .setKey("palap").setName("Palap");
+ ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/xoo");
+ ComponentDto file = ComponentTesting.newFileDto(module, "cdef").setName("Source.xoo")
+ .setKey("palap:src/main/xoo/Source.xoo")
+ .setPath(directory.path());
+ dbClient.componentDao().insert(session, project, module, directory, file);
+
+ SnapshotDto projectSnapshot = dbClient.snapshotDao().insert(session, new SnapshotDto()
+ .setLast(true)
+ .setQualifier(project.qualifier())
+ .setResourceId(project.getId())
+ .setRootProjectId(project.getId())
+ .setScope(project.scope()));
+ SnapshotDto moduleSnapshot = dbClient.snapshotDao().insert(session, new SnapshotDto()
+ .setLast(true)
+ .setQualifier(module.qualifier())
+ .setResourceId(module.getId())
+ .setRootProjectId(project.getId())
+ .setScope(module.scope())
+ .setParentId(projectSnapshot.getId()));
+ SnapshotDto directorySnapshot = dbClient.snapshotDao().insert(session, new SnapshotDto()
+ .setLast(true)
+ .setQualifier(directory.qualifier())
+ .setResourceId(directory.getId())
+ .setRootProjectId(project.getId())
+ .setScope(directory.scope())
+ .setParentId(moduleSnapshot.getId()));
+ dbClient.snapshotDao().insert(session, new SnapshotDto()
+ .setLast(true)
+ .setQualifier(file.qualifier())
+ .setResourceId(file.getId())
+ .setRootProjectId(project.getId())
+ .setScope(file.scope())
+ .setParentId(directorySnapshot.getId()));
+
+ session.commit();
+
+ MockUserSession.set().addProjectUuidPermissions(UserRole.USER, "abcd");
+
+ wsTester = new WsTester(new NavigationWs(new ComponentNavigationAction(dbClient, activeDashboardDao,
+ new Views(), i18n, projectConfigurationPages)));
+
+ wsTester.newGetRequest("api/navigation", "component").setParam("componentKey", "palap:src/main/xoo/Source.xoo").execute().assertJson(getClass(), "breadcrumbs.json");
+ }
+
+ class ProjectConfigurationPagesStub extends ComponentConfigurationPages {
+
+ private Map<String, Boolean> resourceTypeHasProperty;
+
+ public ProjectConfigurationPagesStub() {
+ super(i18n, null);
+ resourceTypeHasProperty = Maps.newHashMap();
+ }
+
+ void setComponentTypeProperty(String resourceTypeProperty, boolean value) {
+ resourceTypeHasProperty.put(resourceTypeProperty, value);
+ }
+
+ @Override
+ boolean componentTypeHasProperty(ComponentDto component, String resourceTypeProperty) {
+ return BooleanUtils.isTrue(resourceTypeHasProperty.get(resourceTypeProperty));
+ }
+
+ @Override
+ List<ConfigPage> getConfigPages(ComponentDto component, UserSession userSession) {
+ return Arrays.asList(
+ new ConfigPage(true, "/visible/page", "Visible Config Page"),
+ new ConfigPage(false, "/invisible/page", "Invisible Config Page"));
+ }
+ }
+}
--- /dev/null
+{
+ "key": "palap:src/main/xoo/Source.xoo",
+ "uuid": "cdef",
+ "name": "Source.xoo",
+ "isComparable": false,
+ "canBeFavorite": false,
+ "isFavorite": false,
+ "dashboards": [],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ },
+ {
+ "key": "palap",
+ "name": "Palap",
+ "qualifier": "BRC"
+ },
+ {
+ "key": "palap:src/main/xoo",
+ "name": "src/main/xoo",
+ "qualifier": "DIR"
+ },
+ {
+ "key": "palap:src/main/xoo/Source.xoo",
+ "name": "Source.xoo",
+ "qualifier": "FIL"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": false,
+ "isFavorite": false,
+ "dashboards": [],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": true,
+ "isFavorite": true,
+ "dashboards": [],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": true,
+ "isFavorite": false,
+ "dashboards": [],
+ "configuration": [
+ {
+ "name": "Visible Config Page",
+ "url": "/visible/page"
+ }
+ ],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": true,
+ "isFavorite": false,
+ "dashboards": [],
+ "configuration": [
+ {
+ "name": "Visible Config Page",
+ "url": "/visible/page"
+ },
+ {
+ "name": "First Page",
+ "url": "/plugins/resource/polop?page=first_page"
+ },
+ {
+ "name": "Second Page",
+ "url": "/second/page?id=polop"
+ }
+ ],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": false,
+ "isFavorite": false,
+ "dashboards": [
+ {
+ "name": "Anon Dashboard"
+ }
+ ],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": false,
+ "isFavorite": false,
+ "dashboards": [],
+ "extensions": [
+ {
+ "name": "First Page",
+ "url": "/plugins/resource/polop?page=first_page"
+ },
+ {
+ "name": "Second Page",
+ "url": "/second/page?id=polop"
+ }
+ ],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
--- /dev/null
+{
+ "key": "polop",
+ "uuid": "abcd",
+ "name": "Polop",
+ "isComparable": false,
+ "canBeFavorite": true,
+ "isFavorite": false,
+ "date": "2015-04-22T11:44:00+0200",
+ "version": "3.14",
+ "dashboards": [],
+ "breadcrumbs": [
+ {
+ "key": "polop",
+ "name": "Polop",
+ "qualifier": "TRK"
+ }
+ ]
+}
}
}
+ public List<DashboardDto> selectProjectDashboardsForUserLogin(@Nullable String login) {
+ SqlSession session = mybatis.openSession(false);
+ try {
+ return selectProjectDashboardsForUserLogin(session, login);
+ } finally {
+ session.close();
+ }
+ }
+
+ public List<DashboardDto> selectProjectDashboardsForUserLogin(SqlSession session, @Nullable String login) {
+ return getMapper(session).selectProjectDashboardsForUserLogin(login);
+ }
+
private ActiveDashboardMapper getMapper(SqlSession session) {
return session.getMapper(ActiveDashboardMapper.class);
}
Integer selectMaxOrderIndexForNullUser();
List<DashboardDto> selectGlobalDashboardsForUserLogin(@Nullable @Param("login") String login);
+
+ List<DashboardDto> selectProjectDashboardsForUserLogin(@Nullable @Param("login") String login);
}
long countByComponentAndMetric(@Param("componentKey") String componentKey, @Param("metricKey") String metricKey);
void insert(MeasureDto measureDto);
+
+ List<String> selectMetricKeysForSnapshot(@Param("snapshotId") long snapshotId);
}
ORDER BY order_index ASC
</select>
+ <select id="selectProjectDashboardsForUserLogin" parameterType="String" resultType="Dashboard">
+ SELECT <include refid="dashboardColumns" />
+ FROM dashboards d
+ INNER JOIN active_dashboards ad on d.id=ad.dashboard_id
+ LEFT OUTER JOIN users u on u.id=ad.user_id
+ WHERE d.is_global=${_false}
+ <choose>
+ <when test="login == null">
+ AND u.login IS NULL
+ </when>
+ <otherwise>
+ AND u.login=#{login}
+ </otherwise>
+ </choose>
+ ORDER BY order_index ASC
+ </select>
+
</mapper>
)
</insert>
+ <select id="selectMetricKeysForSnapshot" parameterType="long" resultType="string">
+ SELECT m.name
+ FROM project_measures pm
+ INNER JOIN metrics m ON m.id=pm.metric_id
+ WHERE pm.snapshot_id=#{snapshotId}
+ </select>
+
</mapper>
assertThat(dao.selectGlobalDashboardsForUserLogin("obiwan")).hasSize(2).extracting("id").containsExactly(2L, 1L);
}
+
+ @Test
+ public void should_get_project_dashboards_for_anonymous() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "shouldSelectProjectDashboardsForAnonymous.xml");
+
+ assertThat(dao.selectProjectDashboardsForUserLogin(null)).hasSize(2).extracting("id").containsExactly(2L, 1L);
+ }
+
+ @Test
+ public void should_get_project_dashboards_for_user() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "shouldSelectProjectDashboardsForUser.xml");
+
+ assertThat(dao.selectProjectDashboardsForUserLogin("obiwan")).hasSize(2).extracting("id").containsExactly(2L, 1L);
+ }
}
--- /dev/null
+<dataset>
+
+ <users id="42" login="obiwan" name="Obiwan" email="obiwan@keno.bi"
+ created_at="1418215735482" updated_at="1418215735482" active="[true]"/>
+
+ <dashboards
+ id="1"
+ user_id="1"
+ name="My Dashboard"
+ description="Dashboard shared by admin"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+ <dashboards
+ id="2"
+ user_id="[null]"
+ name="Default Dashboard"
+ description="Dashboard provided by system"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+ <dashboards
+ id="3"
+ user_id="[null]"
+ name="Project Dashboard"
+ description="Won't appear, global"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[true]"
+ />
+ <dashboards
+ id="4"
+ user_id="[null]"
+ name="User Dashboard"
+ description="Won't appear, not anonymous"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+
+ <!-- Dashboard with ID 1 appears after ID 2 -->
+ <active_dashboards
+ id="1"
+ dashboard_id="1"
+ user_id="[null]"
+ order_index="2"/>
+ <!-- Dashboard with ID 2 appears before ID 1 -->
+ <active_dashboards
+ id="2"
+ dashboard_id="2"
+ user_id="[null]"
+ order_index="1"/>
+ <!-- Dashboard with ID 3 does not appear (global) -->
+ <active_dashboards
+ id="3"
+ dashboard_id="3"
+ user_id="[null]"
+ order_index="1"/>
+ <!-- Dashboard with ID 4 does not appear (not anonymous) -->
+ <active_dashboards
+ id="4"
+ dashboard_id="4"
+ user_id="42"
+ order_index="1"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <users id="24" login="anakin" name="Anakin" email="anakin@skywalk.er"
+ created_at="1418215735482" updated_at="1418215735482" active="[true]"/>
+ <users id="42" login="obiwan" name="Obiwan" email="obiwan@keno.bi"
+ created_at="1418215735482" updated_at="1418215735482" active="[true]"/>
+
+ <dashboards
+ id="1"
+ user_id="1"
+ name="My Dashboard"
+ description="Dashboard shared by admin"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+ <dashboards
+ id="2"
+ user_id="[null]"
+ name="Default Dashboard"
+ description="Dashboard provided by system"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+ <dashboards
+ id="3"
+ user_id="[null]"
+ name="Project Dashboard"
+ description="Won't appear, global"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[true]"
+ />
+ <dashboards
+ id="4"
+ user_id="[null]"
+ name="Anonymous Dashboard"
+ description="Won't appear, anonymous"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+ <dashboards
+ id="5"
+ user_id="[null]"
+ name="Another User Dashboard"
+ description="Won't appear, different user"
+ column_layout="100%"
+ shared="[true]"
+ is_global="[false]"
+ />
+
+ <!-- Dashboard with ID 1 appears after ID 2 -->
+ <active_dashboards
+ id="1"
+ dashboard_id="1"
+ user_id="42"
+ order_index="2"/>
+ <!-- Dashboard with ID 2 appears before ID 1 -->
+ <active_dashboards
+ id="2"
+ dashboard_id="2"
+ user_id="42"
+ order_index="1"/>
+ <!-- Dashboard with ID 3 does not appear (global) -->
+ <active_dashboards
+ id="3"
+ dashboard_id="3"
+ user_id="42"
+ order_index="1"/>
+ <!-- Dashboard with ID 4 does not appear (anonymous) -->
+ <active_dashboards
+ id="4"
+ dashboard_id="4"
+ user_id="[null]"
+ order_index="1"/>
+ <!-- Dashboard with ID 5 does not appear (another user) -->
+ <active_dashboards
+ id="5"
+ dashboard_id="5"
+ user_id="24"
+ order_index="1"/>
+
+</dataset>
private final Map<String, ResourceType> typeByQualifier;
private final Collection<ResourceType> rootTypes;
+ public ResourceTypes() {
+ this(new ResourceTypeTree[0]);
+ }
+
public ResourceTypes(ResourceTypeTree[] trees) {
Preconditions.checkNotNull(trees);