From: Simon Brandhof Date: Wed, 6 Jun 2018 08:39:17 +0000 (+0200) Subject: SONAR-10817 replace api/editions/form_data by api/navigation/marketplace X-Git-Tag: 7.5~1003 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=28766a60ff43a9a742f59de7f9c15c05717cb709;p=sonarqube.git SONAR-10817 replace api/editions/form_data by api/navigation/marketplace The private WS becomes public because it is used by the marketplace page of community edition. --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/MarketplaceAction.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/MarketplaceAction.java new file mode 100644 index 00000000000..9d20353d4f8 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/MarketplaceAction.java @@ -0,0 +1,73 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.sonar.api.platform.Server; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.server.user.UserSession; +import org.sonarqube.ws.Navigation; + +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class MarketplaceAction implements NavigationWsAction { + private final UserSession userSession; + private final Server server; + private final DbClient dbClient; + + public MarketplaceAction(UserSession userSession, Server server, DbClient dbClient) { + this.userSession = userSession; + this.server = server; + this.dbClient = dbClient; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("marketplace") + .setSince("7.2") + .setPost(false) + .setDescription("Provide data to prefill license request forms: the server ID and the total number of lines of code.") + .setResponseExample(getClass().getResource("marketplace-example.json")) + .setInternal(true) + .setHandler(this); + } + + @Override + public void handle(Request request, Response response) { + userSession + .checkLoggedIn() + .checkIsSystemAdministrator(); + + Navigation.MarketplaceResponse responsePayload = Navigation.MarketplaceResponse.newBuilder() + .setNcloc(computeNcloc()) + .setServerId(server.getId()) + .build(); + writeProtobuf(responsePayload, request, response); + } + + private long computeNcloc() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.liveMeasureDao().sumNclocOfBiggestLongLivingBranch(dbSession); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/NavigationWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/NavigationWsModule.java index 8e8f808b937..a95f55e3ba1 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/NavigationWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/NavigationWsModule.java @@ -29,6 +29,7 @@ public class NavigationWsModule extends Module { OrganizationAction.class, ComponentAction.class, GlobalAction.class, + MarketplaceAction.class, SettingsAction.class); } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/ui/ws/marketplace-example.json b/server/sonar-server/src/main/resources/org/sonar/server/ui/ws/marketplace-example.json new file mode 100644 index 00000000000..ef30daefc92 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/ui/ws/marketplace-example.json @@ -0,0 +1,4 @@ +{ + "serverId": "AU-Tpxb--iU5OvuD2FLy", + "ncloc": 12345 +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/MarketplaceActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/MarketplaceActionTest.java new file mode 100644 index 00000000000..ece68f09742 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/MarketplaceActionTest.java @@ -0,0 +1,131 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.tngtech.java.junit.dataprovider.DataProviderRunner; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.sonar.api.platform.Server; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.metric.MetricDto; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Navigation; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; +import static org.sonar.api.measures.Metric.ValueType.INT; +import static org.sonar.test.JsonAssert.assertJson; + + +@RunWith(DataProviderRunner.class) +public class MarketplaceActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSessionRule = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private Server server = mock(Server.class); + private DbClient dbClient = db.getDbClient(); + private MarketplaceAction underTest = new MarketplaceAction(userSessionRule, server, dbClient); + + private WsActionTester ws = new WsActionTester(underTest); + + @Test + public void definition() { + WebService.Action def = ws.getDef(); + + assertThat(def.key()).isEqualTo("marketplace"); + assertThat(def.since()).isEqualTo("7.2"); + assertThat(def.isPost()).isFalse(); + assertThat(def.isInternal()).isTrue(); + assertThat(def.description()).isNotEmpty(); + assertThat(def.params()).isEmpty(); + } + + @Test + public void request_fails_if_user_not_logged_in() { + userSessionRule.anonymous(); + TestRequest request = ws.newRequest(); + + expectedException.expect(UnauthorizedException.class); + expectedException.expectMessage("Authentication is required"); + + request.execute(); + } + + @Test + public void request_fails_if_user_is_not_system_administer() { + userSessionRule.logIn(); + TestRequest request = ws.newRequest(); + + expectedException.expect(ForbiddenException.class); + expectedException.expectMessage("Insufficient privileges"); + + request.execute(); + } + + @Test + public void json_example() { + userSessionRule.logIn().setSystemAdministrator(); + when(server.getId()).thenReturn("AU-Tpxb--iU5OvuD2FLy"); + setNcloc(12345L); + + String result = ws.newRequest().execute().getInput(); + + assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString()); + } + + @Test + public void returns_server_id_and_nloc() { + userSessionRule.logIn().setSystemAdministrator(); + when(server.getId()).thenReturn("myserver"); + long ncloc = 256L; + setNcloc(ncloc); + + Navigation.MarketplaceResponse expectedResponse = Navigation.MarketplaceResponse.newBuilder() + .setServerId("myserver") + .setNcloc(ncloc) + .build(); + + Navigation.MarketplaceResponse result = ws.newRequest().executeProtobuf(Navigation.MarketplaceResponse.class); + + assertThat(result).isEqualTo(expectedResponse); + } + + private void setNcloc(double ncloc) { + ComponentDto project = db.components().insertMainBranch(); + MetricDto nclocMetric = db.measures().insertMetric(m -> m.setValueType(INT.toString()).setKey(NCLOC_KEY)); + db.measures().insertLiveMeasure(project, nclocMetric, m -> m.setValue(ncloc)); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java index 88c4c74fa04..a897416a6c7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java @@ -30,6 +30,6 @@ public class NavigationWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new NavigationWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 6); } } diff --git a/server/sonar-web/src/main/js/api/marketplace.ts b/server/sonar-web/src/main/js/api/marketplace.ts index 3f572eaa8cf..8448d9fbfcb 100644 --- a/server/sonar-web/src/main/js/api/marketplace.ts +++ b/server/sonar-web/src/main/js/api/marketplace.ts @@ -45,7 +45,3 @@ export function showLicense(): Promise { return throwGlobalError(e); }); } - -export function getFormData(): Promise<{ serverId: string; ncloc: number }> { - return getJSON('/api/editions/form_data').catch(throwGlobalError); -} diff --git a/server/sonar-web/src/main/js/api/nav.ts b/server/sonar-web/src/main/js/api/nav.ts index 7dcf404ad71..1313c73972e 100644 --- a/server/sonar-web/src/main/js/api/nav.ts +++ b/server/sonar-web/src/main/js/api/nav.ts @@ -31,6 +31,10 @@ export function getComponentNavigation( return getJSON('/api/navigation/component', data).catch(throwGlobalError); } +export function getMarketplaceNavigation(): Promise<{ serverId: string; ncloc: number }> { + return getJSON('/api/navigation/marketplace').catch(throwGlobalError); +} + export function getSettingsNavigation(): Promise { return getJSON('/api/navigation/settings').catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx b/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx index a9ee399fffc..6f1064db849 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx @@ -21,7 +21,7 @@ import * as React from 'react'; import EditionBox from './components/EditionBox'; import { EDITIONS, EditionKey } from './utils'; -import { getFormData } from '../../api/marketplace'; +import { getMarketplaceNavigation } from '../../api/nav'; export interface Props { currentEdition?: EditionKey; @@ -38,15 +38,15 @@ export default class EditionBoxes extends React.PureComponent { componentDidMount() { this.mounted = true; - this.fetchFormData(); + this.fetchData(); } componentWillUnmount() { this.mounted = false; } - fetchFormData = () => { - getFormData().then( + fetchData = () => { + getMarketplaceNavigation().then( formData => { if (this.mounted) { this.setState({ ...formData }); diff --git a/sonar-ws/src/main/protobuf/ws-navigation.proto b/sonar-ws/src/main/protobuf/ws-navigation.proto new file mode 100644 index 00000000000..0dff573ce4d --- /dev/null +++ b/sonar-ws/src/main/protobuf/ws-navigation.proto @@ -0,0 +1,17 @@ +// Copyright (C) 2018-2018 SonarSource SA +// All rights reserved +// mailto:info AT sonarsource DOT com +syntax = "proto2"; + +package sonarqube.ws.navigation; + +option java_package = "org.sonarqube.ws"; +option java_outer_classname = "Navigation"; + +option optimize_for = SPEED; + +// POST api/navigation/marketplace +message MarketplaceResponse { + optional string serverId = 1; + optional int64 ncloc = 2; +}