refactor: show tg avatar in detached browser
This commit is contained in:
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user