feat: capture and display Google account email for OAuth connections
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

After token exchange, fetches Google userinfo to save the email and
name of the Google account used for authorization. Displays this info
on the GBP audit page so users know which account to reconnect with.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-11 07:32:43 +01:00
parent 997009d88c
commit 555cb99c86
3 changed files with 28 additions and 2 deletions

View File

@ -521,6 +521,8 @@ def gbp_audit_dashboard(slug):
'created_at': gbp_oauth_token.created_at, 'created_at': gbp_oauth_token.created_at,
'expires_at': gbp_oauth_token.expires_at, 'expires_at': gbp_oauth_token.expires_at,
'has_refresh_token': bool(gbp_oauth_token.refresh_token), 'has_refresh_token': bool(gbp_oauth_token.refresh_token),
'google_email': gbp_oauth_token.account_id,
'google_name': gbp_oauth_token.account_name,
} }
logger.info(f"GBP audit dashboard viewed by {current_user.email} for company: {company.name}") logger.info(f"GBP audit dashboard viewed by {current_user.email} for company: {company.name}")

View File

@ -141,7 +141,24 @@ class OAuthService:
if response.status_code != 200: if response.status_code != 200:
logger.error(f"OAuth token exchange failed for {provider}: {response.status_code} - {response.text}") logger.error(f"OAuth token exchange failed for {provider}: {response.status_code} - {response.text}")
return None return None
return response.json() token_data = response.json()
# For Google: fetch user email to identify which account was used
if provider == 'google' and token_data.get('access_token'):
try:
userinfo_resp = requests.get(
'https://www.googleapis.com/oauth2/v2/userinfo',
headers={'Authorization': f"Bearer {token_data['access_token']}"},
timeout=10
)
if userinfo_resp.status_code == 200:
userinfo = userinfo_resp.json()
token_data['google_email'] = userinfo.get('email')
token_data['google_name'] = userinfo.get('name')
except Exception as e:
logger.warning(f"Could not fetch Google userinfo: {e}")
return token_data
except Exception as e: except Exception as e:
logger.error(f"OAuth token exchange error for {provider}: {e}") logger.error(f"OAuth token exchange error for {provider}: {e}")
return None return None
@ -264,6 +281,11 @@ class OAuthService:
token.is_active = True token.is_active = True
token.updated_at = datetime.now() token.updated_at = datetime.now()
# Save Google account identity if available
if token_data.get('google_email'):
token.account_id = token_data['google_email']
token.account_name = token_data.get('google_name', token_data['google_email'])
db.commit() db.commit()
logger.info(f"OAuth token saved: {provider}/{service} for company {company_id}") logger.info(f"OAuth token saved: {provider}/{service} for company {company_id}")
return True return True

View File

@ -970,6 +970,7 @@
<strong style="color: #16a34a;">Konsola Google Business Profile połączona</strong> <strong style="color: #16a34a;">Konsola Google Business Profile połączona</strong>
<p style="margin: 2px 0 0; font-size: var(--font-size-xs); color: var(--text-secondary);"> <p style="margin: 2px 0 0; font-size: var(--font-size-xs); color: var(--text-secondary);">
Dostępne są pełne dane: wyświetlenia, wyszukiwania, kliknięcia i interakcje klientów. Dostępne są pełne dane: wyświetlenia, wyszukiwania, kliknięcia i interakcje klientów.
{% if gbp_connection.google_email %}Konto: <strong>{{ gbp_connection.google_email }}</strong>.{% endif %}
{% if gbp_connection.created_at %}Połączone od {{ gbp_connection.created_at.strftime('%d.%m.%Y') }}.{% endif %} {% if gbp_connection.created_at %}Połączone od {{ gbp_connection.created_at.strftime('%d.%m.%Y') }}.{% endif %}
</p> </p>
</div> </div>
@ -982,7 +983,8 @@
<strong style="color: #d97706;">Połączenie z konsolą GBP wygasło</strong> <strong style="color: #d97706;">Połączenie z konsolą GBP wygasło</strong>
<p style="margin: 2px 0 0; font-size: var(--font-size-xs); color: var(--text-secondary);"> <p style="margin: 2px 0 0; font-size: var(--font-size-xs); color: var(--text-secondary);">
Autoryzacja Google wygasła{% if gbp_connection.expires_at %} {{ gbp_connection.expires_at.strftime('%d.%m.%Y') }}{% endif %}. Autoryzacja Google wygasła{% if gbp_connection.expires_at %} {{ gbp_connection.expires_at.strftime('%d.%m.%Y') }}{% endif %}.
Dane audytu pochodzą z publicznego API. Połącz ponownie, aby uzyskać pełne statystyki. {% if gbp_connection.google_email %}Ostatnio użyte konto: <strong>{{ gbp_connection.google_email }}</strong>.{% endif %}
Połącz ponownie tym samym kontem, aby przywrócić pełne statystyki.
</p> </p>
</div> </div>
<a href="{{ url_for('auth.konto_integracje') }}" class="btn btn-sm" style="background: #d97706; color: white; border: none; white-space: nowrap;">Połącz ponownie</a> <a href="{{ url_for('auth.konto_integracje') }}" class="btn btn-sm" style="background: #d97706; color: white; border: none; white-space: nowrap;">Połącz ponownie</a>