added manual post add
This commit is contained in:
@@ -1581,6 +1581,78 @@ async def api_categorize_post(request: Request):
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.post("/api/post-types/manual-posts")
|
||||
async def api_add_manual_post_for_post_types(request: Request):
|
||||
"""Add a manual post from the post types page and optionally assign a type immediately."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
user_id = UUID(session.user_id)
|
||||
post_text = (data.get("post_text") or "").strip()
|
||||
post_type_id_raw = data.get("post_type_id")
|
||||
|
||||
if len(post_text) < 20:
|
||||
return JSONResponse({"error": "Post muss mindestens 20 Zeichen lang sein"}, status_code=400)
|
||||
|
||||
post_type_id = UUID(post_type_id_raw) if post_type_id_raw else None
|
||||
if post_type_id:
|
||||
post_type = await db.get_post_type(post_type_id)
|
||||
if not post_type or post_type.user_id != user_id:
|
||||
return JSONResponse({"error": "Post-Typ nicht gefunden oder kein Zugriff"}, status_code=404)
|
||||
|
||||
from uuid import uuid4
|
||||
from src.database.models import LinkedInPost
|
||||
|
||||
manual_post = LinkedInPost(
|
||||
user_id=user_id,
|
||||
post_text=post_text,
|
||||
post_url=f"manual://{uuid4()}",
|
||||
post_date=datetime.now(timezone.utc),
|
||||
post_type_id=post_type_id,
|
||||
classification_method="manual",
|
||||
classification_confidence=1.0,
|
||||
raw_data={"source": "manual", "manual_entry": True}
|
||||
)
|
||||
saved_posts = await db.save_linkedin_posts([manual_post])
|
||||
saved = saved_posts[0] if saved_posts else None
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"post": {
|
||||
"id": str(saved.id) if saved and saved.id else None,
|
||||
"post_text": saved.post_text if saved else post_text,
|
||||
"post_date": saved.post_date.isoformat() if saved and saved.post_date else None,
|
||||
"post_type_id": str(saved.post_type_id) if saved and saved.post_type_id else None,
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding manual post from post types page: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.delete("/api/post-types/posts/{post_id}")
|
||||
async def api_delete_post_from_post_types_page(request: Request, post_id: str):
|
||||
"""Delete a post from the main post types page."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
|
||||
try:
|
||||
user_id = UUID(session.user_id)
|
||||
post = await db.get_linkedin_post(UUID(post_id))
|
||||
if not post or post.user_id != user_id:
|
||||
return JSONResponse({"error": "Post nicht gefunden oder kein Zugriff"}, status_code=404)
|
||||
|
||||
await db.delete_linkedin_post(UUID(post_id))
|
||||
return JSONResponse({"success": True})
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting post from post types page: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.get("/api/job-updates")
|
||||
async def job_updates_sse(request: Request):
|
||||
"""Server-Sent Events endpoint for job updates (Redis pub/sub — works across workers)."""
|
||||
@@ -4259,6 +4331,250 @@ async def company_save_all_employee_post_types(request: Request, background_task
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.get("/api/employee/post-types/{post_type_id}/posts")
|
||||
async def employee_list_post_type_posts(request: Request, post_type_id: str):
|
||||
"""List posts assigned to a post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "employee":
|
||||
return JSONResponse({"error": "Only employees can access this endpoint"}, status_code=403)
|
||||
|
||||
try:
|
||||
user_id = UUID(session.user_id)
|
||||
pt_id = UUID(post_type_id)
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != user_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
posts = await db.get_posts_by_type(user_id, pt_id)
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"posts": [
|
||||
{
|
||||
"id": str(p.id),
|
||||
"post_text": p.post_text,
|
||||
"post_date": p.post_date.isoformat() if p.post_date else None,
|
||||
"post_url": p.post_url,
|
||||
"classification_method": p.classification_method,
|
||||
}
|
||||
for p in posts
|
||||
]
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error listing employee post type posts: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.post("/api/employee/post-types/posts")
|
||||
async def employee_add_manual_post_to_type(request: Request):
|
||||
"""Add a manual post and assign it to a post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "employee":
|
||||
return JSONResponse({"error": "Only employees can add posts here"}, status_code=403)
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
user_id = UUID(session.user_id)
|
||||
pt_id = UUID(data.get("post_type_id"))
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != user_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
post_text = (data.get("post_text") or "").strip()
|
||||
if len(post_text) < 20:
|
||||
return JSONResponse({"error": "Post muss mindestens 20 Zeichen lang sein"}, status_code=400)
|
||||
|
||||
from uuid import uuid4
|
||||
from src.database.models import LinkedInPost
|
||||
|
||||
manual_post = LinkedInPost(
|
||||
user_id=user_id,
|
||||
post_text=post_text,
|
||||
post_url=f"manual://{uuid4()}",
|
||||
post_date=datetime.now(timezone.utc),
|
||||
post_type_id=pt_id,
|
||||
classification_method="manual",
|
||||
classification_confidence=1.0,
|
||||
raw_data={"source": "manual", "manual_entry": True}
|
||||
)
|
||||
saved_posts = await db.save_linkedin_posts([manual_post])
|
||||
saved = saved_posts[0] if saved_posts else None
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"post": {
|
||||
"id": str(saved.id) if saved and saved.id else None,
|
||||
"post_text": saved.post_text if saved else post_text,
|
||||
"post_date": saved.post_date.isoformat() if saved and saved.post_date else None,
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding manual post for employee post type: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.delete("/api/employee/post-types/{post_type_id}/posts/{post_id}")
|
||||
async def employee_delete_post_from_type(request: Request, post_type_id: str, post_id: str):
|
||||
"""Delete a post assigned to a post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "employee":
|
||||
return JSONResponse({"error": "Only employees can delete posts here"}, status_code=403)
|
||||
|
||||
try:
|
||||
user_id = UUID(session.user_id)
|
||||
pt_id = UUID(post_type_id)
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != user_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
post = await db.get_linkedin_post(UUID(post_id))
|
||||
if not post or post.user_id != user_id or post.post_type_id != pt_id:
|
||||
return JSONResponse({"error": "Post not found or access denied"}, status_code=404)
|
||||
|
||||
await db.delete_linkedin_post(UUID(post_id))
|
||||
return JSONResponse({"success": True})
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting employee post from type: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.get("/api/company/manage/post-types/{post_type_id}/posts")
|
||||
async def company_list_employee_post_type_posts(request: Request, post_type_id: str, employee_id: str):
|
||||
"""Company lists posts assigned to an employee's post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "company" or not session.company_id:
|
||||
return JSONResponse({"error": "Only company accounts can access this endpoint"}, status_code=403)
|
||||
|
||||
try:
|
||||
emp_id = UUID(employee_id)
|
||||
emp_user = await db.get_user(emp_id)
|
||||
if not emp_user or str(emp_user.company_id) != session.company_id:
|
||||
return JSONResponse({"error": "Employee not found or not in company"}, status_code=403)
|
||||
|
||||
pt_id = UUID(post_type_id)
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != emp_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
posts = await db.get_posts_by_type(emp_id, pt_id)
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"posts": [
|
||||
{
|
||||
"id": str(p.id),
|
||||
"post_text": p.post_text,
|
||||
"post_date": p.post_date.isoformat() if p.post_date else None,
|
||||
"post_url": p.post_url,
|
||||
"classification_method": p.classification_method,
|
||||
}
|
||||
for p in posts
|
||||
]
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error listing company-managed employee post type posts: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.post("/api/company/manage/post-types/posts")
|
||||
async def company_add_manual_post_to_employee_type(request: Request):
|
||||
"""Company adds a manual post for an employee and assigns it to a post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "company" or not session.company_id:
|
||||
return JSONResponse({"error": "Only company accounts can add posts here"}, status_code=403)
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
emp_id = UUID(data.get("employee_id"))
|
||||
emp_user = await db.get_user(emp_id)
|
||||
if not emp_user or str(emp_user.company_id) != session.company_id:
|
||||
return JSONResponse({"error": "Employee not found or not in company"}, status_code=403)
|
||||
|
||||
perms = await get_employee_permissions_or_default(emp_id, UUID(session.company_id))
|
||||
if not perms.get("can_manage_post_types", True):
|
||||
return JSONResponse({"error": "Keine Berechtigung"}, status_code=403)
|
||||
|
||||
pt_id = UUID(data.get("post_type_id"))
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != emp_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
post_text = (data.get("post_text") or "").strip()
|
||||
if len(post_text) < 20:
|
||||
return JSONResponse({"error": "Post muss mindestens 20 Zeichen lang sein"}, status_code=400)
|
||||
|
||||
from uuid import uuid4
|
||||
from src.database.models import LinkedInPost
|
||||
|
||||
manual_post = LinkedInPost(
|
||||
user_id=emp_id,
|
||||
post_text=post_text,
|
||||
post_url=f"manual://{uuid4()}",
|
||||
post_date=datetime.now(timezone.utc),
|
||||
post_type_id=pt_id,
|
||||
classification_method="manual",
|
||||
classification_confidence=1.0,
|
||||
raw_data={"source": "manual", "manual_entry": True}
|
||||
)
|
||||
saved_posts = await db.save_linkedin_posts([manual_post])
|
||||
saved = saved_posts[0] if saved_posts else None
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"post": {
|
||||
"id": str(saved.id) if saved and saved.id else None,
|
||||
"post_text": saved.post_text if saved else post_text,
|
||||
"post_date": saved.post_date.isoformat() if saved and saved.post_date else None,
|
||||
}
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding manual post for company-managed employee post type: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.delete("/api/company/manage/post-types/{post_type_id}/posts/{post_id}")
|
||||
async def company_delete_post_from_employee_type(request: Request, post_type_id: str, post_id: str, employee_id: str):
|
||||
"""Company deletes a post assigned to an employee's post type."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
return JSONResponse({"error": "Not authenticated"}, status_code=401)
|
||||
if session.account_type != "company" or not session.company_id:
|
||||
return JSONResponse({"error": "Only company accounts can delete posts here"}, status_code=403)
|
||||
|
||||
try:
|
||||
emp_id = UUID(employee_id)
|
||||
emp_user = await db.get_user(emp_id)
|
||||
if not emp_user or str(emp_user.company_id) != session.company_id:
|
||||
return JSONResponse({"error": "Employee not found or not in company"}, status_code=403)
|
||||
|
||||
perms = await get_employee_permissions_or_default(emp_id, UUID(session.company_id))
|
||||
if not perms.get("can_manage_post_types", True):
|
||||
return JSONResponse({"error": "Keine Berechtigung"}, status_code=403)
|
||||
|
||||
pt_id = UUID(post_type_id)
|
||||
post_type = await db.get_post_type(pt_id)
|
||||
if not post_type or post_type.user_id != emp_id:
|
||||
return JSONResponse({"error": "Post type not found or access denied"}, status_code=404)
|
||||
|
||||
post = await db.get_linkedin_post(UUID(post_id))
|
||||
if not post or post.user_id != emp_id or post.post_type_id != pt_id:
|
||||
return JSONResponse({"error": "Post not found or access denied"}, status_code=404)
|
||||
|
||||
await db.delete_linkedin_post(UUID(post_id))
|
||||
return JSONResponse({"success": True})
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting company-managed employee post from type: {e}")
|
||||
return JSONResponse({"error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.post("/api/employee/post-types/save-all")
|
||||
async def save_all_and_reanalyze(request: Request, background_tasks: BackgroundTasks):
|
||||
"""Save all changes and conditionally trigger re-categorization based on structural changes."""
|
||||
|
||||
Reference in New Issue
Block a user