#!/usr/bin/env python3 """ profile page template and helpers for connectd comprehensive "get to know" page showing ALL data """ import json from urllib.parse import quote PROFILE_HTML = """ {name} | connectd
โ† back to dashboard
{avatar}
{name} {score} {user_type}
@{username} on {platform}
{location_html} {pronouns_html}
{bio}
๐ŸŒ where to find them โ–ผ
{platforms_html}
{repos_section}
๐Ÿ’œ what they care about ({signal_count} signals) โ–ผ
{signals_html}
{negative_signals_html}
๐Ÿ“Š why they scored {score} โ–ผ
{reasons_html}
{communities_section}
๐Ÿค in the network โ–ผ
{match_count} matches
{lost_score} lost potential
๐Ÿ“ฌ how to connect โ–ผ
{contact_html}
๐Ÿ” the data (everything connectd knows) โ–ผ
""" RARE_SIGNALS = {'queer', 'solarpunk', 'cooperative', 'intentional_community', 'trans', 'nonbinary'} def parse_json_field(val): """safely parse json string or return as-is""" if isinstance(val, str): try: return json.loads(val) except: return val return val or {} def render_profile(human, match_count=0): """render full profile page for a human""" # parse json fields signals = parse_json_field(human.get('signals', '[]')) if isinstance(signals, str): signals = [] negative_signals = parse_json_field(human.get('negative_signals', '[]')) if isinstance(negative_signals, str): negative_signals = [] reasons = parse_json_field(human.get('reasons', '[]')) if isinstance(reasons, str): reasons = [] contact = parse_json_field(human.get('contact', '{}')) extra = parse_json_field(human.get('extra', '{}')) # nested extra sometimes if 'extra' in extra: extra = {**extra, **parse_json_field(extra['extra'])} # basic info name = human.get('name') or human.get('username', 'unknown') username = human.get('username', 'unknown') platform = human.get('platform', 'unknown') bio = human.get('bio', '') location = human.get('location') or extra.get('location', '') score = human.get('score', 0) user_type = human.get('user_type', 'none') lost_score = human.get('lost_potential_score', 0) # avatar - first letter or image avatar_html = name[0].upper() if name else '?' avatar_url = extra.get('avatar_url') or extra.get('profile_image') if avatar_url: avatar_html = f'{name}' # location html location_html = f'
๐Ÿ“ {location}
' if location else '' # pronouns - try to detect pronouns = extra.get('pronouns', '') if not pronouns and bio: bio_lower = bio.lower() if 'she/her' in bio_lower: pronouns = 'she/her' elif 'he/him' in bio_lower: pronouns = 'he/him' elif 'they/them' in bio_lower: pronouns = 'they/them' pronouns_html = f'{pronouns}' if pronouns else '' # platforms/handles handles = extra.get('handles', {}) platforms_html = [] # main platform if platform == 'github': platforms_html.append(f'
๐Ÿ’ปgithub.com/{username}
') elif platform == 'reddit': platforms_html.append(f'
๐Ÿ”ดu/{username}
') elif platform == 'mastodon': instance = human.get('instance', 'mastodon.social') platforms_html.append(f'
๐Ÿ˜@{username}@{instance}
') elif platform == 'lobsters': platforms_html.append(f'
๐Ÿฆžlobste.rs/u/{username}
') # other handles if handles.get('github') and platform != 'github': platforms_html.append(f'
๐Ÿ’ปgithub.com/{handles["github"]}
') if handles.get('twitter'): t = handles['twitter'].lstrip('@') platforms_html.append(f'
๐Ÿฆ@{t}
') if handles.get('mastodon') and platform != 'mastodon': platforms_html.append(f'
๐Ÿ˜{handles["mastodon"]}
') if handles.get('bluesky'): platforms_html.append(f'
๐Ÿฆ‹{handles["bluesky"]}
') if handles.get('linkedin'): platforms_html.append(f'
๐Ÿ’ผlinkedin
') if handles.get('matrix'): platforms_html.append(f'
๐Ÿ’ฌ{handles["matrix"]}
') # contact methods if contact.get('blog'): platforms_html.append(f'
๐ŸŒ{contact["blog"]}
') # signals html signals_html = [] for sig in signals: cls = 'tag' if sig in RARE_SIGNALS: cls = 'tag rare' signals_html.append(f'{sig}') # negative signals negative_signals_html = '' if negative_signals: neg_tags = ' '.join([f'{s}' for s in negative_signals]) negative_signals_html = f'
negative signals:
{neg_tags}
' # reasons html reasons_html = '\n'.join([f'
{r}
' for r in reasons]) if reasons else '
no specific reasons recorded
' # repos section repos_section = '' top_repos = extra.get('top_repos', []) languages = extra.get('languages', {}) repo_count = extra.get('repo_count', 0) total_stars = extra.get('total_stars', 0) if top_repos or languages: repos_html = '' if top_repos: for repo in top_repos[:6]: repo_name = repo.get('name', 'unknown') repo_desc = repo.get('description', '')[:200] or 'no description' repo_stars = repo.get('stars', 0) repo_lang = repo.get('language', '') lang_badge = f'{repo_lang}' if repo_lang else '' repos_html += f'''
{repo_name}
โ˜… {repo_stars:,} {lang_badge}
{repo_desc}
''' # languages langs_html = '' if languages: sorted_langs = sorted(languages.items(), key=lambda x: x[1], reverse=True)[:10] for lang, count in sorted_langs: langs_html += f'
{lang}ร—{count}
' repos_section = f'''
๐Ÿ”จ what they build ({repo_count} repos, {total_stars:,} โ˜…) โ–ผ
{langs_html}
{repos_html}
''' # communities section (subreddits, etc) communities_section = '' subreddits = extra.get('subreddits', []) topics = extra.get('topics', []) if subreddits or topics: subs_html = '' if subreddits: subs_html = '
subreddits:
' for sub in subreddits: subs_html += f'r/{sub}' subs_html += '
' topics_html = '' if topics: topics_html = '
topics:
' for topic in topics: topics_html += f'{topic}' topics_html += '
' communities_section = f'''
๐Ÿ‘ฅ communities โ–ผ
{subs_html} {topics_html}
''' # contact section contact_html = '
' emails = contact.get('emails', []) if contact.get('email') and contact['email'] not in emails: emails = [contact['email']] + emails if emails: for i, email in enumerate(emails[:3]): preferred = 'preferred' if i == 0 else '' contact_html += f'
๐Ÿ“ง{email}
' if contact.get('mastodon'): contact_html += f'
๐Ÿ˜{contact["mastodon"]}
' if contact.get('matrix'): contact_html += f'
๐Ÿ’ฌ{contact["matrix"]}
' if contact.get('twitter'): contact_html += f'
๐Ÿฆ@{contact["twitter"]}
' if not emails and not contact.get('mastodon') and not contact.get('matrix'): contact_html += '
no contact methods discovered
' contact_html += '
' # raw json raw_json = json.dumps(human, indent=2, default=str) # render return PROFILE_HTML.format( name=name, username=username, platform=platform, bio=bio, score=int(score), user_type=user_type, user_type_class=user_type, avatar=avatar_html, location_html=location_html, pronouns_html=pronouns_html, platforms_html='\n'.join(platforms_html), signals_html='\n'.join(signals_html), signal_count=len(signals), negative_signals_html=negative_signals_html, reasons_html=reasons_html, repos_section=repos_section, communities_section=communities_section, match_count=match_count, lost_score=int(lost_score), contact_html=contact_html, raw_json=raw_json, id=human.get('id', 0) )