nordabiz/blueprints/api/routes_social_audit.py
Maciej Pienczyn 4181a2e760 refactor: Migrate access control from is_admin to role-based system
Replace ~170 manual `if not current_user.is_admin` checks with:
- @role_required(SystemRole.ADMIN) for user management, security, ZOPK
- @role_required(SystemRole.OFFICE_MANAGER) for content management
- current_user.can_access_admin_panel() for admin UI access
- current_user.can_moderate_forum() for forum moderation
- current_user.can_edit_company(id) for company permissions

Add @office_manager_required decorator shortcut.
Add SQL migration to sync existing users' role field.

Role hierarchy: UNAFFILIATED(10) < MEMBER(20) < EMPLOYEE(30) < MANAGER(40) < OFFICE_MANAGER(50) < ADMIN(100)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:05:22 +01:00

171 lines
5.8 KiB
Python

"""
Social Audit API Routes - API blueprint
Migrated from app.py as part of the blueprint refactoring.
Contains API routes for Social Media audit functionality.
"""
import logging
import sys
from pathlib import Path
from flask import jsonify, request
from flask_login import current_user, login_required
from database import SessionLocal, Company
from . import bp
logger = logging.getLogger(__name__)
# ============================================================
# SOCIAL MEDIA AUDIT API ROUTES
# ============================================================
@bp.route('/social/audit', methods=['POST'])
@login_required
def api_social_audit_trigger():
"""
API: Trigger Social Media audit for a company.
This endpoint performs a comprehensive social media audit:
- Scans company website for social media links
- Searches for profiles via Brave Search API (if configured)
- Fetches Google Business Profile data
- Updates database with discovered profiles
Request JSON body:
- company_id: Company ID (integer) OR
- slug: Company slug (string)
Returns:
- Success: Updated social media audit results
- Error: Error message with status code
Rate limited to 10 requests per hour per user.
"""
# Import the SocialMediaAuditor from scripts
try:
scripts_dir = Path(__file__).parent.parent.parent / 'scripts'
if str(scripts_dir) not in sys.path:
sys.path.insert(0, str(scripts_dir))
from social_media_audit import SocialMediaAuditor
except ImportError as e:
logger.error(f"Failed to import SocialMediaAuditor: {e}")
return jsonify({
'success': False,
'error': 'Usługa audytu Social Media jest niedostępna. Sprawdź konfigurację serwera.'
}), 503
# Parse request data
data = request.get_json()
if not data:
return jsonify({
'success': False,
'error': 'Brak danych w żądaniu. Podaj company_id lub slug.'
}), 400
company_id = data.get('company_id')
slug = data.get('slug')
if not company_id and not slug:
return jsonify({
'success': False,
'error': 'Podaj company_id lub slug firmy do audytu.'
}), 400
db = SessionLocal()
try:
# Find company by ID or slug
if company_id:
company = db.query(Company).filter_by(id=company_id, status='active').first()
else:
company = db.query(Company).filter_by(slug=slug, status='active').first()
if not company:
return jsonify({
'success': False,
'error': 'Firma nie znaleziona lub nieaktywna.'
}), 404
# Access control - users with admin panel access or company edit rights can audit
if not current_user.can_edit_company(company.id):
return jsonify({
'success': False,
'error': 'Brak uprawnień do audytu social media tej firmy.'
}), 403
logger.info(f"Social Media audit triggered by {current_user.email} for company: {company.name} (ID: {company.id})")
# Prepare company dict for auditor
company_dict = {
'id': company.id,
'name': company.name,
'slug': company.slug,
'website': company.website,
'address_city': company.address_city or 'Wejherowo'
}
# Initialize auditor and run audit
try:
auditor = SocialMediaAuditor()
audit_result = auditor.audit_company(company_dict)
# Check for errors
if audit_result.get('errors') and not audit_result.get('social_media') and not audit_result.get('website'):
return jsonify({
'success': False,
'error': f'Audyt nie powiódł się: {", ".join(audit_result["errors"][:3])}',
'company_id': company.id,
'company_name': company.name
}), 422
# Save result to database
saved = auditor.save_audit_result(audit_result)
if not saved:
return jsonify({
'success': False,
'error': 'Audyt został wykonany, ale nie udało się zapisać wyników do bazy danych.',
'company_id': company.id,
'company_name': company.name
}), 500
# Get count of social media profiles found
social_media_found = audit_result.get('social_media', {})
platforms_count = len(social_media_found)
# Calculate score
all_platforms = ['facebook', 'instagram', 'linkedin', 'youtube', 'twitter', 'tiktok']
score = int((platforms_count / len(all_platforms)) * 100)
return jsonify({
'success': True,
'message': f'Audyt Social Media zakończony. Znaleziono {platforms_count} profili.',
'company_id': company.id,
'company_name': company.name,
'profiles_found': platforms_count,
'platforms': list(social_media_found.keys()),
'score': score,
'google_reviews': audit_result.get('google_reviews', {}),
'errors': audit_result.get('errors') if audit_result.get('errors') else None
}), 200
except Exception as e:
logger.error(f"Social Media audit error for company {company.id}: {e}")
return jsonify({
'success': False,
'error': f'Błąd podczas audytu: {str(e)}'
}), 500
except Exception as e:
logger.error(f"Social Media audit error for company {slug or company_id}: {e}")
db.rollback()
return jsonify({
'success': False,
'error': f'Błąd podczas audytu: {str(e)}'
}), 500
finally:
db.close()