]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8363 Mark just created projects as favorite
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 11 Nov 2016 10:38:19 +0000 (11:38 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 14 Nov 2016 10:17:46 +0000 (11:17 +0100)
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java
server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java
server/sonar-server/src/main/java/org/sonar/server/component/FavoriteService.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/queue/ReportSubmitter.java
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/component/FavoriteServiceTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/queue/ReportSubmitterTest.java

index 4bcdb4b567f3482b3b9b4feb793fa91b195ecd0b..6168cbcc12264bfee5d4da2f985e658ee355175e 100644 (file)
@@ -326,7 +326,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
       UserPermissionChanger.class,
       GroupPermissionChanger.class,
 
-
       // components
       ComponentFinder.class, // used in ComponentService
       ComponentService.class, // used in ReportSubmitter
index 2442a85c96f94800be315dbfa5312ab07cae7334..895abe967758be5af7f1c529c26d3e8de3b918db 100644 (file)
@@ -126,13 +126,15 @@ public class ComponentService {
     projectMeasuresIndexer.index(projectUuid);
   }
 
+  // Used by SQ and Governance
   public ComponentDto create(DbSession session, NewComponent newComponent) {
     userSession.checkPermission(GlobalPermissions.PROVISIONING);
     checkKeyFormat(newComponent.qualifier(), newComponent.key());
-    ComponentDto project = createProject(session, newComponent);
-    removeDuplicatedProjects(session, project.getKey());
-    projectMeasuresIndexer.index(project.uuid());
-    return project;
+    ComponentDto rootComponent = createRootComponent(session, newComponent);
+    removeDuplicatedProjects(session, rootComponent.getKey());
+    projectMeasuresIndexer.index(rootComponent.uuid());
+
+    return rootComponent;
   }
 
   /**
@@ -141,10 +143,10 @@ public class ComponentService {
    * No need to remove duplicated components as it's not possible to create the same developer twice in the same time.
    */
   public ComponentDto createDeveloper(DbSession session, NewComponent newComponent) {
-    return createProject(session, newComponent);
+    return createRootComponent(session, newComponent);
   }
 
-  private ComponentDto createProject(DbSession session, NewComponent newComponent) {
+  private ComponentDto createRootComponent(DbSession session, NewComponent newComponent) {
     checkBranchFormat(newComponent.qualifier(), newComponent.branch());
     String keyWithBranch = ComponentKeys.createKey(newComponent.key(), newComponent.branch());
 
index 9c4343aff3dd9f3b1bc5eb9718e6ee3d489bbac2..7f5399a64f723414c5533cdca7035c7aef7cdc71 100644 (file)
@@ -26,6 +26,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.component.Component;
 import org.sonar.api.component.RubyComponentService;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
@@ -40,12 +41,15 @@ public class DefaultRubyComponentService implements RubyComponentService {
   private final ResourceDao resourceDao;
   private final ComponentService componentService;
   private final PermissionTemplateService permissionTemplateService;
+  private final FavoriteService favoriteService;
 
-  public DefaultRubyComponentService(DbClient dbClient, ResourceDao resourceDao, ComponentService componentService, PermissionTemplateService permissionTemplateService) {
+  public DefaultRubyComponentService(DbClient dbClient, ResourceDao resourceDao, ComponentService componentService, PermissionTemplateService permissionTemplateService,
+    FavoriteService favoriteService) {
     this.dbClient = dbClient;
     this.resourceDao = resourceDao;
     this.componentService = componentService;
     this.permissionTemplateService = permissionTemplateService;
+    this.favoriteService = favoriteService;
   }
 
   @Override
@@ -81,6 +85,11 @@ public class DefaultRubyComponentService implements RubyComponentService {
   public long createComponent(DbSession dbSession, String key, @Nullable String branch, String name, @Nullable String qualifier) {
     ComponentDto provisionedComponent = componentService.create(dbSession, NewComponent.create(key, name).setQualifier(qualifier).setBranch(branch));
     permissionTemplateService.applyDefaultPermissionTemplate(dbSession, provisionedComponent.getKey());
+    if (Qualifiers.PROJECT.equals(provisionedComponent.qualifier())) {
+      favoriteService.put(dbSession, provisionedComponent.getId());
+      dbSession.commit();
+    }
+
     return provisionedComponent.getId();
   }
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/FavoriteService.java b/server/sonar-server/src/main/java/org/sonar/server/component/FavoriteService.java
new file mode 100644 (file)
index 0000000..bf1045f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.component;
+
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.user.UserSession;
+
+public class FavoriteService {
+  private static final String PROP_FAVORITE_KEY = "favourite";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+
+  public FavoriteService(DbClient dbClient, UserSession userSession) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+  }
+
+  /**
+   * Set favorite to the logged in user. If no user is logged, no action is done
+   */
+  public void put(DbSession dbSession, long componentDbId) {
+    if (!userSession.isLoggedIn()) {
+      return;
+    }
+
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
+      .setKey(PROP_FAVORITE_KEY)
+      .setResourceId(componentDbId)
+      .setUserId(Long.valueOf(userSession.getUserId())));
+  }
+}
index 81003ce173d0b7ba1f8cd7982e11117e01b12b25..6997d28bf3519f5998c7e509db5b3829955a4332 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.FavoriteService;
 import org.sonar.server.component.NewComponent;
 import org.sonar.server.permission.PermissionTemplateService;
 import org.sonar.server.user.UserSession;
@@ -49,14 +50,16 @@ public class ReportSubmitter {
   private final ComponentService componentService;
   private final PermissionTemplateService permissionTemplateService;
   private final DbClient dbClient;
+  private final FavoriteService favoriteService;
 
   public ReportSubmitter(CeQueue queue, UserSession userSession,
-    ComponentService componentService, PermissionTemplateService permissionTemplateService, DbClient dbClient) {
+                         ComponentService componentService, PermissionTemplateService permissionTemplateService, DbClient dbClient, FavoriteService favoriteService) {
     this.queue = queue;
     this.userSession = userSession;
     this.componentService = componentService;
     this.permissionTemplateService = permissionTemplateService;
     this.dbClient = dbClient;
+    this.favoriteService = favoriteService;
   }
 
   public CeTask submit(String projectKey, @Nullable String projectBranch, @Nullable String projectName, InputStream reportInput) {
@@ -84,8 +87,11 @@ public class ReportSubmitter {
     newProject.setQualifier(Qualifiers.PROJECT);
     // "provisioning" permission is check in ComponentService
     ComponentDto project = componentService.create(dbSession, newProject);
+    favoriteService.put(dbSession, project.getId());
+    dbSession.commit();
 
     permissionTemplateService.applyDefault(dbSession, project, projectCreatorUserId);
+
     return project;
   }
 
index 41f1509dd3b3f17dc402479e2e7de745a3501785..c3c1dba76a9276de7a9911238fd297a2d93657f6 100644 (file)
@@ -149,7 +149,7 @@ public class PermissionTemplateService {
    */
   public void applyDefault(DbSession dbSession, ComponentDto component, @Nullable Long projectCreatorUserId) {
     PermissionTemplateDto template = findDefaultTemplate(dbSession, component);
-    checkArgument(template != null, "Can not retrieve default permission template");
+    checkArgument(template != null, "Cannot retrieve default permission template");
     copyPermissions(dbSession, template, component, projectCreatorUserId);
     dbSession.commit();
     indexProjectPermissions(dbSession, asList(component.uuid()));
index f093c2e6d8bce2acaf1d82941f514685071df9c0..594d98a044edbf52537e6fa5cf7ddb9cc4686b9a 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.ComponentService;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
+import org.sonar.server.component.FavoriteService;
 import org.sonar.server.component.es.ProjectsEsModule;
 import org.sonar.server.component.ws.ComponentsWsModule;
 import org.sonar.server.config.ws.PropertiesWs;
@@ -379,6 +380,7 @@ public class PlatformLevel4 extends PlatformLevel {
       NewAlerts.class,
       NewAlerts.newMetadata(),
       ComponentCleanerService.class,
+      FavoriteService.class,
 
       // views
       ViewIndexDefinition.class,
index f75f6814fa08dfcf3f27577a6d3136cf7cf3d12a..3b7adea5518112eca0de96453bf05a8c83d47563 100644 (file)
@@ -61,19 +61,20 @@ public class DefaultRubyComponentServiceTest {
   @Rule
   public EsTester es = new EsTester(new ProjectMeasuresIndexDefinition(new MapSettings()));
 
-  I18nRule i18n = new I18nRule();
+  private I18nRule i18n = new I18nRule();
 
-  DbClient dbClient = db.getDbClient();
-  DbSession dbSession = db.getSession();
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
 
-  ResourceDao resourceDao = dbClient.resourceDao();
-  ComponentService componentService = new ComponentService(dbClient, i18n, userSession, System2.INSTANCE, new ComponentFinder(dbClient),
+  private ResourceDao resourceDao = dbClient.resourceDao();
+  private ComponentService componentService = new ComponentService(dbClient, i18n, userSession, System2.INSTANCE, new ComponentFinder(dbClient),
     new ProjectMeasuresIndexer(dbClient, es.client()));
-  PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
+  private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
+  private FavoriteService favoriteService = mock(FavoriteService.class);
 
   ComponentDbTester componentDb = new ComponentDbTester(db);
 
-  DefaultRubyComponentService service = new DefaultRubyComponentService(dbClient, resourceDao, componentService, permissionTemplateService);
+  DefaultRubyComponentService service = new DefaultRubyComponentService(dbClient, resourceDao, componentService, permissionTemplateService, favoriteService);
 
   @Test
   public void find_by_key() {
@@ -111,6 +112,7 @@ public class DefaultRubyComponentServiceTest {
     assertThat(project.qualifier()).isEqualTo(qualifier);
     assertThat(project.getId()).isEqualTo(result);
     verify(permissionTemplateService).applyDefaultPermissionTemplate(any(DbSession.class), eq(componentKey));
+    verify(favoriteService).put(any(DbSession.class), eq(project.getId()));
   }
 
   @Test(expected = BadRequestException.class)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/FavoriteServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/FavoriteServiceTest.java
new file mode 100644 (file)
index 0000000..8c5cdaf
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.component;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.property.PropertyQuery;
+import org.sonar.server.tester.UserSessionRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FavoriteServiceTest {
+  private static final long COMPONENT_ID = 23L;
+  private static final long USER_ID = 42L;
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone().login().setUserId((int) USER_ID);
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
+
+  private FavoriteService underTest = new FavoriteService(dbClient, userSession);
+
+  @Test
+  public void put_favorite() {
+    assertNoFavorite();
+
+    underTest.put(dbSession, COMPONENT_ID);
+
+    assertFavorite();
+  }
+
+  @Test
+  public void do_nothing_when_not_logged_in() {
+    userSession.anonymous();
+
+    underTest.put(dbSession, COMPONENT_ID);
+
+    assertNoFavorite();
+  }
+
+  @Test
+  public void put_existing_favorite() {
+    underTest.put(dbSession, COMPONENT_ID);
+    assertFavorite();
+
+    underTest.put(dbSession, COMPONENT_ID);
+
+    assertFavorite();
+  }
+
+  private void assertFavorite() {
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+      .setUserId((int) USER_ID)
+      .setComponentId(COMPONENT_ID)
+      .build(), dbSession)).hasSize(1);
+  }
+
+  private void assertNoFavorite() {
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
+      .setUserId((int) USER_ID)
+      .setComponentId(COMPONENT_ID)
+      .build(), dbSession)).isEmpty();
+  }
+}
index 7367d0d2d21bdfd7782ba1eb382518aa7b485408..d8609659c747d46db132e8695725ab4fcda2eca6 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.db.DbTester;
 import org.sonar.db.ce.CeTaskTypes;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentService;
+import org.sonar.server.component.FavoriteService;
 import org.sonar.server.component.NewComponent;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.permission.PermissionTemplateService;
@@ -73,7 +74,9 @@ public class ReportSubmitterTest {
   private CeQueue queue = mock(CeQueueImpl.class);
   private ComponentService componentService = mock(ComponentService.class);
   private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);
-  private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentService, permissionTemplateService, db.getDbClient());
+  private FavoriteService favoriteService = mock(FavoriteService.class);
+
+  private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentService, permissionTemplateService, db.getDbClient(), favoriteService);
 
   @Test
   public void submit_a_report_on_existing_project() {
@@ -86,6 +89,7 @@ public class ReportSubmitterTest {
 
     verifyReportIsPersisted(TASK_UUID);
     verifyZeroInteractions(permissionTemplateService);
+    verifyZeroInteractions(favoriteService);
     verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
       @Override
       protected boolean matchesSafely(CeTaskSubmit submit) {
@@ -105,7 +109,7 @@ public class ReportSubmitterTest {
     userSession.setGlobalPermissions(SCAN_EXECUTION, PROVISIONING);
 
     when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    ComponentDto createdProject = new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY);
+    ComponentDto createdProject = new ComponentDto().setId(23L).setUuid(PROJECT_UUID).setKey(PROJECT_KEY);
     when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(createdProject);
     when(permissionTemplateService.wouldUserHavePermissionWithDefaultTemplate(any(DbSession.class), anyLong(), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
       .thenReturn(true);
@@ -114,6 +118,7 @@ public class ReportSubmitterTest {
 
     verifyReportIsPersisted(TASK_UUID);
     verify(permissionTemplateService).applyDefault(any(DbSession.class), eq(createdProject), anyLong());
+    verify(favoriteService).put(any(DbSession.class), eq(createdProject.getId()));
     verify(queue).submit(argThat(new TypeSafeMatcher<CeTaskSubmit>() {
       @Override
       protected boolean matchesSafely(CeTaskSubmit submit) {
@@ -133,7 +138,7 @@ public class ReportSubmitterTest {
     userSession.setGlobalPermissions(SCAN_EXECUTION, PROVISIONING);
 
     when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(TASK_UUID));
-    when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
+    when(componentService.create(any(DbSession.class), any(NewComponent.class))).thenReturn(new ComponentDto().setId(23L).setUuid(PROJECT_UUID).setKey(PROJECT_KEY));
     when(permissionTemplateService.wouldUserHavePermissionWithDefaultTemplate(any(DbSession.class), anyLong(), eq(SCAN_EXECUTION), anyString(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT)))
       .thenReturn(true);