]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10817 replace api/editions/form_data by api/navigation/marketplace
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Wed, 6 Jun 2018 08:39:17 +0000 (10:39 +0200)
committerSonarTech <sonartech@sonarsource.com>
Tue, 12 Jun 2018 18:21:03 +0000 (20:21 +0200)
The private WS becomes public because it is used by the marketplace
page of community edition.

server/sonar-server/src/main/java/org/sonar/server/ui/ws/MarketplaceAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/ui/ws/NavigationWsModule.java
server/sonar-server/src/main/resources/org/sonar/server/ui/ws/marketplace-example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ui/ws/MarketplaceActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/ui/ws/NavigationWsModuleTest.java
server/sonar-web/src/main/js/api/marketplace.ts
server/sonar-web/src/main/js/api/nav.ts
server/sonar-web/src/main/js/apps/marketplace/EditionBoxes.tsx
sonar-ws/src/main/protobuf/ws-navigation.proto [new file with mode: 0644]

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 (file)
index 0000000..9d20353
--- /dev/null
@@ -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);
+    }
+  }
+}
index 8e8f808b937cc666c8a5cc236296b86e42f00a87..a95f55e3ba1fe6d88420431b93442e6ae782190c 100644 (file)
@@ -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 (file)
index 0000000..ef30dae
--- /dev/null
@@ -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 (file)
index 0000000..ece68f0
--- /dev/null
@@ -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));
+  }
+}
index 88c4c74fa04d736b5d60f233af0030ad3dde7b8a..a897416a6c702f9a77615f99be8d0d11bf3e4701 100644 (file)
@@ -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);
   }
 }
index 3f572eaa8cf03ef51875e5cda1a35505dab3cc99..8448d9fbfcb34b52e5f70f77dbb97062f912c240 100644 (file)
@@ -45,7 +45,3 @@ export function showLicense(): Promise<License> {
     return throwGlobalError(e);
   });
 }
-
-export function getFormData(): Promise<{ serverId: string; ncloc: number }> {
-  return getJSON('/api/editions/form_data').catch(throwGlobalError);
-}
index 7dcf404ad711b53b6ede5a9cf4f237e71488eaa0..1313c73972e956327893b1d68d98d0f97d75a1eb 100644 (file)
@@ -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<any> {
   return getJSON('/api/navigation/settings').catch(throwGlobalError);
 }
index a9ee399fffc8a0b9198f170378d2d51024b57bab..6f1064db8491d7ae5d26bc9a8e8ea6d3cca21133 100644 (file)
@@ -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<Props, State> {
 
   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 (file)
index 0000000..0dff573
--- /dev/null
@@ -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;
+}