]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5614 Create project permissions and synchronize project issues
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 15 Sep 2014 11:47:56 +0000 (13:47 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 15 Sep 2014 11:47:56 +0000 (13:47 +0200)
16 files changed:
server/sonar-server/src/main/java/org/sonar/server/batch/BatchWs.java
server/sonar-server/src/main/java/org/sonar/server/batch/UploadReportAction.java
server/sonar-server/src/main/java/org/sonar/server/db/BaseDao.java
server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java
server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionTemplateService.java
server/sonar-server/src/test/java/org/sonar/server/batch/BatchWsTest.java
server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/InternalPermissionTemplateServiceTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/find_after_dates_with_project.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java
sonar-core/src/main/java/org/sonar/core/permission/PermissionFacade.java
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml

index 99fa1ac21e0bc95c75d414f0ed0728a3f46df1ca..ec85d3495b1c89b157fd8f7365a398702f98bb5a 100644 (file)
@@ -30,6 +30,8 @@ import java.io.IOException;
 
 public class BatchWs implements WebService {
 
+  public static final String API_ENDPOINT = "batch";
+
   private final BatchIndex batchIndex;
   private final GlobalReferentialsAction globalReferentialsAction;
   private final ProjectReferentialsAction projectReferentialsAction;
@@ -45,7 +47,7 @@ public class BatchWs implements WebService {
 
   @Override
   public void define(Context context) {
-    NewController controller = context.createController("batch")
+    NewController controller = context.createController(API_ENDPOINT)
       .setSince("4.4")
       .setDescription("Get JAR files and referentials for batch");
 
index 32846ef36e901dcb913e57206811edcc77484f29..e2b2ccf791729079d6881e0f0cc845aed058032a 100644 (file)
 
 package org.sonar.server.batch;
 
+import com.google.common.collect.ImmutableMap;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.core.component.AuthorizedComponentDto;
+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.issue.index.IssueIndex;
+import org.sonar.server.permission.InternalPermissionService;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.user.UserSession;
 
 public class UploadReportAction implements RequestHandler {
 
-  private static final String PARAM_PROJECT = "project";
-  private static final String PARAM_FIRST_ANALYSIS = "firstAnalysis";
+  public static final String UPLOAD_REPORT_ACTION = "upload_report";
+
+  static final String PARAM_PROJECT = "project";
+  static final String PARAM_FIRST_ANALYSIS = "firstAnalysis";
 
   private final DbClient dbClient;
+  private final IndexClient index;
+  private final InternalPermissionService permissionService;
 
-  public UploadReportAction(DbClient dbClient) {
+  public UploadReportAction(DbClient dbClient, IndexClient index, InternalPermissionService permissionService) {
     this.dbClient = dbClient;
+    this.index = index;
+    this.permissionService = permissionService;
   }
 
   void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("upload_report")
+    WebService.NewAction action = controller.createAction(UPLOAD_REPORT_ACTION)
       .setDescription("Update analysis report")
       .setSince("5.0")
       .setPost(true)
@@ -64,7 +77,24 @@ public class UploadReportAction implements RequestHandler {
   public void handle(Request request, Response response) throws Exception {
     DbSession session = dbClient.openSession(false);
     try {
-      // TODO
+      String projectKey = request.mandatoryParam(PARAM_PROJECT);
+      AuthorizedComponentDto project = dbClient.componentDao().getAuthorizedComponentByKey(projectKey, session);
+
+      // Create permission on project
+      boolean isFirstAnalysis = request.mandatoryParamAsBoolean(PARAM_FIRST_ANALYSIS);
+      if (isFirstAnalysis) {
+        permissionService.applyDefaultPermissionTemplate(session, project);
+        session.commit();
+      }
+
+      UserSession.get().checkGlobalPermission(GlobalPermissions.SCAN_EXECUTION);
+
+      // Index project's issues
+      dbClient.issueDao().synchronizeAfter(session,
+        index.get(IssueIndex.class).getLastSynchronization(),
+        ImmutableMap.of("project", projectKey));
+      session.commit();
+
     } finally {
       MyBatis.closeQuietly(session);
     }
index bb42fa775c19659bb6b456a8815e52793a93f342..08d9f0f2153ca24dc2a4840702e80fc942902882 100644 (file)
@@ -299,9 +299,14 @@ public abstract class BaseDao<MAPPER, DTO extends Dto<KEY>, KEY extends Serializ
     }
   }
 
+  @VisibleForTesting
+  public List<DTO> findAfterDate(final DbSession session, Date date, Map<String, String> params) {
+    return session.selectList(getSynchronizeStatementFQN(), getSynchronizationParams(date, params));
+  }
+
   @VisibleForTesting
   public List<DTO> findAfterDate(final DbSession session, Date date) {
-    return session.selectList(getSynchronizeStatementFQN(), getSynchronizationParams(date));
+    return findAfterDate(session, date, Collections.<String, String>emptyMap());
   }
 
   // Synchronization methods
index e37624bdf6b67bce3386583d585bbbb416d782e0..86cef1b1eff23a6f5b4404ea9a5f6bf464106195 100644 (file)
@@ -29,8 +29,13 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.BaseDao;
 import org.sonar.server.search.IndexDefinition;
 
+import java.util.Date;
+import java.util.Map;
+
 public class IssueDao extends BaseDao<IssueMapper, IssueDto, String> implements DaoComponent {
 
+  public static final String PROJECT_KEY = "project";
+
   public IssueDao() {
     this(System2.INSTANCE);
   }
@@ -59,9 +64,15 @@ public class IssueDao extends BaseDao<IssueMapper, IssueDto, String> implements
     return issue;
   }
 
-
   @Override
   protected String getSynchronizationStatementName() {
     return "selectAfterDate";
   }
+
+  @Override
+  protected Map getSynchronizationParams(Date date, Map<String, String> params) {
+    Map<String, Object> finalParams = super.getSynchronizationParams(date, params);
+    finalParams.put(PROJECT_KEY, params.get(PROJECT_KEY));
+    return finalParams;
+  }
 }
index 012a77cb2692216a7819113f06218f8589622948..22a34d2f8656e41a32ccc7b7601328dbfcaa9501 100644 (file)
@@ -116,14 +116,18 @@ public class InternalPermissionService implements ServerComponent {
         UserSession.get().checkGlobalPermission(GlobalPermissions.PROVISIONING);
       }
 
-      permissionFacade.grantDefaultRoles(session, component.getId(), component.qualifier());
-      synchronizePermissions(session, componentKey);
+      applyDefaultPermissionTemplate(session, component);
       session.commit();
     } finally {
       session.close();
     }
   }
 
+  public void applyDefaultPermissionTemplate(DbSession session, AuthorizedComponentDto component) {
+    permissionFacade.grantDefaultRoles(session, component.getId(), component.qualifier());
+    synchronizePermissions(session, component.key());
+  }
+
   public void applyPermissionTemplate(Map<String, Object> params) {
     UserSession.get().checkLoggedIn();
 
@@ -272,8 +276,8 @@ public class InternalPermissionService implements ServerComponent {
   }
 
   private void synchronizePermissions(DbSession session, String projectKey) {
-      dbClient.issueAuthorizationDao().synchronizeAfter(session,
-        index.get(IssueAuthorizationIndex.class).getLastSynchronization(),
-        ImmutableMap.of(IssueAuthorizationDao.PROJECT_KEY, projectKey));
+    dbClient.issueAuthorizationDao().synchronizeAfter(session,
+      index.get(IssueAuthorizationIndex.class).getLastSynchronization(),
+      ImmutableMap.of(IssueAuthorizationDao.PROJECT_KEY, projectKey));
   }
 }
index 97b1798ada7db32a65cdbf2665d933039c33f5e9..e089b2abd393c492e4643843cda167c20788779e 100644 (file)
@@ -23,13 +23,16 @@ package org.sonar.server.permission;
 import com.google.common.collect.Lists;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.permission.PermissionTemplateDao;
 import org.sonar.core.permission.PermissionTemplateDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.properties.PropertyDto;
 import org.sonar.core.user.GroupDto;
 import org.sonar.core.user.UserDao;
+import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.user.UserSession;
@@ -47,12 +50,15 @@ import java.util.regex.PatternSyntaxException;
  */
 public class InternalPermissionTemplateService implements ServerComponent {
 
+  private final DbClient db;
+
   private final MyBatis myBatis;
   private final PermissionTemplateDao permissionTemplateDao;
   private final UserDao userDao;
   private final PermissionFinder finder;
 
-  public InternalPermissionTemplateService(MyBatis myBatis, PermissionTemplateDao permissionTemplateDao, UserDao userDao, PermissionFinder finder) {
+  public InternalPermissionTemplateService(DbClient db, MyBatis myBatis, PermissionTemplateDao permissionTemplateDao, UserDao userDao, PermissionFinder finder) {
+    this.db = db;
     this.myBatis = myBatis;
     this.permissionTemplateDao = permissionTemplateDao;
     this.userDao = userDao;
@@ -110,6 +116,20 @@ public class InternalPermissionTemplateService implements ServerComponent {
     permissionTemplateDao.deletePermissionTemplate(templateId);
   }
 
+  public void updateDefaultTemplate(String permissionTemplateKey, String qualifier){
+    if (Qualifiers.PROJECT.equals(qualifier)) {
+      saveProperty("sonar.permission.template.default", permissionTemplateKey);
+    }
+    saveProperty("sonar.permission." + qualifier + ".default", permissionTemplateKey);
+  }
+
+  private void saveProperty(String propertyKey, String value){
+    PropertyDto property = new PropertyDto()
+      .setKey(propertyKey)
+      .setValue(value);
+    db.propertiesDao().setProperty(property);
+  }
+
   public void addUserPermission(String templateKey, String permission, String userLogin) {
     PermissionTemplateUpdater updater = new PermissionTemplateUpdater(templateKey, permission, userLogin, permissionTemplateDao, userDao) {
       @Override
index 1373d8468a691f0b393a48e5ff7a287f46f9abdf..faecc1be4ee02f68c9c927b49e10ec9199c858ff 100644 (file)
@@ -31,9 +31,11 @@ import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.resources.Languages;
 import org.sonar.core.properties.PropertiesDao;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.permission.InternalPermissionService;
 import org.sonar.server.qualityprofile.QProfileFactory;
 import org.sonar.server.qualityprofile.QProfileLoader;
 import org.sonar.server.rule.RuleService;
+import org.sonar.server.search.IndexClient;
 import org.sonar.server.ws.WsTester;
 
 import java.io.File;
@@ -63,7 +65,7 @@ public class BatchWsTest {
       new GlobalReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class)),
       new ProjectReferentialsAction(mock(DbClient.class), mock(PropertiesDao.class), mock(QProfileFactory.class), mock(QProfileLoader.class), mock(RuleService.class),
         mock(Languages.class)),
-      new UploadReportAction(mock(DbClient.class))));
+      new UploadReportAction(mock(DbClient.class), mock(IndexClient.class), mock(InternalPermissionService.class))));
   }
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java
new file mode 100644 (file)
index 0000000..f88a3c8
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.batch;
+
+import org.elasticsearch.index.query.QueryBuilders;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.permission.PermissionQuery;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.component.SnapshotTesting;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.issue.index.IssueAuthorizationIndex;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.permission.PermissionFinder;
+import org.sonar.server.platform.Platform;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.search.SearchClient;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class UploadReportActionMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester();
+
+  DbClient db;
+  DbSession session;
+
+  WsTester wsTester;
+  BatchWs ws;
+  WebService.Controller controller;
+
+  @Before
+  public void setUp() throws Exception {
+    tester.clearDbAndIndexes();
+
+    db = tester.get(DbClient.class);
+    session = db.openSession(false);
+
+    ws = tester.get(BatchWs.class);
+    wsTester = tester.get(WsTester.class);
+    controller = wsTester.controller(BatchWs.API_ENDPOINT);
+  }
+
+  @After
+  public void after() {
+    session.close();
+  }
+
+  @Test
+  public void define() throws Exception {
+    WebService.Action restoreProfiles = controller.action(UploadReportAction.UPLOAD_REPORT_ACTION);
+    assertThat(restoreProfiles).isNotNull();
+    assertThat(restoreProfiles.params()).hasSize(2);
+  }
+
+  @Test
+  public void create_project_permission_on_first_analysis() throws Exception {
+    // Execute startup task to create default permission template
+    tester.get(Platform.class).executeStartupTasks();
+
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setKey("MyProject")
+      .setProjectId(1L);
+    db.componentDao().insert(session, project);
+    session.commit();
+
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    // Project has no user permission
+    assertThat(tester.get(PermissionFinder.class).findGroupsWithPermission(PermissionQuery.builder().component(project.key()).permission(UserRole.USER).build()).groups().get(0).hasPermission()).isFalse();
+
+    WsTester.TestRequest request = wsTester.newGetRequest(BatchWs.API_ENDPOINT, UploadReportAction.UPLOAD_REPORT_ACTION);
+    request.setParam(UploadReportAction.PARAM_PROJECT, project.key());
+    request.setParam(UploadReportAction.PARAM_FIRST_ANALYSIS, "true");
+    request.execute();
+
+    // Check that user permission group have been affected to the project
+    assertThat(tester.get(PermissionFinder.class).findGroupsWithPermission(PermissionQuery.builder().component(project.key()).permission(UserRole.USER).build()).groups()).hasSize(1);
+    assertThat(tester.get(PermissionFinder.class).findGroupsWithPermission(PermissionQuery.builder().component(project.key()).permission(UserRole.USER).build()).groups().get(0).hasPermission()).isTrue();
+
+    // Check that issue authorization index has been created
+    assertThat(tester.get(IssueAuthorizationIndex.class).getByKey(project.getKey())).isNotNull();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_without_global_scan_permission() throws Exception {
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setKey("MyProject")
+      .setProjectId(1L);
+    db.componentDao().insert(session, project);
+    session.commit();
+
+    MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.USER, project.key());
+
+    WsTester.TestRequest request = wsTester.newGetRequest(BatchWs.API_ENDPOINT, UploadReportAction.UPLOAD_REPORT_ACTION);
+    request.setParam(UploadReportAction.PARAM_PROJECT, project.key());
+    request.execute();
+  }
+
+  @Test
+  public void index_project_issues() throws Exception {
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setKey("MyProject")
+      .setProjectId(1L);
+    db.componentDao().insert(session, project);
+
+    ComponentDto resource = new ComponentDto()
+      .setProjectId(1L)
+      .setKey("MyComponent")
+      .setId(2L);
+    db.componentDao().insert(session, resource);
+    db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource));
+
+    RuleDto rule = RuleTesting.newXooX1();
+    tester.get(RuleDao.class).insert(session, rule);
+
+    IssueDto issue = new IssueDto()
+      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
+      .setIssueUpdateDate(DateUtils.parseDate("2014-12-04"))
+      .setRule(rule)
+      .setDebt(10L)
+      .setRootComponent(project)
+      .setComponent(resource)
+      .setStatus("OPEN").setResolution("OPEN")
+      .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
+      .setSeverity("MAJOR");
+    db.issueDao().insert(session, issue);
+
+    session.commit();
+
+    // Clear issue index to simulate that the issue has been inserted by the batch, so that it's not yet index in E/S
+    clearIssueIndex();
+    assertThat(db.issueDao().getByKey(session, issue.getKey())).isNotNull();
+    assertThat(tester.get(IssueIndex.class).getByKey(issue.getKey())).isNull();
+
+    MockUserSession.set().setLogin("john").setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION);
+
+    WsTester.TestRequest request = wsTester.newGetRequest(BatchWs.API_ENDPOINT, UploadReportAction.UPLOAD_REPORT_ACTION);
+    request.setParam(UploadReportAction.PARAM_PROJECT, project.key());
+    request.execute();
+
+    // Check that the issue has well be indexed in E/S
+    assertThat(tester.get(IssueIndex.class).getByKey(issue.getKey())).isNotNull();
+  }
+
+  private void clearIssueIndex(){
+    tester.get(SearchClient.class).prepareDeleteByQuery(tester.get(SearchClient.class).admin().cluster().prepareState().get()
+      .getState().getMetaData().concreteIndices(new String[]{IndexDefinition.ISSUES.getIndexName()}))
+      .setQuery(QueryBuilders.matchAllQuery())
+      .get();
+  }
+
+}
index 66e3c2ed6b401fa43b3b78f8bac985165e71ac2a..44d4efb6b31cf8dc010caaf028b3c5173aa69d1d 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.issue.db;
 
+import com.google.common.collect.ImmutableMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -60,4 +61,11 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     Date t2014 = DateUtils.parseDate("2014-01-01");
     assertThat(dao.findAfterDate(session, t2014)).hasSize(1);
   }
+
+  @Test
+  public void find_after_dates_with_project() throws Exception {
+    setupData("shared", "find_after_dates_with_project");
+
+    assertThat(dao.findAfterDate(session, DateUtils.parseDate("2014-01-01"), ImmutableMap.of("project", "struts"))).hasSize(1);
+  }
 }
index fe69a4619ee084f47f1eb21fb878f7e90d286252..fb8d9428188ebf2b4309abc81a27d7ae5b84e189 100644 (file)
@@ -73,11 +73,7 @@ public class IssuesWsMediumTest {
 
   @Test
   public void define() throws Exception {
-
-    WebService.Context context = new WebService.Context();
-    ws.define(context);
-
-    WebService.Controller controller = context.controller(IssuesWs.API_ENDPOINT);
+    WebService.Controller controller = wsTester.controller(IssuesWs.API_ENDPOINT);
 
     assertThat(controller).isNotNull();
     assertThat(controller.actions()).hasSize(14);
index 03a3b769f8de47b8e1bd2417e48152431e077ddc..1f176312171581896064ccb14023c32a0cc2f3ba 100644 (file)
@@ -542,11 +542,9 @@ public class InternalPermissionServiceTest {
     final long componentId = 1234l;
     final String qualifier = Qualifiers.PROJECT;
 
-    ComponentDto mockComponent = mock(ComponentDto.class);
-    when(mockComponent.getId()).thenReturn(componentId);
-    when(mockComponent.qualifier()).thenReturn(qualifier);
+    ComponentDto project = new ComponentDto().setId(componentId).setKey(componentKey).setQualifier(qualifier);
 
-    when(componentDao.getAuthorizedComponentByKey(componentKey, session)).thenReturn(mockComponent);
+    when(componentDao.getAuthorizedComponentByKey(componentKey, session)).thenReturn(project);
     when(resourceDao.selectProvisionedProject(session, componentKey)).thenReturn(mock(ResourceDto.class));
     service.applyDefaultPermissionTemplate(componentKey);
 
index c50acc616048d7cc3f4e1a7b3f7e7fcbe3863ea3..661fe9aeb9a37cab09275d2f7df1dd2ebc69d77c 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.user.GroupDto;
 import org.sonar.core.user.UserDao;
 import org.sonar.core.user.UserDto;
+import org.sonar.server.db.DbClient;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.user.MockUserSession;
 
@@ -66,6 +67,9 @@ public class InternalPermissionTemplateServiceTest {
   @Mock
   DbSession session;
 
+  @Mock
+  DbClient db;
+
   InternalPermissionTemplateService service;
 
   @Rule
@@ -77,7 +81,7 @@ public class InternalPermissionTemplateServiceTest {
 
     MyBatis myBatis = mock(MyBatis.class);
     when(myBatis.openSession(false)).thenReturn(session);
-    service = new InternalPermissionTemplateService(myBatis, permissionTemplateDao, userDao, finder);
+    service = new InternalPermissionTemplateService(db, myBatis, permissionTemplateDao, userDao, finder);
   }
 
   @Test
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/find_after_dates_with_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/find_after_dates_with_project.xml
new file mode 100644 (file)
index 0000000..b8ffad1
--- /dev/null
@@ -0,0 +1,105 @@
+<!--
+  ~ 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.
+  -->
+
+<dataset>
+
+  <projects id="1000" kee="other" root_id="[null]" qualifier="TRK" scope="PRJ"/>
+
+  <snapshots id="1000" project_id="1000" root_snapshot_id="[null]" parent_snapshot_id="[null]" root_project_id="1000"
+             path="" islast="[true]"/>
+
+  <!-- On struts project -->
+  <issues
+          id="100"
+          kee="ABCDE-1"
+          component_id="399"
+          root_component_id="399"
+          rule_id="500"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          issue_creation_date="2013-04-16"
+          issue_update_date="2013-04-16"
+          issue_close_date="2013-04-16"
+          created_at="2013-04-16"
+          updated_at="2013-04-16"
+          />
+
+  <issues
+          id="101"
+          kee="ABCDE-2"
+          component_id="399"
+          root_component_id="399"
+          rule_id="500"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          issue_creation_date="2013-04-16"
+          issue_update_date="2013-04-16"
+          issue_close_date="2013-04-16"
+          created_at="2013-04-16"
+          updated_at="2014-04-16"
+          />
+
+
+  <!-- On other project -->
+  <issues
+          id="102"
+          kee="ABCDE-3"
+          component_id="1000"
+          root_component_id="1000"
+          rule_id="501"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          issue_creation_date="2014-04-16"
+          issue_update_date="2014-04-16"
+          issue_close_date="2014-04-16"
+          created_at="2014-04-16"
+          updated_at="2014-04-16"
+          />
+</dataset>
index d89868867c75c6e2903c45a42acd102c144becf1..e09a68c166957238984d40e7e0160af8bc274c0d 100644 (file)
@@ -59,5 +59,5 @@ public interface IssueMapper {
 
   int updateIfBeforeSelectedDate(IssueDto issue);
 
-  List<IssueDto> selectAfterDate(Timestamp timestamp);
+  List<IssueDto> selectAfterDate(@Param("date") Timestamp timestamp, @Nullable @Param("project") String project);
 }
index b2552d5043ecab0ce0e43262b991beed81b9e99a..6bf273c5176086efd6206e61d499aa7ffca9b6b3 100644 (file)
@@ -183,11 +183,11 @@ public class PermissionFacade implements TaskComponent, ServerComponent {
     roleDao.deleteUserRolesByResourceId(resourceId, session);
   }
 
-  public List<String> selectGroupPermissions(DbSession session, String group, Long componentId) {
+  public List<String> selectGroupPermissions(DbSession session, String group, @Nullable Long componentId) {
     return roleDao.selectGroupPermissions(session, group, componentId);
   }
 
-  public List<String> selectUserPermissions(DbSession session, String user, Long componentId) {
+  public List<String> selectUserPermissions(DbSession session, String user, @Nullable Long componentId) {
     return roleDao.selectUserPermissions(session, user, componentId);
   }
 
index 9d22edf886ed1ce6ac830cf34c210d7c91a68741..76fb97eaadf3bbf17de4af23d561a28d131bdc76 100644 (file)
           fetchSize="2000"
           statementType="PREPARED"
           resultSetType="FORWARD_ONLY">
-  select
-    <include refid="issueColumns"/>
+    select <include refid="issueColumns"/>
     from issues i
     inner join rules r on r.id=i.rule_id
     inner join projects p on p.id=i.component_id
     inner join projects root on root.id=i.root_component_id
-    where i.updated_at IS NULL or i.updated_at &gt;= #{date}
+    <where>
+    i.updated_at IS NULL or i.updated_at &gt;= #{date}
+    <if test="project != null">
+      and root.kee = #{project}
+    </if>
+    </where>
   </select>
 
   <select id="selectNonClosedIssuesByModule" parameterType="int" resultType="Issue">