Merge "Allow to disable the validation of code owner configs on commit received"
diff --git a/ui/code-owners-service.js b/ui/code-owners-service.js
index 426d0a7..86dc89c 100644
--- a/ui/code-owners-service.js
+++ b/ui/code-owners-service.js
@@ -37,6 +37,19 @@
 };
 
 /**
+ * @enum
+ */
+const UserRole = {
+  ANONYMOUS: 'ANONYMOUS',
+  AUTHOR: 'AUTHOR',
+  CHANGE_OWNER: 'CHANGE_OWNER',
+  REVIEWER: 'REVIEWER',
+  CC: 'CC',
+  REMOVED_REVIEWER: 'REMOVED_REVIEWER',
+  OTHER: 'OTHER',
+}
+
+/**
  * Responsible for communicating with the rest-api
  *
  * @see resources/Documentation/rest-api.md
@@ -123,6 +136,12 @@
    * Initial fetches.
    */
   init() {
+    this.accountPromise = this.restApi.getLoggedIn().then(loggedIn => {
+      if (!loggedIn) {
+        return undefined;
+      }
+      return this.restApi.getAccount();
+    });
     this.statusPromise = this.codeOwnerApi
         .listOwnerStatus(this.change._number)
         .then(res => {
@@ -134,6 +153,57 @@
             rawStatuses: res.file_code_owner_statuses,
           };
         });
+
+  }
+
+  /**
+   * Returns the role of the current user. The returned value reflects the
+   * role of the user at the time when the change is loaded.
+   * For example, if a user removes themselves as a reviewer, the returned
+   * role 'REVIEWER' remains unchanged until the change view is reloaded.
+   */
+  getLoggedInUserInitialRole() {
+    return this.accountPromise.then((account) => {
+      if (!account) {
+        return UserRole.ANONYMOUS;
+      }
+      const change = this.change;
+      if (
+        change.revisions &&
+        change.current_revision &&
+        change.revisions[change.current_revision]
+      ) {
+        const commit = change.revisions[change.current_revision].commit;
+        if (
+            commit &&
+            commit.author &&
+            account.email &&
+            commit.author.email === account.email
+        ) {
+          return UserRole.AUTHOR;
+        }
+      }
+      if(change.owner._account_id === account._account_id) {
+        return UserRole.CHANGE_OWNER;
+      }
+      if(change.reviewers) {
+        if(this._accountInReviewers(change.reviewers.REVIEWER, account)) {
+          return UserRole.REVIEWER;
+        } else if (this._accountInReviewers(change.reviewers.CC, account)) {
+          return UserRole.CC;
+        } else if (this._accountInReviewers(change.reviewers.REMOVED, account)) {
+          return UserRole.REMOVED_REVIEWER;
+        }
+      }
+      return UserRole.OTHER;
+    })
+  }
+
+  _accountInReviewers(reviewers, account) {
+    if(!reviewers) {
+      return false;
+    }
+    return reviewers.some(reviewer => reviewer._account_id === account._account_id);
   }
 
   getStatus() {
@@ -414,4 +484,4 @@
     }
     return this.ownerService;
   }
-}
\ No newline at end of file
+}
diff --git a/ui/owner-requirement.js b/ui/owner-requirement.js
index e456976..610fdd4 100644
--- a/ui/owner-requirement.js
+++ b/ui/owner-requirement.js
@@ -123,13 +123,14 @@
     return this.ownerService.getStatus()
         .then(({rawStatuses}) => {
           this._statusCount = this._getStatusCount(rawStatuses);
-
-          // Send a metric with overall summary when code owners submit
-          // requirement shown and finished fetching status
-          this.reporting.reportLifeCycle(
-              'owners-submit-requirement-summary-shown',
-              {...this._statusCount}
-          );
+          this.ownerService.getLoggedInUserInitialRole().then(role => {
+            // Send a metric with overall summary when code owners submit
+            // requirement shown and finished fetching status
+            this.reporting.reportLifeCycle(
+                'owners-submit-requirement-summary-shown',
+                {...this._statusCount, user_role: role}
+            );
+          });
         })
         .finally(() => {
           this._isLoading = false;
@@ -205,9 +206,11 @@
         })
     );
     ownerState.expandSuggestion = true;
-
-    this.reporting.reportInteraction('suggest-owners-from-submit-requirement');
+    this.ownerService.getLoggedInUserInitialRole().then(role => {
+      this.reporting.reportInteraction(
+          'suggest-owners-from-submit-requirement', {user_role: role});
+    });
   }
 }
 
-customElements.define(OwnerRequirementValue.is, OwnerRequirementValue);
\ No newline at end of file
+customElements.define(OwnerRequirementValue.is, OwnerRequirementValue);
diff --git a/ui/suggest-owners-trigger.js b/ui/suggest-owners-trigger.js
index 5745545..09fd6f8 100644
--- a/ui/suggest-owners-trigger.js
+++ b/ui/suggest-owners-trigger.js
@@ -90,13 +90,18 @@
         this.change
     );
 
-    Promise.all([this.ownerService.isCodeOwnerEnabled(), this.ownerService.areAllFilesApproved()])
-        .then(([enabled, approved]) => {
+    Promise.all([
+      this.ownerService.isCodeOwnerEnabled(),
+      this.ownerService.areAllFilesApproved(),
+      this.ownerService.getLoggedInUserInitialRole()
+    ])
+        .then(([enabled, approved, userRole]) => {
           if (enabled) {
             this.hidden = approved;
           } else {
             this.hidden = true;
           }
+          this._userRole = userRole;
         });
   }
 
@@ -105,6 +110,7 @@
     ownerState.expandSuggestion = this.expanded;
     this.reporting.reportInteraction('toggle-suggest-owners', {
       expanded: this.expanded,
+      user_role: this._userRole ? this._userRole : 'UNKNOWN',
     });
   }
 
@@ -121,4 +127,4 @@
   }
 }
 
-customElements.define(SuggestOwnersTrigger.is, SuggestOwnersTrigger);
\ No newline at end of file
+customElements.define(SuggestOwnersTrigger.is, SuggestOwnersTrigger);