diff --git a/pyproject.toml b/pyproject.toml index b382328de..1427edca3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,3 +122,4 @@ extension = "html" profile = "django" ignore = "T002,H006,H017,H023" preserve_blank_lines = true +extend_exclude = "htmlcov,staticfiles,static,node_modules" diff --git a/src/config/settings/base.py b/src/config/settings/base.py index 564f26b01..5a42c464c 100644 --- a/src/config/settings/base.py +++ b/src/config/settings/base.py @@ -540,8 +540,11 @@ "person-api-people-list", "person-api-people-detail", "team-api-teams-list", + "profile-get-card", ) +AUTHBROKER_INTROSPECTION_TOKEN = env("AUTHBROKER_INTROSPECTION_TOKEN", default="XXX") + # There are some big pages with lots of content that need to send many fields. DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240 diff --git a/src/peoplefinder/forms/profile.py b/src/peoplefinder/forms/profile.py index a4b17791f..7392a8420 100644 --- a/src/peoplefinder/forms/profile.py +++ b/src/peoplefinder/forms/profile.py @@ -4,7 +4,6 @@ from django.contrib.auth import get_user_model from django.core.validators import ValidationError - User = get_user_model() diff --git a/src/peoplefinder/services/person.py b/src/peoplefinder/services/person.py index 0b81d429a..b0268173c 100644 --- a/src/peoplefinder/services/person.py +++ b/src/peoplefinder/services/person.py @@ -2,6 +2,7 @@ from datetime import timedelta from typing import Any, Dict, List, Optional, Tuple, TypedDict +import requests from django.conf import settings from django.contrib.auth.models import Group from django.contrib.postgres.aggregates import ArrayAgg @@ -554,6 +555,24 @@ def get_profile_section_values( ) return values + @staticmethod + def get_verified_emails(person: Person) -> list[str]: + user_email = person.user.email # @TODO prefer UUID if we can get it from SSO + url = f"{settings.AUTHBROKER_URL}/api/v1/user/emails/" + params = {"email": user_email} + headers = {"Authorization": f"bearer {settings.AUTHBROKER_INTROSPECTION_TOKEN}"} + + response = requests.get(url, params, headers=headers, timeout=5) + + if response.status_code == 200: + resp_json = response.json() + return resp_json["emails"] + else: + logger.error( + f"Response code [{response.status_code}] from authbroker emails endpoint for {user_email}" + ) + return [] + class PersonAuditLogSerializer(AuditLogSerializer): model = Person diff --git a/src/peoplefinder/static/peoplefinder/profile-card.js b/src/peoplefinder/static/peoplefinder/profile-card.js new file mode 100644 index 000000000..9f0889dd7 --- /dev/null +++ b/src/peoplefinder/static/peoplefinder/profile-card.js @@ -0,0 +1,138 @@ +(function () { + /** + * + * @param {String} html + * @returns {Node} + */ + function htmlTemplate(html) { + const template = document.createElement("template"); + template.innerHTML = html; + + return template.content.cloneNode(true); + } + + /** + * + * @returns {String} + */ + function getProfileCardUrl() { + const metaName = "profile-card-url"; + const meta = document.querySelector(`meta[name="${metaName}"]`); + + return meta.content; + } + + /** + * + * @returns {Node} + */ + async function getProfileCard() { + const url = getProfileCardUrl(); + + const response = await fetch(url, { + credentials: "include", + cache: "default", + }); + + if (!response.ok) { + throw new Error("Error fetching profile card"); + } + + const html = await response.text(); + + return htmlTemplate(html); + } + + /** + * + */ + class ProfileCard extends HTMLElement { + constructor() { + super(); + + const css = ` + +
+
+
+ +
+
+ `; + + const cssTemplate = htmlTemplate(css); + + this.attachShadow({ mode: "open" }); + this.shadowRoot.append(cssTemplate); + } + + async connectedCallback() { + const profileName = this.getAttribute("profile-name"); + + if (profileName) { + this.find(".profile-name").innerHTML = profileName; + } + + let html = null; + + try { + html = await getProfileCard(); + } catch (error) { + console.log(error); + } + + if (html) { + this.shadowRoot.querySelector(".loading").style.display = "none"; + this.shadowRoot.append(html); + } + } + + find(selector) { + return this.shadowRoot.querySelector(selector); + } + } + + customElements.define("profile-card", ProfileCard); +})(); diff --git a/src/peoplefinder/templates/peoplefinder/components/profile-card.html b/src/peoplefinder/templates/peoplefinder/components/profile-card.html new file mode 100644 index 000000000..f1b6ea9ce --- /dev/null +++ b/src/peoplefinder/templates/peoplefinder/components/profile-card.html @@ -0,0 +1,31 @@ +{% comment %} +context: + profile (Person) + profile_url (str) + no_photo_url (str) +{% endcomment %} + +
+ {% if profile and profile.photo_small %} + Photo of {{ profile.full_name }} + {% else %} + No photo + {% endif %} + +
+ +
diff --git a/src/peoplefinder/templates/peoplefinder/profile-edit.html b/src/peoplefinder/templates/peoplefinder/profile-edit.html index b5a19e4ed..9356e539d 100644 --- a/src/peoplefinder/templates/peoplefinder/profile-edit.html +++ b/src/peoplefinder/templates/peoplefinder/profile-edit.html @@ -32,7 +32,6 @@

{{ page_title }}