import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DaoUtils;
import org.sonar.core.persistence.DbSession;
+import org.sonar.server.exceptions.NotFoundException;
@ServerSide
public class CustomMeasureDao implements DaoComponent {
mapper(session).insert(customMeasureDto);
}
+ public void delete(DbSession session, long id) {
+ mapper(session).delete(id);
+ }
+
public void deleteByMetricIds(final DbSession session, final List<Integer> metricIds) {
DaoUtils.executeLargeInputsWithoutOutput(metricIds, new Function<List<Integer>, Void>() {
@Override
return mapper(session).selectById(id);
}
+ public CustomMeasureDto selectById(DbSession session, long id) {
+ CustomMeasureDto customMeasure = selectNullableById(session, id);
+ if (customMeasure == null) {
+ throw new NotFoundException(String.format("CustomMeasure '%d' not found", id));
+ }
+ return customMeasure;
+ }
+
public List<CustomMeasureDto> selectByMetricId(DbSession session, int id) {
return mapper(session).selectByMetricId(id);
}
- public List<CustomMeasureDto> selectByComponentId(DbSession session, int id) {
+ public List<CustomMeasureDto> selectByComponentId(DbSession session, long id) {
return mapper(session).selectByComponentId(id);
}
--- /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.custommeasure.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class CustomMeasuresWs implements WebService {
+ public static final String ENDPOINT = "api/custom_measures";
+
+ private final CustomMeasuresWsAction[] actions;
+
+ public CustomMeasuresWs(CustomMeasuresWsAction... actions) {
+ this.actions = actions;
+ }
+
+ @Override
+ public void define(Context context) {
+ NewController controller = context.createController(ENDPOINT)
+ .setDescription("Custom measures management")
+ .setSince("5.2");
+
+ for (CustomMeasuresWsAction action : actions) {
+ action.define(controller);
+ }
+
+ controller.done();
+ }
+}
--- /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.custommeasure.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface CustomMeasuresWsAction extends WsAction {
+ // marker interface
+}
--- /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.custommeasure.ws;
+
+import org.sonar.core.component.Module;
+
+public class CustomMeasuresWsModule extends Module {
+ @Override
+ protected void configureModule() {
+ add(
+ CustomMeasuresWs.class,
+ DeleteAction.class);
+ }
+}
--- /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.custommeasure.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.custommeasure.db.CustomMeasureDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.user.UserSession;
+
+public class DeleteAction implements CustomMeasuresWsAction {
+
+ private static final String ACTION = "delete";
+ public static final String PARAM_ID = "id";
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+
+ public DeleteAction(DbClient dbClient, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction(ACTION)
+ .setPost(true)
+ .setHandler(this)
+ .setSince("5.2")
+ .setDescription("Delete a custom measure.<br /> Requires 'Administer System' permission or 'Administer' permission on the project.");
+
+ action.createParam(PARAM_ID)
+ .setDescription("Id")
+ .setExampleValue("24")
+ .setRequired(true);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ long id = request.mandatoryParamAsLong(PARAM_ID);
+
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ CustomMeasureDto customMeasure = dbClient.customMeasureDao().selectById(dbSession, id);
+ checkPermissions(dbSession, customMeasure);
+ dbClient.customMeasureDao().delete(dbSession, id);
+ dbSession.commit();
+ } finally {
+ MyBatis.closeQuietly(dbSession);
+ }
+
+ response.noContent();
+ }
+
+ private void checkPermissions(DbSession dbSession, CustomMeasureDto customMeasure) {
+ if (userSession.hasGlobalPermission(GlobalPermissions.SYSTEM_ADMIN)) {
+ return;
+ }
+
+ ComponentDto component = dbClient.componentDao().selectById(customMeasure.getComponentId(), dbSession);
+ userSession.checkLoggedIn().checkProjectUuidPermission(UserRole.ADMIN, component.projectUuid());
+ }
+}
--- /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.custommeasure.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.server.computation.ws.IsQueueEmptyWs;
import org.sonar.server.computation.ws.QueueAction;
import org.sonar.server.config.ws.PropertiesWs;
+import org.sonar.server.custommeasure.ws.CustomMeasuresWsModule;
import org.sonar.server.dashboard.template.GlobalDefaultDashboard;
import org.sonar.server.dashboard.template.ProjectDefaultDashboard;
import org.sonar.server.dashboard.template.ProjectIssuesDashboard;
MeasureFilterFactory.class,
MeasureFilterExecutor.class,
MeasureFilterEngine.class,
+ ManualMeasuresWs.class,
+ MetricsWsModule.class,
+ CustomMeasuresWsModule.class,
ProjectFilter.class,
MyFavouritesFilter.class,
CoreCustomMetrics.class,
DefaultMetricFinder.class,
TimeMachineWs.class,
- ManualMeasuresWs.class,
-
- MetricsWsModule.class,
// quality gates
QualityGateDao.class,
sut.insert(session, newCustomMeasureDto().setComponentId(2));
session.commit();
- List<CustomMeasureDto> result = sut.selectByComponentId(session, 1);
+ List<CustomMeasureDto> result = sut.selectByComponentId(session, 1L);
assertThat(result).hasSize(2);
- assertThat(result).extracting("componentId").containsOnly(1);
-
+ assertThat(result).extracting("componentId").containsOnly(1L);
}
}
--- /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.custommeasure.ws;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CustomMeasuresWsModuleTest {
+ @Test
+ public void verify_count_of_added_components() {
+ ComponentContainer container = new ComponentContainer();
+ new CustomMeasuresWsModule().configure(container);
+ assertThat(container.size()).isEqualTo(4);
+ }
+}
--- /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.custommeasure.ws;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class CustomMeasuresWsTest {
+ WsTester ws;
+
+ @Before
+ public void setUp() {
+ DbClient dbClient = mock(DbClient.class);
+ UserSession userSession = mock(UserSession.class);
+ ws = new WsTester(new CustomMeasuresWs(
+ new DeleteAction(dbClient, userSession)
+ ));
+ }
+
+ @Test
+ public void define_ws() {
+ WebService.Controller controller = ws.controller("api/custom_measures");
+ assertThat(controller).isNotNull();
+ assertThat(controller.description()).isNotEmpty();
+ assertThat(controller.actions()).hasSize(1);
+ }
+
+ @Test
+ public void delete_action_properties() {
+ WebService.Action deleteAction = ws.controller("api/custom_measures").action("delete");
+ assertThat(deleteAction.isPost()).isTrue();
+ }
+}
--- /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.custommeasure.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.custommeasure.db.CustomMeasureDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.custommeasure.persistence.CustomMeasureDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.custommeasure.persistence.CustomMeasureTesting.newCustomMeasureDto;
+import static org.sonar.server.custommeasure.ws.DeleteAction.PARAM_ID;
+
+public class DeleteActionTest {
+
+ public static final String ACTION = "delete";
+
+ @ClassRule
+ public static DbTester db = new DbTester();
+ @Rule
+ public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ WsTester ws;
+ DbClient dbClient;
+ DbSession dbSession;
+
+ @Before
+ public void setUp() {
+ dbClient = new DbClient(db.database(), db.myBatis(), new CustomMeasureDao(), new ComponentDao());
+ dbSession = dbClient.openSession(false);
+ ws = new WsTester(new CustomMeasuresWs(new DeleteAction(dbClient, userSessionRule)));
+ userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ db.truncateTables();
+ }
+
+ @After
+ public void tearDown() {
+ dbSession.close();
+ }
+
+ @Test
+ public void delete_in_db() throws Exception {
+ long id = insertCustomMeasure(newCustomMeasureDto());
+ long anotherId = insertCustomMeasure(newCustomMeasureDto());
+ assertThat(dbClient.customMeasureDao().selectNullableById(dbSession, id)).isNotNull();
+
+ WsTester.Result response = newRequest().setParam(PARAM_ID, String.valueOf(id)).execute();
+ dbSession.commit();
+
+ assertThat(dbClient.customMeasureDao().selectNullableById(dbSession, id)).isNull();
+ assertThat(dbClient.customMeasureDao().selectNullableById(dbSession, anotherId)).isNotNull();
+ response.assertNoContent();
+ }
+
+ @Test
+ public void delete_in_db_when_admin_on_project() throws Exception {
+ ComponentDto project = ComponentTesting.newProjectDto("project-uuid");
+ dbClient.componentDao().insert(dbSession, project);
+ userSessionRule.login("login").addProjectUuidPermissions(UserRole.ADMIN, "project-uuid");
+ long id = insertCustomMeasure(newCustomMeasureDto().setComponentId(project.getId()));
+
+ newRequest().setParam(PARAM_ID, String.valueOf(id)).execute();
+
+ assertThat(dbClient.customMeasureDao().selectNullableById(dbSession, id)).isNull();
+ }
+
+ @Test
+ public void fail_when_not_found_in_db() throws Exception {
+ expectedException.expect(NotFoundException.class);
+
+ newRequest().setParam(PARAM_ID, "42").execute();
+ }
+
+ @Test
+ public void fail_when_insufficient_permissions() throws Exception {
+ expectedException.expect(ForbiddenException.class);
+ userSessionRule.login("login");
+ ComponentDto project = ComponentTesting.newProjectDto("any-uuid");
+ dbClient.componentDao().insert(dbSession, project);
+ long id = insertCustomMeasure(newCustomMeasureDto().setComponentId(project.getId()));
+
+ newRequest().setParam(PARAM_ID, String.valueOf(id)).execute();
+ }
+
+ private long insertCustomMeasure(CustomMeasureDto customMeasure) {
+ dbClient.customMeasureDao().insert(dbSession, customMeasure);
+ dbSession.commit();
+ return customMeasure.getId();
+ }
+
+ private WsTester.TestRequest newRequest() {
+ return ws.newPostRequest(CustomMeasuresWs.ENDPOINT, ACTION);
+ }
+}
public class CustomMeasureDto {
private long id;
private int metricId;
- private int componentId;
+ private long componentId;
private double value;
private String textValue;
private String userLogin;
return this;
}
- public int getComponentId() {
+ public long getComponentId() {
return componentId;
}
- public CustomMeasureDto setComponentId(int resourceId) {
- this.componentId = resourceId;
+ public CustomMeasureDto setComponentId(long componentId) {
+ this.componentId = componentId;
return this;
}
List<CustomMeasureDto> selectByMetricId(int id);
- List<CustomMeasureDto> selectByComponentId(int id);
+ List<CustomMeasureDto> selectByComponentId(long id);
+ void delete(long id);
}
#{metricId}
</foreach>
</delete>
+
+ <delete id="delete">
+ delete from manual_measures
+ where id=#{id}
+ </delete>
</mapper>