Published an OpportunityMarksUpdated event when an opportunity's marks change over the API

This commit is contained in:
bwilliams committed 2026-10-16 13:19:58 +01:00
1 parent 70d62f280e
commit 848edc73e2
7 files changed
+203 -34

No files matched your search

+26 -5
View File
@@ -10,6 +10,7 @@ import (
"github.com/go-chi/chi/v5"
"git.avsdev.uk/Go/job-search/internal/events"
"git.avsdev.uk/Go/job-search/internal/httpx"
"git.avsdev.uk/Go/job-search/internal/store"
"git.avsdev.uk/Go/job-search/internal/types"
@@ -33,7 +34,8 @@ type OpportunityPage struct {
// opportunityRoutes wires HTTP handlers to the opportunity store.
// Opportunities are read-only; only their marks can be changed.
type opportunityRoutes struct {
store *store.Store
store *store.Store
events *events.Bus // nil: nothing is published
// marksMu makes changing one mark (read the marks, change one, write
// them all back) atomic, so concurrent changes to different marks of an
@@ -42,10 +44,13 @@ type opportunityRoutes struct {
}
// newOpportunityRoutes returns the opportunity handlers for
// opportunityStore.
func newOpportunityRoutes(opportunityStore *store.Store) *opportunityRoutes {
// opportunityStore, publishing mark changes to bus if it isn't nil.
func newOpportunityRoutes(
opportunityStore *store.Store, bus *events.Bus,
) *opportunityRoutes {
return &opportunityRoutes{
store: opportunityStore,
store: opportunityStore,
events: bus,
}
}
@@ -179,7 +184,9 @@ func (h *opportunityRoutes) clearMark(w http.ResponseWriter, r *http.Request) {
// changeMark sets the mark named in the URL to value, keeping the
// opportunity's other marks, and responds with all of its marks. Setting won
// while lost is set, or lost while won is, is refused with 409 Conflict.
// while lost is set, or lost while won is, is refused with 409 Conflict. A
// change is published as an events.OpportunityMarksUpdated event; one that
// changes nothing is neither stored nor published.
func (h *opportunityRoutes) changeMark(
w http.ResponseWriter, r *http.Request, value bool,
) {
@@ -196,6 +203,7 @@ func (h *opportunityRoutes) changeMark(
marks := opportunity.Marks
marks.UUID = uuid
before := marks
if !setMark(&marks, name, value) {
httpx.WriteProblem(
w,
@@ -205,6 +213,10 @@ func (h *opportunityRoutes) changeMark(
)
return
}
if marks == before {
httpx.WriteJSON(w, http.StatusOK, marks)
return
}
err = h.store.SetMarks(r.Context(), marks)
if err != nil {
@@ -213,6 +225,15 @@ func (h *opportunityRoutes) changeMark(
}
httpx.WriteJSON(w, http.StatusOK, marks)
// Still under marksMu, so events are published in the order the
// changes were made.
if h.events != nil {
h.events.Publish(events.Event{
Type: events.OpportunityMarksUpdated,
Payload: marks,
})
}
}
// findMarks returns the marks of types.OpportunityMarks: every bool field,