ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / internal/modules/opportunities/teaming_handler.go

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / internal/modules/opportunities/teaming_handler.go
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberinternal/modules/opportunities/teaming_handler.go
Original SHA-256f5665033677486117d2807c41fcfda4b971438943451b48c1c5b1e0d0dfa0d12
Git blob SHAe9c7b83d2357d9f01850bc6b221c21122497ba8d
Reading-copy SHA-256f5665033677486117d2807c41fcfda4b971438943451b48c1c5b1e0d0dfa0d12

Original source ↗

Recovered source transcript

package opportunities import ( "encoding/json" "errors" "log" "net/http" "github.com/go-chi/chi/v5" "github.com/google/uuid" "github.com/missionworkforce/missionmatch/internal/platform/security" ) // TeamingRoutes mounts the partner and key personnel surface. It rides the SAME capability as the rest of // capture, opportunity.manage, because deciding who you bid with is the same act as deciding what you bid on. func (h *Handler) TeamingRoutes(r chi.Router) { manage := security.RequireCapability(security.CapOpportunityManage) r.With(manage).Get("/opportunities/tracked/{id}/partners", h.listPartners) r.With(manage).Post("/opportunities/tracked/{id}/partners", h.addPartner) r.With(manage).Patch("/teaming-partners/{partnerID}", h.updatePartner) r.With(manage).Get("/opportunities/tracked/{id}/key-personnel", h.listCommitments) r.With(manage).Get("/requirements/{reqID}/key-personnel", h.listCommitmentsForRequirement) r.With(manage).Post("/key-personnel", h.addCommitment) r.With(manage).Patch("/key-personnel/{commitmentID}", h.updateCommitment) // THE CAPTURE GATE. The same capability again: deciding whether to bid is the same act as deciding what // to bid on and who to bid it with, and splitting the permission would mean a capture lead who can add a // teaming partner cannot record the decision that partner was chosen for. r.With(manage).Get("/capture/review", h.captureReview) r.With(manage).Get("/opportunities/tracked/{id}/gate", h.listGateDecisions) r.With(manage).Post("/opportunities/tracked/{id}/gate", h.recordGateDecision) } func (h *Handler) listPartners(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "id") if !ok { return } out, err := h.svc.ListPartners(r.Context(), id) if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusOK, map[string]any{"partners": out, "count": len(out)}) } func (h *Handler) addPartner(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "id") if !ok { return } var in PartnerInput if !decodeTeaming(w, r, &in) { return } newID, err := h.svc.AddPartner(r.Context(), id, in) if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusCreated, map[string]string{"id": newID}) } func (h *Handler) updatePartner(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "partnerID") if !ok { return } var in PartnerInput if !decodeTeaming(w, r, &in) { return } if err := h.svc.UpdatePartner(r.Context(), id, in); err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusOK, map[string]bool{"updated": true}) } func (h *Handler) listCommitments(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "id") if !ok { return } out, err := h.svc.ListCommitments(r.Context(), id) if err != nil { writeTeamingErr(w, err) return } // The lapsed count is reported alongside, because it is the number a bid review opens this screen to // find and counting it in the browser would mean every screen counted it slightly differently. lapsed := 0 for _, c := range out { if c.Lapsed { lapsed++ } } writeJSON(w, http.StatusOK, map[string]any{ "commitments": out, "count": len(out), "lapsed": lapsed, }) } func (h *Handler) listCommitmentsForRequirement(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "reqID") if !ok { return } out, err := h.svc.ListCommitmentsForRequirement(r.Context(), id) if err != nil { writeTeamingErr(w, err) return } lapsed := 0 for _, c := range out { if c.Lapsed { lapsed++ } } writeJSON(w, http.StatusOK, map[string]any{"commitments": out, "count": len(out), "lapsed": lapsed}) } func (h *Handler) addCommitment(w http.ResponseWriter, r *http.Request) { var in CommitmentInput if !decodeTeaming(w, r, &in) { return } newID, err := h.svc.AddCommitment(r.Context(), in) if err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusCreated, map[string]string{"id": newID}) } func (h *Handler) updateCommitment(w http.ResponseWriter, r *http.Request) { id, ok := teamingID(w, r, "commitmentID") if !ok { return } var in CommitmentInput if !decodeTeaming(w, r, &in) { return } if err := h.svc.UpdateCommitment(r.Context(), id, in); err != nil { writeTeamingErr(w, err) return } writeJSON(w, http.StatusOK, map[string]bool{"updated": true}) } func teamingID(w http.ResponseWriter, r *http.Request, param string) (uuid.UUID, bool) { id, err := uuid.Parse(chi.URLParam(r, param)) if err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "that is not an identifier"}) return uuid.Nil, false } return id, true } func decodeTeaming(w http.ResponseWriter, r *http.Request, v any) bool { if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 32<<10)).Decode(v); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid body"}) return false } return true } // writeTeamingErr maps the module's sentinels onto statuses, and carries the SENTENCE rather than a generic // message. Every one of these is a rule the database encodes, and a capture manager who trips one can fix it // in seconds if told which. func writeTeamingErr(w http.ResponseWriter, err error) { switch { case errors.Is(err, ErrPartnerExists): writeJSON(w, http.StatusConflict, map[string]string{"error": ErrPartnerExists.Error()}) case errors.Is(err, ErrRequirementMissing): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": ErrRequirementMissing.Error()}) case errors.Is(err, ErrCommitmentNeedsPerson): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": ErrCommitmentNeedsPerson.Error()}) case errors.Is(err, ErrSignedNeedsDate): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": ErrSignedNeedsDate.Error()}) case errors.Is(err, ErrGateUnknown), errors.Is(err, ErrDecisionUnknown), errors.Is(err, ErrRationaleRequired), errors.Is(err, ErrRationaleTooLong), errors.Is(err, ErrBandUnknown), errors.Is(err, ErrWinProbRange): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": err.Error()}) case errors.Is(err, ErrGateUnknown), errors.Is(err, ErrDecisionUnknown), errors.Is(err, ErrRationaleRequired), errors.Is(err, ErrRationaleTooLong), errors.Is(err, ErrBandUnknown), errors.Is(err, ErrWinProbRange): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": err.Error()}) case errors.Is(err, ErrInvalidInput): writeJSON(w, http.StatusUnprocessableEntity, map[string]string{"error": err.Error()}) case errors.Is(err, ErrNotFound): writeJSON(w, http.StatusNotFound, map[string]string{"error": "not found"}) case errors.Is(err, ErrNoDatabase): writeJSON(w, http.StatusServiceUnavailable, map[string]string{"error": "unavailable on this node"}) default: // The cause is LOGGED and a generic message is returned. A generic message to the caller is right; a // generic message in the server log is how a 500 becomes an afternoon of guessing, which is exactly // what the missing staging grant cost before this line existed. log.Printf("opportunities: unmapped teaming error: %v", err) writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "internal error"}) } }

Search equations, builds, manuscript text, and recovered sources.