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
Audits (SEO, IT, GBP, Social Media) are now visible only to the designated audit owner (maciej.pienczyn@inpi.pl). All other users, including admins, see 404 for audit routes and no audit links in navigation. KRS Audit and Digital Maturity remain unchanged. Adds /admin/access-overview panel showing the access matrix. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
174 lines
5.9 KiB
Python
174 lines
5.9 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 abort, jsonify, request
|
|
from flask_login import current_user, login_required
|
|
from utils.decorators import is_audit_owner
|
|
|
|
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.
|
|
"""
|
|
if not is_audit_owner():
|
|
abort(404)
|
|
# 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()
|