Per-user checklists with items that may link a course, reading, deadline, material or own presentation deck. An item with a reading shares the reading's read mark. Student API routes with token twins, MCP tools, migrations, tests and README.
126 lines
8.3 KiB
Go
126 lines
8.3 KiB
Go
package bm
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
)
|
|
|
|
// checklistsInput is the input of bm_checklists.
|
|
type checklistsInput struct {
|
|
Meeting uint `json:"meeting,omitempty" query:"meeting" jsonschema:"only checklists of this zjazd (meeting) id"`
|
|
}
|
|
|
|
// checklistIDInput names one of the student's checklists.
|
|
type checklistIDInput struct {
|
|
ID uint `json:"id" path:"id" jsonschema:"the checklist id, as listed by bm_checklists"`
|
|
}
|
|
|
|
// checklistItemIDInput names one item of the student's checklists.
|
|
type checklistItemIDInput struct {
|
|
ID uint `json:"id" path:"id" jsonschema:"the checklist item id, as listed by bm_checklist"`
|
|
}
|
|
|
|
// createChecklistInput is the body of bm_create_checklist.
|
|
type createChecklistInput struct {
|
|
MeetingID *uint `json:"meeting_id,omitempty" jsonschema:"an existing zjazd (meeting) id, as listed by bm_meetings"`
|
|
Title string `json:"title" jsonschema:"title, at most 255 characters, e.g. Zjazd 4"`
|
|
Description *string `json:"description,omitempty" jsonschema:"description, at most 10000 characters"`
|
|
SortOrder *int `json:"sort_order,omitempty" jsonschema:"position among the student's checklists, an integer"`
|
|
}
|
|
|
|
// updateChecklistInput is the body of bm_update_checklist.
|
|
type updateChecklistInput struct {
|
|
ID uint `json:"id" path:"id" jsonschema:"the checklist id"`
|
|
MeetingID *uint `json:"meeting_id,omitempty" jsonschema:"an existing zjazd (meeting) id; null clears it"`
|
|
Title *string `json:"title,omitempty" jsonschema:"title, at most 255 characters; required, so not null"`
|
|
Description *string `json:"description,omitempty" jsonschema:"description, at most 10000 characters"`
|
|
SortOrder *int `json:"sort_order,omitempty" jsonschema:"position among the student's checklists, an integer"`
|
|
}
|
|
|
|
// addChecklistItemInput is the body of bm_add_checklist_item.
|
|
type addChecklistItemInput struct {
|
|
ID uint `json:"id" path:"id" jsonschema:"the checklist id"`
|
|
Kind *string `json:"kind,omitempty" jsonschema:"one of: lektura, artykul, ksiazka, prezentacja, zadanie, inne (default zadanie)"`
|
|
Title string `json:"title" jsonschema:"title, at most 500 characters"`
|
|
Notes *string `json:"notes,omitempty" jsonschema:"notes, at most 10000 characters"`
|
|
URL *string `json:"url,omitempty" jsonschema:"link, at most 2048 characters"`
|
|
CourseID *uint `json:"course_id,omitempty" jsonschema:"an existing course id"`
|
|
ReadingID *uint `json:"reading_id,omitempty" jsonschema:"an existing reading id; the item is then done exactly when the reading is marked read"`
|
|
DeadlineID *uint `json:"deadline_id,omitempty" jsonschema:"an existing deadline id"`
|
|
MaterialID *uint `json:"material_id,omitempty" jsonschema:"an existing material id"`
|
|
PresentationSlug *string `json:"presentation_slug,omitempty" jsonschema:"slug of one of the student's own presentation decks"`
|
|
DueAt *string `json:"due_at,omitempty" jsonschema:"when it should be done: RFC 3339 or YYYY-MM-DD HH:MM in Europe/Warsaw"`
|
|
EstimateMinutes *int `json:"estimate_minutes,omitempty" jsonschema:"estimated work in minutes, 0 to 10000"`
|
|
SortOrder *int `json:"sort_order,omitempty" jsonschema:"position in the checklist, an integer (default: last)"`
|
|
}
|
|
|
|
// updateChecklistItemInput is the body of bm_update_checklist_item.
|
|
type updateChecklistItemInput struct {
|
|
ID uint `json:"id" path:"id" jsonschema:"the checklist item id"`
|
|
ChecklistID *uint `json:"checklist_id,omitempty" jsonschema:"move the item to another of the student's checklists"`
|
|
Kind *string `json:"kind,omitempty" jsonschema:"one of: lektura, artykul, ksiazka, prezentacja, zadanie, inne"`
|
|
Title *string `json:"title,omitempty" jsonschema:"title, at most 500 characters; required, so not null"`
|
|
Notes *string `json:"notes,omitempty" jsonschema:"notes, at most 10000 characters"`
|
|
URL *string `json:"url,omitempty" jsonschema:"link, at most 2048 characters"`
|
|
CourseID *uint `json:"course_id,omitempty" jsonschema:"an existing course id"`
|
|
ReadingID *uint `json:"reading_id,omitempty" jsonschema:"an existing reading id; the item is then done exactly when the reading is marked read"`
|
|
DeadlineID *uint `json:"deadline_id,omitempty" jsonschema:"an existing deadline id"`
|
|
MaterialID *uint `json:"material_id,omitempty" jsonschema:"an existing material id"`
|
|
PresentationSlug *string `json:"presentation_slug,omitempty" jsonschema:"slug of one of the student's own presentation decks"`
|
|
DueAt *string `json:"due_at,omitempty" jsonschema:"when it should be done: RFC 3339 or YYYY-MM-DD HH:MM in Europe/Warsaw"`
|
|
EstimateMinutes *int `json:"estimate_minutes,omitempty" jsonschema:"estimated work in minutes, 0 to 10000"`
|
|
SortOrder *int `json:"sort_order,omitempty" jsonschema:"position in the checklist, an integer (default: last)"`
|
|
}
|
|
|
|
// The sentences of the checklist tool descriptions.
|
|
const (
|
|
checklistsPrivate = " Checklists are the signed-in student's own; another student's id answers 404."
|
|
checklistAnswer = " Returns the checklist with its progress (total, done, percent, minutes_total, minutes_done, minutes_left) and its items."
|
|
itemAnswer = " Returns the item with its done mark and the reading, deadline, material, course or deck it points at."
|
|
checklistInvalid = " Unknown fields and invalid values answer 422 with the errors per field."
|
|
)
|
|
|
|
// checklistTools are the student's checklist tools over the token twins of
|
|
// the student API.
|
|
func checklistTools() []pact.MCPTool {
|
|
tool := func(name, title, desc, method, path string, input any) pact.MCPTool {
|
|
return pact.MCPTool{Name: name, Title: title, Description: desc + checklistsPrivate, Guard: "user", Method: method, Path: TokenPrefix + path, Input: input}
|
|
}
|
|
unmark := tool("unmark_checklist_item_done", "Unmark a checklist item as done",
|
|
"Clears the done mark of a checklist item; for an item with a reading it removes the student's read mark of that reading."+itemAnswer+needsScopeWrite,
|
|
http.MethodDelete, "/checklist-items/{id}/done", checklistItemIDInput{})
|
|
unmark.Destructive = boolPtr(false)
|
|
unmark.Idempotent = boolPtr(true)
|
|
return []pact.MCPTool{
|
|
tool("checklists", "BM checklists",
|
|
"Lists the student's checklists (e.g. the preparation for a zjazd) with zjazd and progress, without items."+needsScopeRead,
|
|
http.MethodGet, "/checklists", checklistsInput{}),
|
|
tool("checklist", "BM checklist",
|
|
"Returns one of the student's checklists."+checklistAnswer+needsScopeRead,
|
|
http.MethodGet, "/checklists/{id}", checklistIDInput{}),
|
|
tool("create_checklist", "Create a checklist",
|
|
"Creates a checklist for the student, optionally for one zjazd."+checklistAnswer+checklistInvalid+needsScopeWrite,
|
|
http.MethodPost, "/checklists", createChecklistInput{}),
|
|
tool("update_checklist", "Update a checklist",
|
|
"Changes the sent fields of one of the student's checklists; the rest stay."+checklistAnswer+checklistInvalid+needsScopeWrite,
|
|
http.MethodPatch, "/checklists/{id}", updateChecklistInput{}),
|
|
tool("delete_checklist", "Delete a checklist",
|
|
"Deletes one of the student's checklists with its items, for good; reading marks stay."+needsScopeWrite,
|
|
http.MethodDelete, "/checklists/{id}", checklistIDInput{}),
|
|
tool("add_checklist_item", "Add a checklist item",
|
|
"Adds an item (a reading, article, book, presentation, task) to one of the student's checklists, last unless sort_order is given."+itemAnswer+checklistInvalid+needsScopeWrite,
|
|
http.MethodPost, "/checklists/{id}/items", addChecklistItemInput{}),
|
|
tool("update_checklist_item", "Update a checklist item",
|
|
"Changes the sent fields of one checklist item; the rest stay."+itemAnswer+checklistInvalid+needsScopeWrite,
|
|
http.MethodPatch, "/checklist-items/{id}", updateChecklistItemInput{}),
|
|
tool("delete_checklist_item", "Delete a checklist item",
|
|
"Deletes one checklist item for good; a reading mark stays."+needsScopeWrite,
|
|
http.MethodDelete, "/checklist-items/{id}", checklistItemIDInput{}),
|
|
tool("mark_checklist_item_done", "Mark a checklist item as done",
|
|
"Marks a checklist item done; for an item with a reading it marks that reading read (the reading list shows it). Marking again keeps the first time."+itemAnswer+needsScopeWrite,
|
|
http.MethodPut, "/checklist-items/{id}/done", checklistItemIDInput{}),
|
|
unmark,
|
|
}
|
|
}
|