The private WS becomes public because it is used by the marketplace page of community edition.tags/7.5
@@ -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); | |||
} | |||
} | |||
} |
@@ -29,6 +29,7 @@ public class NavigationWsModule extends Module { | |||
OrganizationAction.class, | |||
ComponentAction.class, | |||
GlobalAction.class, | |||
MarketplaceAction.class, | |||
SettingsAction.class); | |||
} | |||
} |
@@ -0,0 +1,4 @@ | |||
{ | |||
"serverId": "AU-Tpxb--iU5OvuD2FLy", | |||
"ncloc": 12345 | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} |
@@ -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 }); |
@@ -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; | |||
} |