From 69feaa8ac907daff9852890d89eb9c8d03889263 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 2 Jun 2014 13:46:19 +0200 Subject: [PATCH] SONAR-5306 Add list of component viewer extensions in /api/component/app WS --- .../sonar/core/component/ComponentDto.java | 21 +++++++ .../core/component/db/ComponentMapper.xml | 2 + .../core/component/ComponentDtoTest.java | 4 ++ .../component/ws/ComponentAppAction.java | 38 ++++++++++++- .../ws/components-app-example-show.json | 3 +- .../persistence/ComponentDaoTest.java | 4 ++ .../component/ws/ComponentAppActionTest.java | 55 ++++++++++++++++++- .../server/component/ws/ComponentsWsTest.java | 3 +- .../persistence/ComponentDaoTest/shared.xml | 6 +- .../app_with_extensions.json | 17 ++++++ 10 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 sonar-server/src/test/resources/org/sonar/server/component/ws/ComponentAppActionTest/app_with_extensions.json diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java index 71b48a6eb3f..a106603b7bf 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java @@ -33,6 +33,8 @@ public class ComponentDto extends Dto implements Component { private String name; private String longName; private String qualifier; + private String scope; + private String language; private Long projectId; private Long subProjectId; @@ -96,6 +98,25 @@ public class ComponentDto extends Dto implements Component { return this; } + public String scope() { + return scope; + } + + public ComponentDto setScope(String scope) { + this.scope = scope; + return this; + } + + @CheckForNull + public String language() { + return language; + } + + public ComponentDto setLanguage(@Nullable String language) { + this.language = language; + return this; + } + public Long projectId() { return projectId; } diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml index 27ab64ac750..a604fea396b 100644 --- a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml @@ -8,6 +8,8 @@ p.name as name, p.long_name as longName, p.qualifier as qualifier, + p.scope as scope, + p.language as language, s.root_project_id as projectId, p.root_id as subProjectId, p.path as path diff --git a/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java b/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java index 1b2ea6a641f..b71779f0e06 100644 --- a/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/component/ComponentDtoTest.java @@ -34,6 +34,8 @@ public class ComponentDtoTest { .setName("RequestContext.java") .setLongName("org.struts.RequestContext") .setQualifier("FIL") + .setScope("FIL") + .setLanguage("java") .setPath("src/org/struts/RequestContext.java") .setProjectId(2L) .setSubProjectId(3L); @@ -43,7 +45,9 @@ public class ComponentDtoTest { assertThat(componentDto.name()).isEqualTo("RequestContext.java"); assertThat(componentDto.longName()).isEqualTo("org.struts.RequestContext"); assertThat(componentDto.qualifier()).isEqualTo("FIL"); + assertThat(componentDto.scope()).isEqualTo("FIL"); assertThat(componentDto.path()).isEqualTo("src/org/struts/RequestContext.java"); + assertThat(componentDto.language()).isEqualTo("java"); assertThat(componentDto.projectId()).isEqualTo(2L); assertThat(componentDto.subProjectId()).isEqualTo(3L); } diff --git a/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java b/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java index 7b74b9549dd..47d8e4daca0 100644 --- a/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java +++ b/sonar-server/src/main/java/org/sonar/server/component/ws/ComponentAppAction.java @@ -35,6 +35,8 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.Durations; 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.measure.db.MeasureDto; @@ -49,6 +51,8 @@ import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.IssueService; import org.sonar.server.issue.RulesAggregation; import org.sonar.server.source.SourceService; +import org.sonar.server.ui.ViewProxy; +import org.sonar.server.ui.Views; import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; @@ -67,14 +71,16 @@ public class ComponentAppAction implements RequestHandler { private final IssueService issueService; private final SourceService sourceService; + private final Views views; private final Periods periods; private final Durations durations; private final I18n i18n; - public ComponentAppAction(DbClient dbClient, IssueService issueService, SourceService sourceService, Periods periods, Durations durations, I18n i18n) { + public ComponentAppAction(DbClient dbClient, IssueService issueService, SourceService sourceService, Views views, Periods periods, Durations durations, I18n i18n) { this.dbClient = dbClient; this.issueService = issueService; this.sourceService = sourceService; + this.views = views; this.periods = periods; this.durations = durations; this.i18n = i18n; @@ -116,6 +122,7 @@ public class ComponentAppAction implements RequestHandler { appendPeriods(json, component.projectId(), session); appendIssuesAggregation(json, component.key(), session); appendMeasures(json, component, session); + appendExtensions(json, component, userSession); } finally { MyBatis.closeQuietly(session); } @@ -228,6 +235,35 @@ public class ComponentAppAction implements RequestHandler { json.endArray(); } + private void appendExtensions(JsonWriter json, ComponentDto component, UserSession userSession) { + List> extensionPages = views.getPages(NavigationSection.RESOURCE_TAB, component.scope(), component.qualifier(), component.language(), null); + List extensions = extensions(extensionPages, component, userSession); + if (!extensions.isEmpty()) { + json.name("extensions").beginArray(); + json.values(extensions); + json.endArray(); + } + } + + private List extensions(List> extensions, ComponentDto component, UserSession userSession){ + List result = newArrayList(); + List providedExtensions = newArrayList("tests_viewer", "coverage", "duplications", "issues", "source"); + for (ViewProxy page : extensions) { + if (!providedExtensions.contains(page.getId())) { + if (page.getUserRoles().length == 0) { + result.add(page.getId()); + } else { + for (String userRole : page.getUserRoles()) { + if (userSession.hasComponentPermission(userRole, component.key())) { + result.add(page.getId()); + } + } + } + } + } + return result; + } + @CheckForNull private Component componentById(@Nullable Long componentId, DbSession session) { if (componentId != null) { diff --git a/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json b/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json index 5798fdac578..a5561d06187 100644 --- a/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json +++ b/sonar-server/src/main/resources/org/sonar/server/component/ws/components-app-example-show.json @@ -45,5 +45,6 @@ "fDebt": "4h", "fIssues": "4", "fInfoIssues": "4" - } + }, + "extensions": ["metricsTab"] } diff --git a/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java b/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java index 2e8f075c82b..9d1cc0fcecf 100644 --- a/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java +++ b/sonar-server/src/test/java/org/sonar/server/component/persistence/ComponentDaoTest.java @@ -56,6 +56,8 @@ public class ComponentDaoTest extends AbstractDaoTestCase { assertThat(result.name()).isEqualTo("RequestContext.java"); assertThat(result.longName()).isEqualTo("org.struts.RequestContext"); assertThat(result.qualifier()).isEqualTo("FIL"); + assertThat(result.scope()).isEqualTo("FIL"); + assertThat(result.language()).isEqualTo("java"); assertThat(result.subProjectId()).isEqualTo(2); assertThat(result.projectId()).isEqualTo(1); @@ -73,6 +75,8 @@ public class ComponentDaoTest extends AbstractDaoTestCase { assertThat(result.name()).isEqualTo("Struts"); assertThat(result.longName()).isEqualTo("Apache Struts"); assertThat(result.qualifier()).isEqualTo("TRK"); + assertThat(result.scope()).isEqualTo("PRJ"); + assertThat(result.language()).isNull(); assertThat(result.subProjectId()).isNull(); assertThat(result.projectId()).isEqualTo(1); } diff --git a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java index 84e20e69d8f..c059072f2d6 100644 --- a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java +++ b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java @@ -34,6 +34,8 @@ import org.sonar.api.measures.CoreMetrics; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.Duration; import org.sonar.api.utils.Durations; +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.measure.db.MeasureDto; @@ -52,6 +54,8 @@ import org.sonar.server.issue.IssueService; import org.sonar.server.issue.RulesAggregation; import org.sonar.server.measure.persistence.MeasureDao; import org.sonar.server.source.SourceService; +import org.sonar.server.ui.ViewProxy; +import org.sonar.server.ui.Views; import org.sonar.server.user.MockUserSession; import org.sonar.server.ws.WsTester; @@ -95,6 +99,9 @@ public class ComponentAppActionTest { @Mock SourceService sourceService; + @Mock + Views views; + @Mock Periods periods; @@ -124,7 +131,7 @@ public class ComponentAppActionTest { when(issueService.findRulesByComponent(anyString(), eq(session))).thenReturn(mock(RulesAggregation.class)); when(measureDao.findByComponentKeyAndMetricKeys(anyString(), anyListOf(String.class), eq(session))).thenReturn(measures); - tester = new WsTester(new ComponentsWs(new ComponentAppAction(dbClient, issueService, sourceService, periods, durations, i18n))); + tester = new WsTester(new ComponentsWs(new ComponentAppAction(dbClient, issueService, sourceService, views, periods, durations, i18n))); } @Test @@ -263,6 +270,18 @@ public class ComponentAppActionTest { request.execute().assertJson(getClass(), "app_with_rules.json"); } + @Test + public void app_with_extensions() throws Exception { + MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, PROJECT_KEY, COMPONENT_KEY); + addComponent(); + + when(views.getPages(anyString(), anyString(), anyString(), anyString(), any(String[].class))).thenReturn( + newArrayList(new ViewProxy(new MyExtension()), new ViewProxy(new MyExtensionWithRole()), new ViewProxy(new ProvidedExtension()))); + + WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY); + request.execute().assertJson(getClass(), "app_with_extensions.json"); + } + private void addComponent() { ComponentDto file = new ComponentDto().setId(10L).setQualifier("FIL").setKey(COMPONENT_KEY).setName("Plugin.java") .setPath("src/main/java/org/sonar/api/Plugin.java").setSubProjectId(5L).setProjectId(1L); @@ -281,4 +300,38 @@ public class ComponentAppActionTest { when(i18n.formatDouble(any(Locale.class), eq(value))).thenReturn(Double.toString(value)); } + @NavigationSection(NavigationSection.RESOURCE_TAB) + private static class MyExtension implements Page { + public String getId() { + return "my-extension"; + } + + public String getTitle() { + return "my-extension"; + } + } + + @NavigationSection(NavigationSection.RESOURCE_TAB) + @UserRole(UserRole.CODEVIEWER) + private static class MyExtensionWithRole implements Page { + public String getId() { + return "my-extension-with-role"; + } + + public String getTitle() { + return "my-extension-with-role"; + } + } + + @NavigationSection(NavigationSection.RESOURCE_TAB) + private static class ProvidedExtension implements Page { + public String getId() { + return "issues"; + } + + public String getTitle() { + return "issues"; + } + } + } diff --git a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java index dc952770f8a..b61e0a2de9f 100644 --- a/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java @@ -30,6 +30,7 @@ import org.sonar.core.timemachine.Periods; import org.sonar.server.db.DbClient; import org.sonar.server.issue.IssueService; import org.sonar.server.source.SourceService; +import org.sonar.server.ui.Views; import org.sonar.server.ws.WsTester; import static org.fest.assertions.Assertions.assertThat; @@ -41,7 +42,7 @@ public class ComponentsWsTest { @Before public void setUp() throws Exception { - WsTester tester = new WsTester(new ComponentsWs(new ComponentAppAction(mock(DbClient.class), mock(IssueService.class), mock(SourceService.class), + WsTester tester = new WsTester(new ComponentsWs(new ComponentAppAction(mock(DbClient.class), mock(IssueService.class), mock(SourceService.class), mock(Views.class), mock(Periods.class), mock(Durations.class), mock(I18n.class)))); controller = tester.controller("api/components"); } diff --git a/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml b/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml index c86f8c33061..05861ec543f 100644 --- a/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml +++ b/sonar-server/src/test/resources/org/sonar/server/component/persistence/ComponentDaoTest/shared.xml @@ -7,7 +7,7 @@ + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"/> + description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]"/> + enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts"/>