fix(oauth): Move OAuth flow to user-facing /konto/integracje route
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

Company users should connect their own Google/Meta accounts, not admins.
- Add /konto/integracje route for company users (auth blueprint)
- OAuth callbacks now redirect to /konto/integracje
- Template breadcrumb adapts to user vs admin view
- Admin route /admin/companies/<id>/settings kept for admin access

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-02-08 16:25:52 +01:00
parent 70e40d133b
commit 5616ae8561
3 changed files with 52 additions and 9 deletions

View File

@ -78,10 +78,8 @@ def oauth_callback(provider):
pass
def settings_redirect(params):
"""Redirect to company settings page with query params."""
if state_company_id:
return redirect(f'/admin/companies/{state_company_id}/settings?{params}')
return redirect(f'/admin/companies?{params}')
"""Redirect to user's integrations page with query params."""
return redirect(f'/konto/integracje?{params}')
if error:
logger.warning(f"OAuth error from {provider}: {error}")
@ -107,14 +105,14 @@ def oauth_callback(provider):
# Verify user owns this company
if current_user.id != user_id or current_user.company_id != company_id:
return redirect(f'/admin/companies/{company_id}/settings?oauth_error=unauthorized')
return redirect(f'/konto/integracje?oauth_error=unauthorized')
# Exchange code for token
oauth = OAuthService()
token_data = oauth.exchange_code(provider, code)
if not token_data:
return redirect(f'/admin/companies/{company_id}/settings?oauth_error=token_exchange_failed')
return redirect(f'/konto/integracje?oauth_error=token_exchange_failed')
# Save token
db = SessionLocal()
@ -122,9 +120,9 @@ def oauth_callback(provider):
success = oauth.save_token(db, company_id, user_id, provider, service, token_data)
if success:
logger.info(f"OAuth connected: {provider}/{service} for company {company_id} by user {user_id}")
return redirect(f'/admin/companies/{company_id}/settings?oauth_success={provider}/{service}')
return redirect(f'/konto/integracje?oauth_success={provider}/{service}')
else:
return redirect(f'/admin/companies/{company_id}/settings?oauth_error=save_failed')
return redirect(f'/konto/integracje?oauth_error=save_failed')
finally:
db.close()

View File

@ -843,6 +843,45 @@ def konto_blokady_dodaj():
return redirect(url_for('auth.konto_blokady'))
@bp.route('/konto/integracje')
@login_required
def konto_integracje():
"""OAuth integrations page for company users.
Allows company users to connect their Google/Meta accounts
for enriched audit data (GBP reviews, Search Console, Facebook insights).
"""
if not current_user.company_id:
flash('Musisz byc przypisany do firmy, aby korzystac z integracji.', 'info')
return redirect(url_for('auth.konto_dane'))
db = SessionLocal()
try:
company = db.query(Company).filter(Company.id == current_user.company_id).first()
if not company:
flash('Firma nie istnieje.', 'error')
return redirect(url_for('auth.konto_dane'))
from oauth_service import OAuthService
oauth = OAuthService()
connections = oauth.get_connected_services(db, current_user.company_id)
oauth_available = {
'google': bool(oauth.google_client_id),
'meta': bool(oauth.meta_app_id),
}
return render_template(
'admin/company_settings.html',
company=company,
connections=connections,
oauth_available=oauth_available,
is_user_view=True,
)
finally:
db.close()
@bp.route('/konto/blokady/usun/<int:block_id>', methods=['POST'])
@login_required
def konto_blokady_usun(block_id):

View File

@ -277,13 +277,19 @@
<!-- Breadcrumb -->
<div class="settings-header">
<div class="breadcrumb">
{% if is_user_view %}
<a href="{{ url_for('auth.konto_dane') }}">Moje konto</a>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
<span>Integracje</span>
{% else %}
<a href="{{ url_for('admin.admin_companies') }}">Firmy</a>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
<a href="{{ url_for('admin.admin_company_get', company_id=company.id) }}">{{ company.name }}</a>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
<span>Ustawienia</span>
{% endif %}
</div>
<h1>Ustawienia firmy</h1>
<h1>{% if is_user_view %}Integracje{% else %}Ustawienia firmy{% endif %}</h1>
<p class="settings-subtitle">{{ company.name }} — integracje z zewnętrznymi serwisami</p>
</div>