refactor: show tg avatar in detached browser

This commit is contained in:
3252a8
2026-04-24 21:31:58 +03:00
parent 5ccb8ddabe
commit 651572f15f
5 changed files with 68 additions and 15 deletions
+15
View File
@@ -854,6 +854,14 @@ async def _sync_panel_identity_for_user(request: web.Request, user: User) -> Non
)
def _telegram_photo_url_value(telegram_user: Dict[str, Any]) -> Optional[str]:
raw_value = telegram_user.get("photo_url")
if not raw_value:
return None
value = str(raw_value).strip()
return value or None
def _apply_telegram_profile_to_user(
user: User,
telegram_user: Dict[str, Any],
@@ -868,6 +876,9 @@ def _apply_telegram_profile_to_user(
user.first_name = sanitize_display_name(telegram_user.get("first_name"))
user.last_name = sanitize_display_name(telegram_user.get("last_name"))
user.language_code = language_code
telegram_photo_url = _telegram_photo_url_value(telegram_user)
if telegram_photo_url:
user.telegram_photo_url = telegram_photo_url
async def _link_telegram_to_user(
@@ -1067,6 +1078,9 @@ async def _ensure_user_from_telegram(
"last_name": sanitize_display_name(telegram_user.get("last_name")),
"language_code": language_code,
}
telegram_photo_url = _telegram_photo_url_value(telegram_user)
if telegram_photo_url:
update_data["telegram_photo_url"] = telegram_photo_url
db_user = await user_dal.get_user_by_telegram_id(session, user_id)
if not db_user:
@@ -1153,6 +1167,7 @@ async def _build_user_payload(request: web.Request, user_id: int) -> Dict[str, A
"email_verified": bool(db_user.email_verified_at),
"telegram_id": db_user.telegram_id,
"telegram_linked": bool(_telegram_id_for_user(db_user)),
"telegram_photo_url": db_user.telegram_photo_url,
"first_name": db_user.first_name,
"language_code": lang,
},
+34 -14
View File
@@ -615,7 +615,7 @@ const MOCK = (() => {
script.src = TELEGRAM_LOGIN_WIDGET_URL;
script.setAttribute('data-telegram-login', botUsername);
script.setAttribute('data-size', 'large');
script.setAttribute('data-userpic', 'false');
script.setAttribute('data-userpic', 'true');
script.setAttribute('data-request-access', 'write');
script.setAttribute('data-onauth', 'onTelegramAuth(user)');
script.onerror = () => setAuthStatus(t('telegram_auth_unavailable'), true);
@@ -1003,7 +1003,8 @@ const MOCK = (() => {
const telegramLinked = Boolean(user.telegram_linked);
const displayName = getUserDisplayName(user);
const secondary = getUserSecondaryText(user, emailLinked, telegramLinked);
const avatar = getUserAvatarSrc(user, emailLinked);
const avatarSrc = getUserAvatarSrc(user);
const avatarFallback = buildIdenticon(getUserAvatarSeed(user, emailLinked));
const chipName = document.getElementById('user-chip-name');
const chipAvatar = document.getElementById('user-chip-avatar');
@@ -1014,10 +1015,8 @@ const MOCK = (() => {
const telegramStatus = document.getElementById('user-dropdown-telegram-status');
chipName.textContent = displayName;
chipAvatar.src = avatar;
chipAvatar.alt = displayName;
dropAvatar.src = avatar;
dropAvatar.alt = displayName;
setAvatarWithFallback(chipAvatar, avatarSrc, avatarFallback, displayName);
setAvatarWithFallback(dropAvatar, avatarSrc, avatarFallback, displayName);
dropName.textContent = displayName;
dropSub.textContent = secondary;
dropSub.classList.toggle('hidden', !secondary);
@@ -1059,6 +1058,19 @@ const MOCK = (() => {
return tg.initDataUnsafe.user;
}
function getUserAvatarSeed(user, emailLinked) {
const tgUser = getTelegramInitUser();
if (emailLinked && user && user.email) return user.email.trim().toLowerCase();
return String((user && user.id) || (user && user.telegram_id) || (tgUser && tgUser.id) || 'guest');
}
function getUserAvatarSrc(user) {
const tgUser = getTelegramInitUser();
if (tgUser && tgUser.photo_url) return tgUser.photo_url;
if (user && user.telegram_photo_url) return user.telegram_photo_url;
return '';
}
function getUserDisplayName(user) {
const tgUser = getTelegramInitUser();
if (tgUser && tgUser.first_name) return tgUser.first_name;
@@ -1075,13 +1087,21 @@ const MOCK = (() => {
return '';
}
function getUserAvatarSrc(user, emailLinked) {
const tgUser = getTelegramInitUser();
if (tgUser && tgUser.photo_url) return tgUser.photo_url;
const seed = (emailLinked && user.email)
? user.email.trim().toLowerCase()
: String(user.id || user.telegram_id || tgUser && tgUser.id || 'guest');
return buildIdenticon(seed);
function setAvatarWithFallback(img, avatarSrc, avatarFallback, altText) {
if (!img) return;
img.alt = altText || '';
if (!avatarSrc) {
img.onerror = null;
img.src = avatarFallback;
return;
}
img.onerror = () => {
img.onerror = null;
img.src = avatarFallback;
};
img.src = avatarSrc;
}
function buildIdenticon(seed) {
@@ -1460,7 +1480,7 @@ const MOCK = (() => {
script.src = TELEGRAM_LOGIN_WIDGET_URL;
script.setAttribute('data-telegram-login', botUsername);
script.setAttribute('data-size', 'large');
script.setAttribute('data-userpic', 'false');
script.setAttribute('data-userpic', 'true');
script.setAttribute('data-request-access', 'write');
script.setAttribute('data-onauth', 'onTelegramLinkAuth(user)');
script.onerror = () => setTelegramLinkStatus(t('telegram_auth_unavailable'), true);
+1 -1
View File
@@ -287,7 +287,7 @@ async def merge_users(
if referral_code_to_move:
target.referral_code = referral_code_to_move
for attr in ("username", "first_name", "last_name", "language_code"):
for attr in ("username", "first_name", "last_name", "language_code", "telegram_photo_url"):
if not getattr(target, attr) and getattr(source, attr):
setattr(target, attr, getattr(source, attr))
if not target.referred_by_id and source.referred_by_id != target_user_id:
+17
View File
@@ -239,6 +239,18 @@ def _migration_0006_add_security_throttles(connection: Connection) -> None:
)
)
def _migration_0007_add_telegram_photo_url(connection: Connection) -> None:
inspector = inspect(connection)
columns: Set[str] = {col["name"] for col in inspector.get_columns("users")}
if "telegram_photo_url" in columns:
return
connection.execute(
text("ALTER TABLE users ADD COLUMN telegram_photo_url TEXT")
)
MIGRATIONS: List[Migration] = [
Migration(
id="0001_add_channel_subscription_fields",
@@ -270,6 +282,11 @@ MIGRATIONS: List[Migration] = [
description="Add generic lockout tracking for brute-force protection",
upgrade=_migration_0006_add_security_throttles,
),
Migration(
id="0007_add_telegram_photo_url",
description="Store Telegram profile photo URLs for linked users",
upgrade=_migration_0007_add_telegram_photo_url,
),
]
+1
View File
@@ -17,6 +17,7 @@ class User(Base):
email = Column(String, nullable=True, unique=True, index=True)
email_verified_at = Column(DateTime(timezone=True), nullable=True)
telegram_id = Column(BigInteger, nullable=True, unique=True, index=True)
telegram_photo_url = Column(Text, nullable=True)
first_name = Column(String, nullable=True)
last_name = Column(String, nullable=True)
language_code = Column(String, default="ru")