117 lines
3.8 KiB
Python
117 lines
3.8 KiB
Python
# retoor <retoor@molodetz.nl>
|
|||
|
|
|
||
|
|
import logging
|
||
|
|
|
||
|
|
from fastapi import APIRouter, Request
|
||
|
|
from fastapi.responses import HTMLResponse
|
||
|
|
|
||
|
|
from devplacepy.database import (
|
||
|
|
build_pagination,
|
||
|
|
db,
|
||
|
|
get_maturity_by_targets,
|
||
|
|
get_table,
|
||
|
|
get_users_by_uids,
|
||
|
|
)
|
||
|
|
from devplacepy.content import can_view_project
|
||
|
|
from devplacepy.responses import respond
|
||
|
|
from devplacepy.schemas import WorkspaceIndexOut
|
||
|
|
from devplacepy.seo import base_seo_context, public_base_url, site_url, website_schema
|
||
|
|
from devplacepy.utils import get_current_user
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
PER_PAGE = 50
|
||
|
|
|
||
|
|
|
||
|
|
def published_instances() -> list[dict]:
|
||
|
|
if "instances" not in db.tables:
|
||
|
|
return []
|
||
|
|
table = get_table("instances")
|
||
|
|
if not table.has_column("ingress_slug"):
|
||
|
|
return []
|
||
|
|
rows = [
|
||
|
|
row
|
||
|
|
for row in table.find(deleted_at=None, order_by=["-created_at"])
|
||
|
|
if (row.get("ingress_slug") or "").strip()
|
||
|
|
]
|
||
|
|
return rows
|
||
|
|
|
||
|
|
|
||
|
|
def projects_by_uids(uids: list[str]) -> dict[str, dict]:
|
||
|
|
unique = [uid for uid in set(uids) if uid]
|
||
|
|
if not unique or "projects" not in db.tables:
|
||
|
|
return {}
|
||
|
|
table = get_table("projects")
|
||
|
|
return {
|
||
|
|
row["uid"]: row for row in table.find(table.table.columns.uid.in_(unique))
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def index_entries(rows: list[dict], user: dict | None) -> list[dict]:
|
||
|
|
projects = projects_by_uids([row.get("project_uid", "") for row in rows])
|
||
|
|
owners = get_users_by_uids(
|
||
|
|
[row.get("owner_uid") or row.get("created_by") for row in rows]
|
||
|
|
)
|
||
|
|
maturity = get_maturity_by_targets("workspace", [row["uid"] for row in rows])
|
||
|
|
base = public_base_url()
|
||
|
|
entries = []
|
||
|
|
for row in rows:
|
||
|
|
project = projects.get(row.get("project_uid", ""))
|
||
|
|
if not can_view_project(project, user):
|
||
|
|
project = None
|
||
|
|
owner_uid = row.get("owner_uid") or row.get("created_by") or ""
|
||
|
|
owner = owners.get(owner_uid)
|
||
|
|
slug = row["ingress_slug"]
|
||
|
|
project_slug = (project or {}).get("slug") or (project or {}).get("uid") or ""
|
||
|
|
entries.append(
|
||
|
|
{
|
||
|
|
"uid": row["uid"],
|
||
|
|
"name": row.get("name") or slug,
|
||
|
|
"slug": slug,
|
||
|
|
"owner_uid": owner_uid,
|
||
|
|
"url": f"{base}/p/{slug}" if base else f"/p/{slug}",
|
||
|
|
"description": (project or {}).get("description", "") or "",
|
||
|
|
"owner": owner["username"] if owner else "",
|
||
|
|
"maturity": maturity.get(row["uid"], {}).get("level", "general"),
|
||
|
|
"project_url": f"/projects/{project_slug}" if project_slug else "",
|
||
|
|
}
|
||
|
|
)
|
||
|
|
return entries
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/index", response_class=HTMLResponse)
|
||
|
|
async def workspace_index(request: Request, page: int = 1):
|
||
|
|
user = get_current_user(request)
|
||
|
|
rows = published_instances()
|
||
|
|
pagination = build_pagination(page, len(rows), PER_PAGE)
|
||
|
|
offset = (pagination["page"] - 1) * pagination["per_page"]
|
||
|
|
window = rows[offset : offset + pagination["per_page"]]
|
||
|
|
base = site_url(request)
|
||
|
|
seo_ctx = base_seo_context(
|
||
|
|
request,
|
||
|
|
title="Published workspaces",
|
||
|
|
description=(
|
||
|
|
"Every workspace DevPlace members have published to the public ingress, "
|
||
|
|
"with its owner, project and direct link."
|
||
|
|
),
|
||
|
|
breadcrumbs=[
|
||
|
|
{"name": "Home", "url": "/feed"},
|
||
|
|
{"name": "Published workspaces", "url": "/workspaces/index"},
|
||
|
|
],
|
||
|
|
schemas=[website_schema(base)],
|
||
|
|
)
|
||
|
|
return respond(
|
||
|
|
request,
|
||
|
|
"workspace_index.html",
|
||
|
|
{
|
||
|
|
**seo_ctx,
|
||
|
|
"request": request,
|
||
|
|
"user": user,
|
||
|
|
"workspaces": index_entries(window, user),
|
||
|
|
"pagination": pagination,
|
||
|
|
"total": len(rows),
|
||
|
|
},
|
||
|
|
model=WorkspaceIndexOut,
|
||
|
|
)
|