File size: 2,851 Bytes
37cb069
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
"""Community member privacy and directory rendering rules.

Applies opt-in-only directory listing based on Google Form signup preferences.
Never exposes information the member did not explicitly consent to.
"""

DIRECTORY_CHOICES = {
    "public": "Yes, list me publicly",
    "minimal": "Yes, but name and role only (no contact info)",
    "private": "No — keep me private",
}

CONTACT_FIELDS = {
    "email": "Email address",
    "orcid": "ORCID",
    "scholar": "Google Scholar profile",
    "website": "Personal website",
    "alias": "ICSAC-aliased email only (we forward to your real address)",
}


def directory_entry(member: dict) -> dict | None:
    """Build a directory entry that respects the member's privacy choices.

    Returns None for private members. For public/minimal members, returns only
    the fields they consented to expose. Never includes email unless they ticked
    'Email address' explicitly.
    """
    choice = member.get("directory_choice", "")

    if choice == DIRECTORY_CHOICES["private"]:
        return None

    entry = {
        "display_name": format_display_name(member),
        "affiliation": member.get("affiliation", ""),
        "role": member.get("contribution_role", ""),
        "research_interests": member.get("research_interests", []),
    }

    if choice == DIRECTORY_CHOICES["minimal"]:
        entry.pop("affiliation", None)
        return entry

    consented = set(member.get("public_contact_fields", []))
    contact = {}
    if CONTACT_FIELDS["email"] in consented:
        contact["email"] = member.get("email", "")
    if CONTACT_FIELDS["alias"] in consented:
        contact["email_alias"] = member.get("icsac_alias", "")
    if CONTACT_FIELDS["orcid"] in consented:
        contact["orcid"] = member.get("orcid", "")
    if CONTACT_FIELDS["scholar"] in consented:
        contact["scholar"] = member.get("scholar_url", "")
    if CONTACT_FIELDS["website"] in consented:
        contact["website"] = member.get("website_url", "")

    if contact:
        entry["contact"] = contact

    return entry


def format_display_name(member: dict) -> str:
    """Build a display name from title preference + name + post-nominals."""
    title = member.get("title", "")
    name = member.get("full_name", "")
    postnoms = member.get("post_nominals", "")

    parts = []
    if title and title not in ("No title (first name is fine)", "Prefer not to say"):
        parts.append(title)
    parts.append(name)

    display = " ".join(parts)
    if postnoms:
        display = f"{display}, {postnoms}"
    return display


def public_directory(members: list[dict]) -> list[dict]:
    """Filter the member list into directory-visible entries only."""
    entries = []
    for m in members:
        e = directory_entry(m)
        if e is not None:
            entries.append(e)
    return entries