Merge "Remove unused value assignments"
diff --git a/java/com/google/gerrit/common/data/GlobalCapability.java b/java/com/google/gerrit/common/data/GlobalCapability.java
index e613d21..3e11256 100644
--- a/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -90,6 +90,9 @@
   /** Default result limit per executed query. */
   public static final int DEFAULT_MAX_QUERY_LIMIT = 500;
 
+  /** Can impersonate any user to see which refs they can read. */
+  public static final String READ_AS = "readAs";
+
   /** Ability to impersonate another user. */
   public static final String RUN_AS = "runAs";
 
@@ -138,6 +141,7 @@
     NAMES_ALL.add(MODIFY_ACCOUNT);
     NAMES_ALL.add(PRIORITY);
     NAMES_ALL.add(QUERY_LIMIT);
+    NAMES_ALL.add(READ_AS);
     NAMES_ALL.add(RUN_AS);
     NAMES_ALL.add(RUN_GC);
     NAMES_ALL.add(STREAM_EVENTS);
diff --git a/java/com/google/gerrit/server/account/CapabilityCollection.java b/java/com/google/gerrit/server/account/CapabilityCollection.java
index ee74f47..1abc33f 100644
--- a/java/com/google/gerrit/server/account/CapabilityCollection.java
+++ b/java/com/google/gerrit/server/account/CapabilityCollection.java
@@ -48,6 +48,7 @@
   public final ImmutableList<PermissionRule> batchChangesLimit;
   public final ImmutableList<PermissionRule> emailReviewers;
   public final ImmutableList<PermissionRule> priority;
+  public final ImmutableList<PermissionRule> readAs;
   public final ImmutableList<PermissionRule> queryLimit;
   public final ImmutableList<PermissionRule> createGroup;
 
@@ -97,6 +98,7 @@
     batchChangesLimit = getPermission(GlobalCapability.BATCH_CHANGES_LIMIT);
     emailReviewers = getPermission(GlobalCapability.EMAIL_REVIEWERS);
     priority = getPermission(GlobalCapability.PRIORITY);
+    readAs = getPermission(GlobalCapability.READ_AS);
     queryLimit = getPermission(GlobalCapability.QUERY_LIMIT);
     createGroup = getPermission(GlobalCapability.CREATE_GROUP);
   }
diff --git a/java/com/google/gerrit/server/config/CapabilityConstants.java b/java/com/google/gerrit/server/config/CapabilityConstants.java
index 961dbbd..4ab97f8 100644
--- a/java/com/google/gerrit/server/config/CapabilityConstants.java
+++ b/java/com/google/gerrit/server/config/CapabilityConstants.java
@@ -34,6 +34,7 @@
   public String maintainServer;
   public String modifyAccount;
   public String priority;
+  public String readAs;
   public String queryLimit;
   public String runAs;
   public String runGC;
diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
index 51a0f95..8cf9444 100644
--- a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
@@ -172,6 +172,7 @@
         case CREATE_PROJECT:
         case MAINTAIN_SERVER:
         case MODIFY_ACCOUNT:
+        case READ_AS:
         case STREAM_EVENTS:
         case VIEW_ALL_ACCOUNTS:
         case VIEW_CONNECTIONS:
diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java b/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
index 9593521..cee42ad 100644
--- a/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
+++ b/java/com/google/gerrit/server/permissions/DefaultPermissionMappings.java
@@ -50,6 +50,7 @@
           .put(GlobalPermission.KILL_TASK, GlobalCapability.KILL_TASK)
           .put(GlobalPermission.MAINTAIN_SERVER, GlobalCapability.MAINTAIN_SERVER)
           .put(GlobalPermission.MODIFY_ACCOUNT, GlobalCapability.MODIFY_ACCOUNT)
+          .put(GlobalPermission.READ_AS, GlobalCapability.READ_AS)
           .put(GlobalPermission.RUN_AS, GlobalCapability.RUN_AS)
           .put(GlobalPermission.RUN_GC, GlobalCapability.RUN_GC)
           .put(GlobalPermission.STREAM_EVENTS, GlobalCapability.STREAM_EVENTS)
diff --git a/java/com/google/gerrit/server/permissions/GlobalPermission.java b/java/com/google/gerrit/server/permissions/GlobalPermission.java
index 01ef725..07c9e84 100644
--- a/java/com/google/gerrit/server/permissions/GlobalPermission.java
+++ b/java/com/google/gerrit/server/permissions/GlobalPermission.java
@@ -43,6 +43,7 @@
   KILL_TASK,
   MAINTAIN_SERVER,
   MODIFY_ACCOUNT,
+  READ_AS,
   RUN_AS,
   RUN_GC,
   STREAM_EVENTS,
diff --git a/java/com/google/gerrit/sshd/commands/LsUserRefs.java b/java/com/google/gerrit/sshd/commands/LsUserRefs.java
index 781679d..2c15e78 100644
--- a/java/com/google/gerrit/sshd/commands/LsUserRefs.java
+++ b/java/com/google/gerrit/sshd/commands/LsUserRefs.java
@@ -42,7 +42,7 @@
 import org.eclipse.jgit.lib.Repository;
 import org.kohsuke.args4j.Option;
 
-@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
+@RequiresCapability(GlobalCapability.READ_AS)
 @CommandMetaData(
     name = "ls-user-refs",
     description = "List refs visible to a specific user",
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java b/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
index 5404fdd..1ca019e 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/CapabilityInfo.java
@@ -28,6 +28,7 @@
   public boolean modifyAccount;
   public boolean priority;
   public QueryLimit queryLimit;
+  public boolean readAs;
   public boolean runAs;
   public boolean runGC;
   public boolean streamEvents;
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 6843b59..e995858 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -74,6 +74,7 @@
 import com.google.gerrit.index.Schema;
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.Id;
 import com.google.gerrit.reviewdb.client.Branch;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Patch;
@@ -198,6 +199,9 @@
   // These queries must be kept in sync with PolyGerrit:
   // polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
 
+  protected static final String DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY = "has:draft";
+  protected static final String DASHBOARD_ASSIGNED_QUERY =
+      "assignee:${user} (-is:wip OR " + "owner:self OR assignee:self)";
   protected static final String DASHBOARD_WORK_IN_PROGRESS_QUERY = "is:open owner:${user} is:wip";
   protected static final String DASHBOARD_OUTGOING_QUERY =
       "is:open owner:${user} -is:wip -is:ignored";
@@ -205,7 +209,8 @@
       "is:open -owner:${user} -is:wip -is:ignored (reviewer:${user} OR assignee:${user})";
   protected static final String DASHBOARD_RECENTLY_CLOSED_QUERY =
       "is:closed -is:ignored (-is:wip OR owner:self) "
-          + "(owner:${user} OR reviewer:${user} OR assignee:${user})";
+          + "(owner:${user} OR reviewer:${user} OR assignee:${user} "
+          + "OR cc:${user})";
 
   protected abstract Injector createInjector();
 
@@ -2585,7 +2590,10 @@
   protected class DashboardChangeState {
     private final Account.Id ownerId;
     private final List<Account.Id> reviewedBy;
+    private final List<Account.Id> cced;
     private final List<Account.Id> ignoredBy;
+    private final List<Account.Id> draftCommentBy;
+    private final List<Account.Id> deleteDraftCommentBy;
     private boolean wip;
     private boolean abandoned;
     @Nullable private Account.Id mergedBy;
@@ -2596,7 +2604,10 @@
     DashboardChangeState(Account.Id ownerId) {
       this.ownerId = ownerId;
       reviewedBy = new ArrayList<>();
+      cced = new ArrayList<>();
       ignoredBy = new ArrayList<>();
+      draftCommentBy = new ArrayList<>();
+      deleteDraftCommentBy = new ArrayList<>();
     }
 
     DashboardChangeState assignTo(Account.Id assigneeId) {
@@ -2629,6 +2640,21 @@
       return this;
     }
 
+    DashboardChangeState addCc(Account.Id ccId) {
+      cced.add(ccId);
+      return this;
+    }
+
+    DashboardChangeState draftCommentBy(Account.Id commenterId) {
+      draftCommentBy.add(commenterId);
+      return this;
+    }
+
+    DashboardChangeState draftAndDeleteCommentBy(Id commenterId) {
+      deleteDraftCommentBy.add(commenterId);
+      return this;
+    }
+
     DashboardChangeState create(TestRepository<Repo> repo) throws Exception {
       requestContext.setContext(newRequestContext(ownerId));
       Change change = insert(repo, newChange(repo), ownerId);
@@ -2648,11 +2674,28 @@
       for (Account.Id reviewerId : reviewedBy) {
         cApi.addReviewer("" + reviewerId);
       }
+      for (Account.Id reviewerId : cced) {
+        AddReviewerInput in = new AddReviewerInput();
+        in.reviewer = reviewerId.toString();
+        in.state = ReviewerState.CC;
+        cApi.addReviewer(in);
+      }
       for (Account.Id ignorerId : ignoredBy) {
         requestContext.setContext(newRequestContext(ignorerId));
         StarsInput in = new StarsInput(new HashSet<>(Arrays.asList("ignore")));
         gApi.accounts().self().setStars("" + id, in);
       }
+      DraftInput in = new DraftInput();
+      in.path = Patch.COMMIT_MSG;
+      in.message = "message";
+      for (Account.Id commenterId : draftCommentBy) {
+        requestContext.setContext(newRequestContext(commenterId));
+        gApi.changes().id(change.getChangeId()).current().createDraft(in);
+      }
+      for (Account.Id commenterId : deleteDraftCommentBy) {
+        requestContext.setContext(newRequestContext(commenterId));
+        gApi.changes().id(change.getChangeId()).current().createDraft(in).delete();
+      }
       if (mergedBy != null) {
         requestContext.setContext(newRequestContext(mergedBy));
         cApi = gApi.changes().id(change.getChangeId());
@@ -2674,6 +2717,43 @@
   }
 
   @Test
+  public void dashboardHasUnpublishedDrafts() throws Exception {
+    TestRepository<Repo> repo = createProject("repo");
+    Account.Id otherAccountId = createAccount("other");
+    DashboardChangeState hasUnpublishedDraft =
+        new DashboardChangeState(otherAccountId).draftCommentBy(user.getAccountId()).create(repo);
+
+    // Create changes that should not be returned by query.
+    new DashboardChangeState(user.getAccountId()).create(repo);
+    new DashboardChangeState(user.getAccountId()).draftCommentBy(otherAccountId).create(repo);
+    new DashboardChangeState(user.getAccountId())
+        .draftAndDeleteCommentBy(user.getAccountId())
+        .create(repo);
+
+    assertDashboardQuery("self", DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY, hasUnpublishedDraft);
+  }
+
+  @Test
+  public void dashboardAssignedReviews() throws Exception {
+    TestRepository<Repo> repo = createProject("repo");
+    Account.Id otherAccountId = createAccount("other");
+    DashboardChangeState otherOpenWip =
+        new DashboardChangeState(otherAccountId).wip().assignTo(user.getAccountId()).create(repo);
+    DashboardChangeState selfOpenWip =
+        new DashboardChangeState(user.getAccountId())
+            .wip()
+            .assignTo(user.getAccountId())
+            .create(repo);
+
+    // Create changes that should not be returned by query.
+    assertDashboardQuery("self", DASHBOARD_ASSIGNED_QUERY, selfOpenWip, otherOpenWip);
+
+    // Viewing another user's dashboard.
+    requestContext.setContext(newRequestContext(otherAccountId));
+    assertDashboardQuery(user.getUserName().get(), DASHBOARD_ASSIGNED_QUERY, otherOpenWip);
+  }
+
+  @Test
   public void dashboardWorkInProgressReviews() throws Exception {
     TestRepository<Repo> repo = createProject("repo");
     DashboardChangeState ownedOpenWip =
@@ -2773,6 +2853,11 @@
             .ignoreBy(user.getAccountId())
             .mergeBy(user.getAccountId())
             .create(repo);
+    DashboardChangeState mergedCced =
+        new DashboardChangeState(otherAccountId)
+            .addCc(user.getAccountId())
+            .mergeBy(user.getAccountId())
+            .create(repo);
     DashboardChangeState mergedAssigned =
         new DashboardChangeState(otherAccountId)
             .assignTo(user.getAccountId())
@@ -2859,6 +2944,7 @@
         abandonedOwnedIgnoredByOther,
         abandonedOwned,
         mergedAssigned,
+        mergedCced,
         mergedReviewing,
         mergedOwnedIgnoredByOther,
         mergedOwned);
@@ -2877,6 +2963,7 @@
         abandonedOwned,
         mergedAssignedIgnoredByUser,
         mergedAssigned,
+        mergedCced,
         mergedReviewingIgnoredByUser,
         mergedReviewing,
         mergedOwned);
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
index d84dec5..72ef0e5 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
@@ -22,15 +22,22 @@
 
   // NOTE: These queries are tested in Java. Any changes made to definitions
   // here require corresponding changes to:
-  // gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+  // javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
   const DEFAULT_SECTIONS = [
     {
       // Changes with unpublished draft comments. This section is omitted when
       // viewing other users, so we don't need to filter anything out.
-      name: 'Has unpublished drafts',
+      name: 'Has draft comments',
       query: 'has:draft',
       selfOnly: true,
       hideIfEmpty: true,
+      suffixForDashboard: 'limit:10',
+    },
+    {
+      // Changes that are assigned to the viewed user.
+      name: 'Assigned reviews',
+      query: 'assignee:${user} (-is:wip OR owner:self OR assignee:self)',
+      hideIfEmpty: true,
     },
     {
       // WIP open changes owned by viewing user. This section is omitted when
diff --git a/resources/com/google/gerrit/server/config/CapabilityConstants.properties b/resources/com/google/gerrit/server/config/CapabilityConstants.properties
index 6654837..ba590ee 100644
--- a/resources/com/google/gerrit/server/config/CapabilityConstants.properties
+++ b/resources/com/google/gerrit/server/config/CapabilityConstants.properties
@@ -10,6 +10,7 @@
 maintainServer = Maintain Server
 modifyAccount = Modify Account
 priority = Priority
+readAs = Read As
 queryLimit = Query Limit
 runAs = Run As
 runGC = Run Garbage Collection