Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/templates/sitewide/user-profile-page.ezt b/templates/sitewide/user-profile-page.ezt
new file mode 100644
index 0000000..7517d15
--- /dev/null
+++ b/templates/sitewide/user-profile-page.ezt
@@ -0,0 +1,474 @@
+[define category_css]css/ph_list.css[end]
+[include "../framework/header.ezt" "showusertabs" "t1"]
+[include "../framework/js-placeholders.ezt"]
+<div id="colcontrol">
+
+<h2>
+  [if-any viewing_self][else]
+   [if-any user_stars_enabled]
+    [if-any logged_in_user]
+     [if-any read_only][else]
+          [if-any user_stars_enabled]
+           [if-any logged_in_user]
+            [if-any read_only][else]
+             <a id="user_star"
+              style="color:[if-any is_user_starred]cornflowerblue[else]gray[end]"
+              title="[if-any is_user_starred]Un-s[else]S[end]tar this user">
+             [if-any is_user_starred]&#9733;[else]&#9734;[end]
+             </a>
+            [end]
+           [end]
+          [end]
+     [end]
+    [end]
+   [end]
+ [end]
+
+ [viewed_user_display_name]
+</h2>
+
+<p>
+  <b>Last visit:</b>
+  [last_visit_str]
+</p>
+
+[if-any last_bounce_str]
+  <p>
+    <b>Email to this user bounced:</b>
+    [last_bounce_str]
+    [define offer_clear_bouncing]No[end]
+    [if-any viewing_self][define offer_clear_bouncing]Yes[end][end]
+    [if-any perms._EditOtherUsers][define offer_clear_bouncing]Yes[end][end]
+    [is offer_clear_bouncing "Yes"]
+      <a href="[viewed_user.profile_url]clearBouncing" style="margin-left:2em">Clear</a>
+    [end]
+  </p>
+[end]
+
+[if-any vacation_message]
+  <p>
+    <b>Vacation message:</b>
+    [vacation_message]
+  </p>
+[end]
+
+[if-any linked_parent]
+  <p>
+  <b>Linked parent account:</b>
+    [include "../framework/user-link.ezt" linked_parent]
+    [if-any offer_unlink perms._EditOtherUsers]
+      <input type="button" class="unlink_account secondary"
+             data-parent="[linked_parent.email]"
+             data-child="[viewed_user.email]"
+             value="Unlink">
+    [end]
+  </p>
+[end]
+
+[if-any linked_children]
+  <p>
+  <b>Linked child accounts:</b>
+  [for linked_children]
+    [include "../framework/user-link.ezt" linked_children]
+    [if-any offer_unlink perms._EditOtherUsers]
+      <input type="button" class="unlink_account secondary"
+             data-parent="[viewed_user.email]"
+             data-child="[linked_children.email]"
+             value="Unlink">
+    [end]
+  [end]
+  </p>
+[end]
+
+[if-any incoming_invite_users]
+  <b>Accept linked sub-account:</b>
+    [for incoming_invite_users]
+      <div>
+        [include "../framework/user-link.ezt" incoming_invite_users]
+        [if-any can_edit_invites][# TODO(jrobbins): allow site admin to accept invites for other users.]
+          <input type="button" class="incoming_invite" data-email="[incoming_invite_users.email]" value="Accept">
+          [# TODO(jrobbins): Button to decline invite.]
+        [end]
+      </div>
+    [end]
+[else][if-any outgoing_invite_users]
+  <b>Waiting for acceptance by parent-account:</b>
+    [for outgoing_invite_users]
+      <div>
+        [include "../framework/user-link.ezt" outgoing_invite_users]
+      </div>
+    [end]
+[else][if-any possible_parent_accounts]
+  <b>Link this account to:</b>
+  <select id="parent_to_invite">
+    <option value="" selected="selected">----</option>
+    [for possible_parent_accounts]
+      <option value="[possible_parent_accounts]">[possible_parent_accounts]</option>
+    [end]
+  </select>
+  [if-any can_edit_invites][# TODO(jrobbins): allow site admin to create invites for other users.]
+    <button id="create_linked_account_invite" disabled="disabled">Link</button>
+  [end]
+[end][end][end]
+
+
+[if-any user_stars_enabled]
+<p>
+<b>Starred developers:</b>
+[if-any starred_users]
+[for starred_users]
+  [include "../framework/user-link.ezt" starred_users][if-index starred_users last][else], [end]
+[end]
+[else]<i>None</i>[end]
+</p>
+[end]
+<br>
+
+<div class="list">
+  <table style="width: 100%;" cellspacing="0" cellpadding="0">
+  <tbody><tr>
+     <th style="text-align: left;">Projects
+     </th>
+  </tr></tbody>
+  </table>
+</div>
+
+<table cellspacing="0" cellpadding="2" border="0" class="results striped" id="projecttable" width="100%">
+    <tbody>
+      <tr id="headingrow">
+        [if-any logged_in_user]
+        <th style="white-space:nowrap; width:3%;"></th>
+        [end]
+        <th style="white-space:nowrap; width:15%;">Role</th>
+        <th style="white-space:nowrap; width:25%;">Project</th>
+        <th style="white-space:nowrap; width:57%;">Summary</th>
+      </tr>
+ [if-any owner_of_projects committer_of_projects contributor_to_projects]
+      [if-any owner_of_projects]
+        [for owner_of_projects]
+        <tr data-url="[owner_of_projects.relative_home_url]" data-project-name="[owner_of_projects.project_name]">
+        [if-any logged_in_user]
+        <td class="rowwidgets">
+         <a class="star"
+          style="color:[if-any owner_of_projects.starred]cornflowerblue[else]gray[end]"
+          title="[if-any owner_of_projects.starred]Un-s[else]S[end]tar this project"
+          data-project-name="[owner_of_projects.project_name]">
+         [if-any owner_of_projects.starred]&#9733;[else]&#9734;[end]
+         </a>
+        </td>
+        [end]
+        <td>Owner</td>
+        <td class="id" name="owner">
+        <a href="[owner_of_projects.relative_home_url]/">[owner_of_projects.project_name]</a>
+          [is owner_of_projects.state_name "HIDDEN"]<span style="color:red"> - hidden</span>[end]
+        </td>
+        <td>[owner_of_projects.summary]</td>
+        </tr>
+        [end]
+      [end]
+      [if-any committer_of_projects]
+        [for committer_of_projects]
+        <tr data-url="[committer_of_projects.relative_home_url]" data-project-name="[committer_of_projects.project_name]">
+        [if-any logged_in_user]
+        <td class="rowwidgets">
+         <a class="star"
+          style="color:[if-any committer_of_projects.starred]cornflowerblue[else]gray[end]"
+          title="[if-any committer_of_projects.starred]Un-s[else]S[end]tar this project"
+          data-project-name="[committer_of_projects.project_name]">
+         [if-any committer_of_projects.starred]&#9733;[else]&#9734;[end]
+         </a>
+        </td>
+        [end]
+        <td>Committer</td>
+        <td class="id" name="committer">
+          <a href="[committer_of_projects.relative_home_url]/">[committer_of_projects.project_name]
+          </a>
+        </td>
+        <td>
+        [committer_of_projects.summary]
+        </td>
+        </tr>
+        [end]
+      [end]
+
+      [if-any contributor_to_projects]
+        [for contributor_to_projects]
+        <tr data-url="[contributor_to_projects.relative_home_url]" data-project-name="[contributor_to_projects.project_name]">
+        [if-any logged_in_user]
+        <td class="rowwidgets">
+         <a class="star"
+          style="color:[if-any contributor_to_projects.starred]cornflowerblue[else]gray[end]"
+          title="[if-any contributor_to_projects.starred]Un-s[else]S[end]tar this project"
+          data-project-name="[contributor_to_projects.project_name]">
+         [if-any contributor_to_projects.starred]&#9733;[else]&#9734;[end]
+         </a>
+        </td>
+        [end]
+        <td>Contributor</td>
+        <td class="id" name="contributor">
+          <a href="[contributor_to_projects.relative_home_url]/">[contributor_to_projects.project_name]
+          </a>
+        [is contributor_to_projects.state_name "HIDDEN"]<span style="color:red"> - hidden</span>[end]</td>
+        <td>
+        [contributor_to_projects.summary]
+        </td>
+        </tr>
+        [end]
+      [end]
+
+ [else]
+      <tr>
+      <td colspan="4"><i>No projects.</i></td>
+      <tr>
+ [end]
+  </tbody>
+</table>
+
+
+[if-any starred_projects]
+<br>
+<div class="list">
+  <table style="width: 100%;" cellspacing="0" cellpadding="0">
+  <tbody><tr>
+     <th style="text-align: left;">
+      Starred by [if-any viewing_self]me[else]
+      [viewed_user_display_name]
+      [end]
+     </th>
+  </tr></tbody>
+  </table>
+</div>
+<table cellspacing="0" cellpadding="2" border="0" class="results striped" id="starredtable" width="100%">
+    <tbody>
+      <tr id="headingrow">
+        [if-any logged_in_user]
+        <th style="white-space:nowrap; width:3%;"></th>
+        [end]
+        <th style="white-space:nowrap; width:25%;">Name</th>
+        <th style="white-space:nowrap; width:57%;">Summary</th>
+      </tr>
+
+      [for starred_projects]
+      <tr data-url="[starred_projects.relative_home_url]" data-project-name="[starred_projects.project_name]">
+      [if-any logged_in_user]
+      <td class="rowwidgets">
+        <a class="star"
+         style="color:[if-any starred_projects.starred]cornflowerblue[else]gray[end]"
+         title="[if-any starred_projects.starred]Un-s[else]S[end]tar this project"
+         data-project-name="[starred_projects.project_name]">
+        [if-any starred_projects.starred]&#9733;[else]&#9734;[end]
+        </a>
+      </td>
+      [end]
+      <td class="id" name="starred_project">
+        <a href="[starred_projects.relative_home_url]/">[starred_projects.project_name]</a>
+        [is starred_projects.state_name "HIDDEN"]<span style="color:red"> - hidden</span>[end]
+      </td>
+      <td>
+      [starred_projects.summary]
+      </td>
+      </tr>
+      [end]
+
+</table>
+[end]
+
+[if-any owner_of_archived_projects]
+<br>
+<div class="list">
+  <table style="width: 100%;" cellspacing="0" cellpadding="0">
+  <tbody><tr>
+     <th style="text-align: left;">Archived projects
+     </th>
+  </tr></tbody>
+  </table>
+</div>
+<table cellspacing="0" cellpadding="2" border="0" class="results striped" id="archivedtable" width="100%">
+    <tbody>
+      <tr id="headingrow">
+        <th style="white-space:nowrap; width:25%;">Name</th>
+        <th style="white-space:nowrap; width:60%;">Summary</th>
+      </tr>
+        [for owner_of_archived_projects]
+        <tr data-url="[owner_of_archived_projects.relative_home_url]/adminAdvanced">
+        <td class="id" name="deleted_project">[owner_of_archived_projects.project_name] -
+          <a href="[owner_of_archived_projects.relative_home_url]/adminAdvanced">Unarchive or delete</a>
+        </td>
+        <td>
+        [owner_of_archived_projects.summary]
+        </td>
+        </tr>
+        [end]
+</table>
+[end]
+
+[if-any user_groups]
+<br>
+<div class="list">
+  <table style="width: 100%;" cellspacing="0" cellpadding="0">
+  <tbody><tr>
+     <th style="text-align: left;">User groups
+     </th>
+  </tr></tbody>
+  </table>
+</div>
+<table cellspacing="0" cellpadding="2" border="0" class="results striped" id="usergrouptable" width="100%">
+ <tbody>
+  <tr id="headingrow">
+   <th style="white-space:nowrap; width:25%;">Name</th>
+  </tr>
+  [for user_groups]
+   <tr data-url="[user_groups.profile_url]">
+    <td class="id">
+     <a href="[user_groups.profile_url]">[user_groups.email]</a>
+    </td>
+   </tr>
+  [end]
+ </tbody>
+</table>
+[end]
+
+[if-any can_ban]
+ <form action="ban.do" method="POST">
+  <input type="hidden" name="token" value="[ban_token]">
+  <h4>Banned for abuse</h4>
+  <div style="margin:0 0 2em 2em">
+   <input type="checkbox" name="banned" id="banned" value="1"
+          [if-any settings_user_is_banned]checked="checked"[end] >
+   <label for="banned">This user is banned because:</label>
+   <input type="text" size="50" name="banned_reason" id="banned_reason" value="[settings_user_pb.banned]">
+  </div>
+
+  <div style="margin:0 0 2em 2em">
+   <input id="submit_btn" type="submit" name="btn"
+          value="Update banned status">
+  </div>
+
+ </form>
+
+  [if-any viewed_user_is_spammer]
+   <form action="banSpammer.do" method="POST">
+    <input type="hidden" name="token" value="[ban_spammer_token]">
+    <input type="hidden" size="50" name="banned_reason" id="banned_reason" value="">
+    <input type="submit" name="undoBanSpammerButton" id="undo_ban_spammer_btn" value="Un-ban this user as a spammer">
+   </form>
+  [end]
+
+
+  [if-any viewed_user_may_be_spammer]
+   <form action="banSpammer.do" method="POST">
+    <input type="hidden" name="token" value="[ban_spammer_token]">
+    <input type="hidden" name="banned" value="True">
+    <input type="hidden" size="50" name="banned_reason" id="banned_reason" value="Spam">
+    <input type="submit" name="banSpammerButton" id="ban_spammer_btn" value="Ban this user as a spammer">
+   </form>
+  [end]
+
+[end]
+
+[if-any perms._EditOtherUsers]
+<h3 style="clear:both">Edit user</h3>
+ <form action="edit.do" method="POST">
+  <input type="hidden" name="token" value="[form_token]">
+  <h4>Site administration</h4>
+  <div style="margin:0 0 2em 2em">
+   <input type="checkbox" name="site_admin" id="site_admin" value="1" [if-any viewed_user_pb.is_site_admin_bool]checked="checked"[end] >
+   <label for="site_admin">This user is a site administrator (a super user)</label>
+  </div>
+
+  [include "unified-settings.ezt"]
+
+  <div style="margin:0 0 2em 2em">
+   <input id="submit_btn" type="submit" name="btn"
+          value="Save changes">
+  </div>
+
+ </form>
+[end]
+
+[if-any can_delete_user]
+<h3 style="clear:both">Delete user account</h3>
+  <p>Deleting a user account deletes the user and most user owned items from the site.
+     The user's email will be removed from any issues that the user participated in.
+     Hotlists owned by the user will either be transferred to another editor or get deleted.
+     Any Project Rules that the user is involved in will get deleted.
+  </p>
+  <div style="margin:0 0 2em 2em">
+    <input id="delete_btn" type="submit" name="btn" value="Delete user account">
+    <div id="delete_error" class="fielderror"></div>
+  </div>
+[end]
+
+</div>
+</div>
+
+<script type="text/javascript" nonce="[nonce]">
+runOnLoad(function() {
+  if ($("user_star")) {
+    [# The user viewing this page wants to star the user *on* this page]
+    $("user_star").addEventListener("click", function () {
+       _TKR_toggleStar($("user_star"), null, null, "[viewed_user_id]", null, null);
+    });
+  }
+
+  var stars = document.getElementsByClassName("star");
+  for (var i = 0; i < stars.length; ++i) {
+    var star = stars[[]i];
+    star.addEventListener("click", function (event) {
+        var projectName = event.target.getAttribute("data-project-name");
+        _TKR_toggleStar(event.target, projectName);
+    });
+  }
+
+  function _handleProjectClick(event) {
+    var target = event.target;
+    if (target.tagName == "A")
+      return;
+
+    if (target.classList.contains("rowwidgets") || target.parentNode.classList.contains("rowwidgets"))
+      return;
+    if (target.tagName != "TR") target = target.parentNode;
+    _go(target.attributes[[]"data-url"].value,
+        (event.metaKey || event.ctrlKey || event.button == 1));
+  };
+  $("projecttable").addEventListener("click", _handleProjectClick);
+  if ($("starredtable")) {
+    $("starredtable").addEventListener("click", _handleProjectClick);
+  }
+  if ($("archivedtable")) {
+    $("archivedtable").addEventListener("click", _handleProjectClick);
+  }
+
+  if ($("banned_reason")) {
+    $("banned_reason").addEventListener("keyup", function() {
+      $("banned").checked = $("banned_reason").value != "";
+    });
+  }
+
+  if ($("ban_spammer_btn")) {
+    $("ban_spammer_btn").addEventListener("click", function(evt) {
+       var ok = window.confirm("This will remove all issues and comments " +
+          "created by this user. Continue?");
+       if (!ok) {
+         evt.preventDefault();
+       }
+     });
+   }
+
+   if ($("delete_btn")) {
+     $("delete_btn").addEventListener("click", async function(event) {
+       const expungeCall = window.prpcClient.call(
+         'monorail.Users', 'ExpungeUser', {email: "[viewed_user_display_name]"});
+       expungeCall.then((resp) => {
+         location.replace(location.origin);
+       }).catch((reason) => {
+         $("delete_error").textContent = reason;
+       });
+     });
+   }
+});
+</script>
+<script type="module" defer src="[version_base]/static/js/sitewide/linked-accounts.js" nonce="[nonce]"></script>
+
+
+[include "../framework/footer.ezt"]