205 lines
6.4 KiB
Python
205 lines
6.4 KiB
Python
from dataclasses import dataclass, field
|
|
|
|
import jsonfile
|
|
from fields import FieldSpec, get_path
|
|
|
|
|
|
@dataclass
|
|
class Collection:
|
|
id: str
|
|
title: str
|
|
file: str
|
|
fields: list[FieldSpec]
|
|
columns: list[tuple[str, str]] = field(default_factory=list)
|
|
single: bool = False
|
|
|
|
@property
|
|
def title_field(self) -> FieldSpec:
|
|
return self.fields[0]
|
|
|
|
|
|
PROJECT_BASICS = [
|
|
FieldSpec("name", "Name", required=True),
|
|
FieldSpec("description", "Description", "longtext"),
|
|
FieldSpec("featured", "Featured", "flag"),
|
|
FieldSpec("tags", "Tags", "tags"),
|
|
]
|
|
PROJECT_COLUMNS = [("Name", "name"), ("Featured", "featured"), ("Tags", "tags")]
|
|
|
|
PROFILE = Collection(
|
|
"profile",
|
|
"Profile",
|
|
"profile.json",
|
|
[
|
|
FieldSpec("name", "Full name", required=True),
|
|
FieldSpec("displayName", "Display name"),
|
|
FieldSpec("title", "Title"),
|
|
FieldSpec("tagline", "Tagline", "longtext"),
|
|
FieldSpec("bio", "Bio", "longtext"),
|
|
FieldSpec("email", "Email"),
|
|
FieldSpec("photo", "Portfolio photo", "image"),
|
|
FieldSpec("avatar", "Avatar", "image"),
|
|
FieldSpec("education.school", "School"),
|
|
FieldSpec("education.degree", "Degree"),
|
|
FieldSpec("education.graduation", "Graduation"),
|
|
FieldSpec("interests", "Interests", "tags"),
|
|
FieldSpec("skills", "Skills", "skill_map"),
|
|
FieldSpec("socials", "Socials", "socials"),
|
|
FieldSpec("donateUrl", "Donate url"),
|
|
FieldSpec("giteaUrl", "Gitea url"),
|
|
],
|
|
single=True,
|
|
)
|
|
|
|
EXPERIENCE = Collection(
|
|
"experience",
|
|
"Experience",
|
|
"experience.json",
|
|
[
|
|
FieldSpec("role", "Role", required=True),
|
|
FieldSpec("organization", "Organization"),
|
|
FieldSpec("school", "School"),
|
|
FieldSpec("period", "Period"),
|
|
FieldSpec("employmentType", "Employment type"),
|
|
FieldSpec("highlights", "Highlights", "lines"),
|
|
FieldSpec("tech", "Tech", "tags"),
|
|
FieldSpec("awards", "Awards", "lines"),
|
|
FieldSpec("links", "Links", "link_list"),
|
|
],
|
|
[("Role", "role"), ("Organization", "organization"), ("Period", "period")],
|
|
)
|
|
|
|
LEADERSHIP = Collection(
|
|
"leadership",
|
|
"Leadership",
|
|
"leadership.json",
|
|
[
|
|
FieldSpec("role", "Role", required=True),
|
|
FieldSpec("organization", "Organization"),
|
|
FieldSpec("url", "Url"),
|
|
],
|
|
[("Role", "role"), ("Organization", "organization")],
|
|
)
|
|
|
|
PROJECT_COLLECTIONS = [
|
|
Collection(
|
|
"opensource",
|
|
"Open Source",
|
|
"projects/opensource.json",
|
|
[*PROJECT_BASICS, FieldSpec("version", "Version"), FieldSpec("period", "Period"), FieldSpec("image", "Image", "image"), FieldSpec("links", "Links", "link_map")],
|
|
PROJECT_COLUMNS,
|
|
),
|
|
Collection(
|
|
"packages",
|
|
"Packages",
|
|
"projects/packages.json",
|
|
[*PROJECT_BASICS, FieldSpec("deprecated", "Deprecated", "flag"), FieldSpec("links", "Links", "link_map")],
|
|
PROJECT_COLUMNS,
|
|
),
|
|
Collection(
|
|
"hackathons",
|
|
"Hackathons",
|
|
"projects/hackathons.json",
|
|
[
|
|
*PROJECT_BASICS,
|
|
FieldSpec("image", "Image", "image"),
|
|
FieldSpec("event.name", "Event"),
|
|
FieldSpec("event.university", "University"),
|
|
FieldSpec("event.location", "Location"),
|
|
FieldSpec("event.year", "Year"),
|
|
FieldSpec("awards", "Awards", "awards"),
|
|
FieldSpec("links", "Links", "link_map"),
|
|
],
|
|
[("Name", "name"), ("Event", "event.name"), ("Featured", "featured")],
|
|
),
|
|
Collection(
|
|
"research",
|
|
"Research groups",
|
|
"projects/research.json",
|
|
[
|
|
FieldSpec("name", "Name", required=True),
|
|
FieldSpec("shortName", "Short name"),
|
|
FieldSpec("institution", "Institution"),
|
|
FieldSpec("role", "Role"),
|
|
FieldSpec("period", "Period"),
|
|
FieldSpec("description", "Description", "longtext"),
|
|
FieldSpec("lab.name", "Lab name"),
|
|
FieldSpec("lab.url", "Lab url"),
|
|
FieldSpec("focus", "Focus", "tags"),
|
|
FieldSpec("links", "Links", "link_list"),
|
|
],
|
|
[("Name", "name"), ("Role", "role"), ("Period", "period")],
|
|
),
|
|
Collection(
|
|
"organizations",
|
|
"Organizations",
|
|
"projects/organizations.json",
|
|
[
|
|
*PROJECT_BASICS,
|
|
FieldSpec("organization", "Roles"),
|
|
FieldSpec("awards", "Awards", "awards"),
|
|
FieldSpec("gallery", "Gallery", "images"),
|
|
FieldSpec("links", "Links", "link_map"),
|
|
FieldSpec("socials", "Socials", "socials"),
|
|
],
|
|
PROJECT_COLUMNS,
|
|
),
|
|
]
|
|
|
|
|
|
def find_collection(collection_id: str) -> Collection:
|
|
for collection in [PROFILE, EXPERIENCE, LEADERSHIP, *PROJECT_COLLECTIONS]:
|
|
if collection.id == collection_id:
|
|
return collection
|
|
raise ValueError(f"Unknown collection {collection_id}")
|
|
|
|
|
|
def load_records(collection: Collection):
|
|
return jsonfile.load(collection.file)
|
|
|
|
|
|
def save_records(collection: Collection, records) -> None:
|
|
jsonfile.save(collection.file, records)
|
|
|
|
|
|
def record_title(collection: Collection, record: dict) -> str:
|
|
return str(get_path(record, collection.title_field.path) or "untitled")
|
|
|
|
|
|
def check_required(collection: Collection, record: dict) -> None:
|
|
for spec in collection.fields:
|
|
if spec.required and not get_path(record, spec.path):
|
|
raise ValueError(f"{spec.label} is required")
|
|
|
|
|
|
def save_record(collection: Collection, index: int | None, record: dict) -> int:
|
|
check_required(collection, record)
|
|
if collection.single:
|
|
save_records(collection, record)
|
|
return 0
|
|
records = load_records(collection)
|
|
if index is None:
|
|
records.append(record)
|
|
index = len(records) - 1
|
|
else:
|
|
records[index] = record
|
|
save_records(collection, records)
|
|
return index
|
|
|
|
|
|
def remove_record(collection: Collection, index: int) -> dict:
|
|
records = load_records(collection)
|
|
removed = records.pop(index)
|
|
save_records(collection, records)
|
|
return removed
|
|
|
|
|
|
def move_record(collection: Collection, index: int, step: int) -> int:
|
|
records = load_records(collection)
|
|
target = index + step
|
|
if not 0 <= target < len(records):
|
|
return index
|
|
records[index], records[target] = records[target], records[index]
|
|
save_records(collection, records)
|
|
return target
|