Improved features, implemented moco integration
This commit is contained in:
@@ -29,7 +29,7 @@ from src.services.email_service import (
|
||||
send_approval_request_email,
|
||||
send_decision_notification_email,
|
||||
validate_token,
|
||||
mark_token_used
|
||||
mark_token_used,
|
||||
)
|
||||
from src.services.background_jobs import (
|
||||
job_manager, JobType, JobStatus,
|
||||
@@ -1241,36 +1241,41 @@ async def dashboard(request: Request):
|
||||
|
||||
if session.company_id:
|
||||
try:
|
||||
company = await db.get_company(UUID(session.company_id))
|
||||
employees_raw = await db.get_company_employees(UUID(session.company_id))
|
||||
pending_invitations = await db.get_pending_invitations(UUID(session.company_id))
|
||||
quota = await db.get_company_daily_quota(UUID(session.company_id))
|
||||
license_key = await db.get_company_limits(UUID(session.company_id))
|
||||
company_id_uuid = UUID(session.company_id)
|
||||
company, employees_raw, pending_invitations, quota, license_key = await asyncio.gather(
|
||||
db.get_company(company_id_uuid),
|
||||
db.get_company_employees(company_id_uuid),
|
||||
db.get_pending_invitations(company_id_uuid),
|
||||
db.get_company_daily_quota(company_id_uuid),
|
||||
db.get_company_limits(company_id_uuid),
|
||||
)
|
||||
except Exception as company_error:
|
||||
logger.warning(f"Could not load company data for {session.company_id}: {company_error}")
|
||||
# Continue without company data - better than crashing
|
||||
|
||||
# Add avatar URLs to employees
|
||||
employees = []
|
||||
for emp in employees_raw:
|
||||
emp_session = UserSession(
|
||||
# Add avatar URLs to employees (parallel)
|
||||
def _make_emp_session(emp):
|
||||
return UserSession(
|
||||
user_id=str(emp.id),
|
||||
linkedin_picture=emp.linkedin_picture,
|
||||
email=emp.email,
|
||||
account_type=emp.account_type.value if hasattr(emp.account_type, 'value') else emp.account_type,
|
||||
display_name=emp.display_name
|
||||
)
|
||||
avatar_url = await get_user_avatar(emp_session, emp.id)
|
||||
|
||||
# Create employee dict with avatar
|
||||
emp_dict = {
|
||||
emp_sessions = [_make_emp_session(emp) for emp in employees_raw]
|
||||
avatar_urls = await asyncio.gather(*[get_user_avatar(s, emp.id) for s, emp in zip(emp_sessions, employees_raw)])
|
||||
|
||||
employees = [
|
||||
{
|
||||
"id": emp.id,
|
||||
"email": emp.email,
|
||||
"display_name": emp.display_name or emp.linkedin_name or emp.email,
|
||||
"onboarding_status": emp.onboarding_status,
|
||||
"avatar_url": avatar_url
|
||||
}
|
||||
employees.append(emp_dict)
|
||||
for emp, avatar_url in zip(employees_raw, avatar_urls)
|
||||
]
|
||||
|
||||
user_id = UUID(session.user_id)
|
||||
profile_picture = await get_user_avatar(session, user_id)
|
||||
@@ -1586,14 +1591,13 @@ async def post_detail_page(request: Request, post_id: str):
|
||||
if str(post.user_id) != session.user_id:
|
||||
return RedirectResponse(url="/posts", status_code=302)
|
||||
|
||||
profile = await db.get_profile(post.user_id)
|
||||
linkedin_posts = await db.get_linkedin_posts(post.user_id)
|
||||
profile, linkedin_posts, profile_picture_url, profile_analysis_record = await asyncio.gather(
|
||||
db.get_profile(post.user_id),
|
||||
db.get_linkedin_posts(post.user_id),
|
||||
get_user_avatar(session, post.user_id),
|
||||
db.get_profile_analysis(post.user_id),
|
||||
)
|
||||
reference_posts = [p.post_text for p in linkedin_posts if p.post_text and len(p.post_text) > 100][:10]
|
||||
|
||||
# Get avatar with priority: LinkedInAccount > profile_picture > session.linkedin_picture
|
||||
profile_picture_url = await get_user_avatar(session, post.user_id)
|
||||
|
||||
profile_analysis_record = await db.get_profile_analysis(post.user_id)
|
||||
profile_analysis = profile_analysis_record.full_analysis if profile_analysis_record else None
|
||||
|
||||
post_type = None
|
||||
@@ -2198,7 +2202,7 @@ async def update_post_status(
|
||||
if status == "approved" and profile and profile.customer_email:
|
||||
# Build base URL from request
|
||||
base_url = str(request.base_url).rstrip('/')
|
||||
email_sent = send_approval_request_email(
|
||||
email_sent = await send_approval_request_email(
|
||||
to_email=profile.customer_email,
|
||||
post_id=UUID(post_id),
|
||||
post_title=post.topic_title or "Untitled Post",
|
||||
@@ -2235,6 +2239,9 @@ async def update_post(
|
||||
if str(post.user_id) != session.user_id:
|
||||
raise HTTPException(status_code=403, detail="Not authorized")
|
||||
|
||||
if len(content) > 3000:
|
||||
raise HTTPException(status_code=422, detail="Post überschreitet 3000-Zeichen-Limit")
|
||||
|
||||
# Save as new version
|
||||
writer_versions = post.writer_versions or []
|
||||
writer_versions.append(content)
|
||||
@@ -2265,7 +2272,7 @@ async def update_post(
|
||||
@user_router.get("/api/email-action/{token}", response_class=HTMLResponse)
|
||||
async def handle_email_action(request: Request, token: str):
|
||||
"""Handle email action (approve/reject) from email link."""
|
||||
token_data = validate_token(token)
|
||||
token_data = await validate_token(token)
|
||||
|
||||
if not token_data:
|
||||
return templates.TemplateResponse("email_action_result.html", {
|
||||
@@ -2306,7 +2313,7 @@ async def handle_email_action(request: Request, token: str):
|
||||
await db.update_generated_post(post_id, {"status": new_status})
|
||||
|
||||
# Mark token as used
|
||||
mark_token_used(token)
|
||||
await mark_token_used(token)
|
||||
|
||||
# Send notification to creator
|
||||
if profile and profile.creator_email:
|
||||
@@ -2713,27 +2720,30 @@ async def company_manage_page(request: Request, employee_id: str = None):
|
||||
all_employees = await db.get_company_employees(company_id)
|
||||
active_employees = [emp for emp in all_employees if emp.onboarding_status == "completed"]
|
||||
|
||||
# Build display info for employees with correct avatar URLs
|
||||
# Build display info for employees with correct avatar URLs (parallel)
|
||||
# Note: emp is a User object from get_company_employees which has linkedin_name and linkedin_picture
|
||||
active_employees_info = []
|
||||
for emp in active_employees:
|
||||
# Create minimal session for employee to get avatar
|
||||
emp_session = UserSession(
|
||||
def _make_emp_session_manage(emp):
|
||||
return UserSession(
|
||||
user_id=str(emp.id),
|
||||
linkedin_picture=emp.linkedin_picture,
|
||||
email=emp.email,
|
||||
account_type=emp.account_type.value if hasattr(emp.account_type, 'value') else emp.account_type,
|
||||
display_name=emp.display_name
|
||||
)
|
||||
avatar_url = await get_user_avatar(emp_session, emp.id)
|
||||
|
||||
active_employees_info.append({
|
||||
emp_sessions_manage = [_make_emp_session_manage(emp) for emp in active_employees]
|
||||
emp_avatars = await asyncio.gather(*[get_user_avatar(s, emp.id) for s, emp in zip(emp_sessions_manage, active_employees)])
|
||||
|
||||
active_employees_info = [
|
||||
{
|
||||
"id": str(emp.id),
|
||||
"email": emp.email,
|
||||
"display_name": emp.linkedin_name or emp.display_name or emp.email,
|
||||
"linkedin_picture": avatar_url, # Now contains the correct avatar with priority
|
||||
"linkedin_picture": avatar_url,
|
||||
"onboarding_status": emp.onboarding_status
|
||||
})
|
||||
}
|
||||
for emp, avatar_url in zip(active_employees, emp_avatars)
|
||||
]
|
||||
|
||||
# Selected employee data
|
||||
selected_employee = None
|
||||
@@ -2749,10 +2759,11 @@ async def company_manage_page(request: Request, employee_id: str = None):
|
||||
break
|
||||
|
||||
if selected_employee:
|
||||
# Get employee's user_id
|
||||
emp_profile = await db.get_profile(UUID(employee_id))
|
||||
emp_profile, employee_posts = await asyncio.gather(
|
||||
db.get_profile(UUID(employee_id)),
|
||||
db.get_generated_posts(UUID(employee_id)),
|
||||
)
|
||||
if emp_profile:
|
||||
employee_posts = await db.get_generated_posts(emp_profile.id)
|
||||
pending_posts = len([p for p in employee_posts if p.status in ['draft', 'pending']])
|
||||
approved_posts = len([p for p in employee_posts if p.status in ['approved', 'published']])
|
||||
|
||||
@@ -2827,24 +2838,25 @@ async def company_manage_post_detail(request: Request, post_id: str, employee_id
|
||||
if not employee_id:
|
||||
return RedirectResponse(url="/company/manage", status_code=302)
|
||||
|
||||
# Get employee info
|
||||
emp_profile = await db.get_profile(UUID(employee_id))
|
||||
# Get employee info + post in parallel
|
||||
emp_profile, emp_user, post = await asyncio.gather(
|
||||
db.get_profile(UUID(employee_id)),
|
||||
db.get_user(UUID(employee_id)),
|
||||
db.get_generated_post(UUID(post_id)),
|
||||
)
|
||||
if not emp_profile:
|
||||
return RedirectResponse(url="/company/manage", status_code=302)
|
||||
|
||||
# Verify employee belongs to this company
|
||||
emp_user = await db.get_user(UUID(employee_id))
|
||||
if not emp_user or str(emp_user.company_id) != session.company_id:
|
||||
return RedirectResponse(url="/company/manage", status_code=302)
|
||||
|
||||
post = await db.get_generated_post(UUID(post_id))
|
||||
if not post or str(post.user_id) != str(emp_profile.id):
|
||||
return RedirectResponse(url=f"/company/manage/posts?employee_id={employee_id}", status_code=302)
|
||||
|
||||
profile = await db.get_profile(emp_profile.id)
|
||||
profile = emp_profile # same object - no second DB call needed
|
||||
|
||||
# Get employee's avatar
|
||||
# Note: Create minimal session for the employee to use get_user_avatar
|
||||
emp_session = UserSession(
|
||||
user_id=str(emp_profile.id),
|
||||
linkedin_picture=emp_user.linkedin_picture,
|
||||
|
||||
Reference in New Issue
Block a user