Match Owned Files entries even when owners.expandGroups == false

When `owners.expandGroups == false` then neither groups nor accounts are
expaned in the plugins REST API response. In addition, owner can be
configured as:
* email - in this case the `@domain` is dropped
* full user name - in this case full user name is conveyed

Considering the above when `Owned Files` tab content is resolved then:
* if file owner has no `account_id` resolved (so that we avoid false
  positive matches when `owners.expandGroups == true`)
* try to match its name with email without domain
* try to match its name with full name

Bug: Issue 379269836
Change-Id: I68794b4477758b62cdd2bba717a263505ac8d55b
diff --git a/owners/web/gr-owned-files.ts b/owners/web/gr-owned-files.ts
index 969d91c..5f5d919 100644
--- a/owners/web/gr-owned-files.ts
+++ b/owners/web/gr-owned-files.ts
@@ -23,6 +23,7 @@
   AccountInfo,
   ChangeInfo,
   ChangeStatus,
+  EmailAddress,
   RevisionInfo,
   EDIT,
 } from '@gerritcodereview/typescript-api/rest-api';
@@ -296,12 +297,22 @@
     return;
   }
 
+  const groupPrefix = 'group/';
+  const emailWithoutDomain = toEmailWithoutDomain(owner.email);
   const ownedFiles = [];
   for (const file of Object.keys(files)) {
     if (
-      files[file].find(
-        fileOwner => isOwner(fileOwner) && fileOwner.id === owner._account_id
-      )
+      files[file].find(fileOwner => {
+        if (isOwner(fileOwner)) {
+          return fileOwner.id === owner._account_id;
+        }
+
+        return (
+          !fileOwner.name?.startsWith(groupPrefix) &&
+          (fileOwner.name === emailWithoutDomain ||
+            fileOwner.name === owner.name)
+        );
+      })
     ) {
       ownedFiles.push(file);
     }
@@ -329,3 +340,8 @@
 
   return `${getBaseUrl()}/c/${repo}${change._number}${range}${path}`;
 }
+
+function toEmailWithoutDomain(email?: EmailAddress): string | undefined {
+  const startDomainIndex = email?.indexOf('@');
+  return startDomainIndex ? email?.substring(0, startDomainIndex) : undefined;
+}
diff --git a/owners/web/gr-owned-files_test.ts b/owners/web/gr-owned-files_test.ts
index 0437ab9..f9c7f3a 100644
--- a/owners/web/gr-owned-files_test.ts
+++ b/owners/web/gr-owned-files_test.ts
@@ -17,6 +17,7 @@
 
 import {assert} from '@open-wc/testing';
 import {
+  AccountId,
   AccountInfo,
   ChangeInfo,
   ChangeStatus,
@@ -25,7 +26,7 @@
   SubmitRequirementResultInfo,
 } from '@gerritcodereview/typescript-api/rest-api';
 import {ownedFiles, shouldHide} from './gr-owned-files';
-import {OwnedFiles, Owner} from './owners-service';
+import {GroupOwner, OwnedFiles, Owner} from './owners-service';
 import {deepEqual} from './utils';
 import {User, UserRole} from './owners-model';
 import {getRandom} from './test-utils';
@@ -59,6 +60,27 @@
     test('ownedFiles - should return owned files', () => {
       assert.equal(deepEqual(ownedFiles(owner, files), [ownedFile]), true);
     });
+
+    test('ownedFiles - should match file owner through email without domain name', () => {
+      const files = {
+        [ownedFile]: [fileOwnerWithNameOnly(`${ownerAccountId}_email`)],
+        'some.text': [fileOwnerWithNameOnly('random_joe')],
+      } as unknown as OwnedFiles;
+      assert.equal(deepEqual(ownedFiles(owner, files), [ownedFile]), true);
+    });
+
+    test('ownedFiles - should match file owner through full name', () => {
+      const files = {
+        [ownedFile]: [fileOwnerWithNameOnly(`${ownerAccountId}_name`)],
+        'some.text': [fileOwnerWithNameOnly('random_joe')],
+      } as unknown as OwnedFiles;
+      assert.equal(deepEqual(ownedFiles(owner, files), [ownedFile]), true);
+    });
+
+    test('ownedFiles - should NOT match file owner over email without domain or full name when account id is different', () => {
+      const notFileOwner = {...owner, _account_id: 2 as unknown as AccountId};
+      assert.equal(deepEqual(ownedFiles(notFileOwner, files), []), true);
+    });
   });
 
   suite('shouldHide tests', () => {
@@ -174,12 +196,18 @@
 function account(id: number): AccountInfo {
   return {
     _account_id: id,
+    email: `${id}_email@example.com`,
+    name: `${id}_name`,
   } as unknown as AccountInfo;
 }
 
 function fileOwner(id: number): Owner {
   return {
     id,
-    name: `name for account: ${id}`,
+    name: `${id}_name`,
   } as unknown as Owner;
 }
+
+function fileOwnerWithNameOnly(name: string): GroupOwner {
+  return {name} as unknown as GroupOwner;
+}