This is an automated email from the ASF dual-hosted git repository.
lahirujayathilake pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git
The following commit(s) were added to refs/heads/master by this push:
new 66f4e38b5 Temp account creation (#495)
66f4e38b5 is described below
commit 66f4e38b5045b0849b63801cdb2532cb0df5fa0b
Author: Dimuthu Wannipurage <[email protected]>
AuthorDate: Fri Jun 19 00:35:46 2026 -0400
Temp account creation (#495)
* Initial change for global config
* Fixing loaders
* Removing un used config loading
* Intial temp account connector impl
* Adding user type to user
* Assigning an allocation for a temp account
* Adding support apis and integrate with core
* Rename TempAccount loader package to tempaccount to drop import alias
* Include license headers
* lign AMIE handlers with pkg/common JSON helpers
---------
Co-authored-by: lahiruj <[email protected]>
---
config/custos.yaml | 4 +
.../ACCESS/AMIE-Processor/server/handlers.go | 56 +--
connectors/TempAccount/internal/handlers.go | 187 +++++++++
connectors/TempAccount/pkg/tempaccount/loader.go | 36 ++
internal/connectors/loader.go | 5 +-
internal/db/migrations/000015_user_type.down.sql | 18 +
internal/db/migrations/000015_user_type.up.sql | 18 +
internal/server/audit_handlers.go | 29 +-
internal/server/auth.go | 7 +-
internal/server/privilege.go | 41 +-
internal/server/role.go | 89 ++--
internal/server/server.go | 446 ++++++++++-----------
internal/store/user_store.go | 12 +-
pkg/common/support.go | 62 +++
pkg/models/project.go | 26 ++
pkg/service/integration_common_test.go | 4 +-
pkg/service/user.go | 6 +
17 files changed, 681 insertions(+), 365 deletions(-)
diff --git a/config/custos.yaml b/config/custos.yaml
index ca8e749f1..6296d21a7 100644
--- a/config/custos.yaml
+++ b/config/custos.yaml
@@ -58,3 +58,7 @@ connectors:
timeouts:
connect_timeout: "5s"
read_timeout: "20s"
+
+ temp-account:
+ type: "temp-account"
+ enabled: true
diff --git a/connectors/ACCESS/AMIE-Processor/server/handlers.go
b/connectors/ACCESS/AMIE-Processor/server/handlers.go
index bd4dfb36b..feb4f60f3 100644
--- a/connectors/ACCESS/AMIE-Processor/server/handlers.go
+++ b/connectors/ACCESS/AMIE-Processor/server/handlers.go
@@ -19,7 +19,6 @@
package server
import (
- "encoding/json"
"errors"
"net/http"
"strconv"
@@ -27,6 +26,7 @@ import (
"time"
"github.com/apache/airavata-custos/connectors/ACCESS/AMIE-Processor/store"
+ "github.com/apache/airavata-custos/pkg/common"
)
type Handlers struct {
@@ -65,20 +65,20 @@ func (h *Handlers) RegisterRoutes(mux *http.ServeMux) {
// @Router /connectors/amie/packets/{packet_id}/audits [get]
func (h *Handlers) listPacketAudits(w http.ResponseWriter, r *http.Request) {
if h.audits == nil {
- writeError(w, http.StatusServiceUnavailable, errors.New("amie
packet audit store not configured"))
+ common.WriteError(w, http.StatusServiceUnavailable,
errors.New("amie packet audit store not configured"))
return
}
packetID := strings.TrimSpace(r.PathValue("packet_id"))
if packetID == "" {
- writeError(w, http.StatusBadRequest, errors.New("packet_id is
required"))
+ common.WriteError(w, http.StatusBadRequest,
errors.New("packet_id is required"))
return
}
events, err := h.audits.ListAuditsForPacket(r.Context(), packetID)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
- writeJSON(w, http.StatusOK, map[string]any{
+ common.WriteJSON(w, http.StatusOK, map[string]any{
"packet_id": packetID,
"events": events,
})
@@ -101,24 +101,24 @@ func (h *Handlers) listPacketAudits(w
http.ResponseWriter, r *http.Request) {
// @Router /connectors/amie/packets [get]
func (h *Handlers) listPackets(w http.ResponseWriter, r *http.Request) {
if h.packets == nil {
- writeJSON(w, http.StatusOK, emptyPacketPage(parseLimit(r),
parseOffset(r)))
+ common.WriteJSON(w, http.StatusOK,
emptyPacketPage(parseLimit(r), parseOffset(r)))
return
}
f, err := parsePacketFilter(r)
if err != nil {
- writeError(w, http.StatusBadRequest, err)
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
rows, total, err := h.packets.ListPackets(r.Context(), f)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
items := make([]PacketResponse, 0, len(rows))
for _, p := range rows {
items = append(items, packetResponseFrom(p))
}
- writeJSON(w, http.StatusOK, PacketListResponse{
+ common.WriteJSON(w, http.StatusOK, PacketListResponse{
Packets: items,
Total: total,
Limit: effectiveLimit(f.Limit),
@@ -137,19 +137,19 @@ func (h *Handlers) listPackets(w http.ResponseWriter, r
*http.Request) {
// @Router /connectors/amie/packets/{id} [get]
func (h *Handlers) getPacket(w http.ResponseWriter, r *http.Request) {
if h.packets == nil {
- writeError(w, http.StatusNotFound, errors.New("not found"))
+ common.WriteError(w, http.StatusNotFound, errors.New("not
found"))
return
}
p, err := h.packets.FindByID(r.Context(), r.PathValue("id"))
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
if p == nil {
- writeError(w, http.StatusNotFound, errors.New("not found"))
+ common.WriteError(w, http.StatusNotFound, errors.New("not
found"))
return
}
- writeJSON(w, http.StatusOK, packetResponseFrom(*p))
+ common.WriteJSON(w, http.StatusOK, packetResponseFrom(*p))
}
// @Summary List processing events for an AMIE packet
@@ -162,19 +162,19 @@ func (h *Handlers) getPacket(w http.ResponseWriter, r
*http.Request) {
// @Router /connectors/amie/packets/{id}/events [get]
func (h *Handlers) listPacketEvents(w http.ResponseWriter, r *http.Request) {
if h.packets == nil {
- writeJSON(w, http.StatusOK, []PacketEventResponse{})
+ common.WriteJSON(w, http.StatusOK, []PacketEventResponse{})
return
}
rows, err := h.packets.ListPacketEvents(r.Context(), r.PathValue("id"))
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
out := make([]PacketEventResponse, 0, len(rows))
for _, e := range rows {
out = append(out, packetEventResponseFrom(e))
}
- writeJSON(w, http.StatusOK, out)
+ common.WriteJSON(w, http.StatusOK, out)
}
// @Summary Per-day packet stats grouped by status and type
@@ -187,16 +187,16 @@ func (h *Handlers) listPacketEvents(w
http.ResponseWriter, r *http.Request) {
// @Router /connectors/amie/stats [get]
func (h *Handlers) getStats(w http.ResponseWriter, r *http.Request) {
if h.packets == nil {
- writeJSON(w, http.StatusOK, PacketStatsResponse{ByDay:
[]PacketStatBucketResponse{}})
+ common.WriteJSON(w, http.StatusOK, PacketStatsResponse{ByDay:
[]PacketStatBucketResponse{}})
return
}
window := parseWindow(r.URL.Query().Get("window"))
buckets, err := h.packets.GetStats(r.Context(), window)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
- writeJSON(w, http.StatusOK, packetStatsResponseFrom(buckets))
+ common.WriteJSON(w, http.StatusOK, packetStatsResponseFrom(buckets))
}
// ReplyListResponse is the paginated list envelope for connector replies.
@@ -216,7 +216,7 @@ type ReplyListResponse struct {
// @Success 200 {object} ReplyListResponse
// @Router /connectors/amie/replies [get]
func (h *Handlers) listReplies(w http.ResponseWriter, r *http.Request) {
- writeJSON(w, http.StatusOK, ReplyListResponse{
+ common.WriteJSON(w, http.StatusOK, ReplyListResponse{
Replies: []any{},
Total: 0,
Limit: effectiveLimit(parseLimit(r)),
@@ -233,7 +233,7 @@ func (h *Handlers) listReplies(w http.ResponseWriter, r
*http.Request) {
// @Success 200 {object} PacketListResponse
// @Router /connectors/amie/unmapped [get]
func (h *Handlers) listUnmapped(w http.ResponseWriter, r *http.Request) {
- writeJSON(w, http.StatusOK, emptyPacketPage(parseLimit(r),
parseOffset(r)))
+ common.WriteJSON(w, http.StatusOK, emptyPacketPage(parseLimit(r),
parseOffset(r)))
}
// @Summary Retry an AMIE packet (not yet implemented)
@@ -281,7 +281,7 @@ func (h *Handlers) linkUnmapped(w http.ResponseWriter, _
*http.Request) {
}
func writeNotImplemented(w http.ResponseWriter, op string) {
- writeJSON(w, http.StatusNotImplemented, map[string]string{
+ common.WriteJSON(w, http.StatusNotImplemented, map[string]string{
"error": "not_implemented",
"message": op + " not supported on this branch",
})
@@ -362,15 +362,3 @@ func parseWindow(v string) time.Duration {
}
return 30 * 24 * time.Hour
}
-
-func writeJSON(w http.ResponseWriter, status int, v any) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(status)
- _ = json.NewEncoder(w).Encode(v)
-}
-
-func writeError(w http.ResponseWriter, status int, err error) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(status)
- _ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
-}
diff --git a/connectors/TempAccount/internal/handlers.go
b/connectors/TempAccount/internal/handlers.go
new file mode 100644
index 000000000..32ee121a1
--- /dev/null
+++ b/connectors/TempAccount/internal/handlers.go
@@ -0,0 +1,187 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package internal
+
+import (
+ "errors"
+ "net/http"
+
+ "github.com/apache/airavata-custos/pkg/common"
+ "github.com/apache/airavata-custos/pkg/models"
+ "github.com/apache/airavata-custos/pkg/service"
+)
+
+type Handlers struct {
+ coreService *service.Service
+}
+
+func NewHandlers(coreService *service.Service) *Handlers {
+ return &Handlers{coreService: coreService}
+}
+
+// RegisterRoutes attaches the TempAccount connector's HTTP endpoints to mux.
+func (h *Handlers) RegisterRoutes(mux *http.ServeMux) {
+ mux.HandleFunc("/connectors/temp-account/create", h.createTempAccount)
+ mux.HandleFunc("/connectors/temp-account/assign-allocation",
h.assignAllocationToTempAccount)
+ mux.HandleFunc("/connectors/temp-account/update-allocation",
h.updateAllocationToTempAccount)
+ mux.HandleFunc("/connectors/temp-account/remove/{user_id}",
h.removeTempAccount)
+ mux.HandleFunc("/connectors/temp-account/membership/{user_id}",
h.getAllocationMembershipForTempUser)
+}
+
+func (h *Handlers) createTempAccount(w http.ResponseWriter, r *http.Request) {
+ var u models.User
+ if err := common.DecodeJSON(r, &u); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
+ return
+ }
+
+ if u.Type != models.UserTypeVirtual {
+ common.WriteError(w, http.StatusBadRequest, errors.New("User
type must be VIRTUAL"))
+ return
+ }
+
+ created, err := h.coreService.CreateUser(r.Context(), &u)
+
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ common.WriteJSON(w, http.StatusCreated, created)
+}
+
+func (h *Handlers) removeTempAccount(w http.ResponseWriter, r *http.Request) {
+ userID := r.PathValue("user_id")
+ if userID == "" {
+ common.WriteError(w, http.StatusBadRequest, errors.New("user_id
query parameter is required"))
+ return
+ }
+
+ user, err := h.coreService.GetUser(r.Context(), userID)
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ if user == nil {
+ common.WriteError(w, http.StatusNotFound, errors.New("user not
found"))
+ return
+ }
+
+ if user.Type != models.UserTypeVirtual {
+ common.WriteError(w, http.StatusBadRequest, errors.New("User
type must be VIRTUAL"))
+ return
+ }
+
+ err = h.coreService.DeleteUser(r.Context(), userID)
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ w.WriteHeader(http.StatusNoContent)
+}
+
+func (h *Handlers) assignAllocationToTempAccount(w http.ResponseWriter, r
*http.Request) {
+ var m models.ComputeAllocationMembership
+ if err := common.DecodeJSON(r, &m); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
+ return
+ }
+
+ if m.UserID == "" || m.ComputeAllocationID == "" {
+ common.WriteError(w, http.StatusBadRequest, errors.New("UserID
and ComputeAllocationID must be provided"))
+ return
+ }
+
+ // In future, we may want to check that the user already has a
membership to an allocation
+ // If that's the case, prevent user from getting membershup to multiple
allocations, which TempAccount connector doesn't support.
+
+ user, err := h.coreService.GetUser(r.Context(), m.UserID)
+
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+
+ if user.Type != models.UserTypeVirtual {
+ common.WriteError(w, http.StatusBadRequest, errors.New("User
type must be VIRTUAL"))
+ return
+ }
+
+ assigned, err :=
h.coreService.CreateComputeAllocationMembership(r.Context(), &m)
+
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ common.WriteJSON(w, http.StatusOK, assigned)
+}
+
+func (h *Handlers) updateAllocationToTempAccount(w http.ResponseWriter, r
*http.Request) {
+ var m models.ComputeAllocationMembership
+ if err := common.DecodeJSON(r, &m); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
+ return
+ }
+
+ if m.UserID == "" || m.ComputeAllocationID == "" {
+ common.WriteError(w, http.StatusBadRequest, errors.New("UserID
and ComputeAllocationID must be provided"))
+ return
+ }
+
+ updated, err :=
h.coreService.UpdateComputeAllocationMembership(r.Context(), &m)
+
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ common.WriteJSON(w, http.StatusOK, updated)
+}
+
+func (h *Handlers) getAllocationMembershipForTempUser(w http.ResponseWriter, r
*http.Request) {
+ userID := r.PathValue("user_id")
+ if userID == "" {
+ common.WriteError(w, http.StatusBadRequest, errors.New("user_id
query parameter is required"))
+ return
+ }
+
+ user, err := h.coreService.GetUser(r.Context(), userID)
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ if user == nil {
+ common.WriteError(w, http.StatusNotFound, errors.New("user not
found"))
+ return
+ }
+
+ if user.Type != models.UserTypeVirtual {
+ common.WriteError(w, http.StatusBadRequest, errors.New("User
type must be VIRTUAL"))
+ return
+ }
+
+ memberships, err := h.coreService.ListAllocationsForUser(r.Context(),
userID)
+ if err != nil {
+ common.WriteServiceError(w, err)
+ return
+ }
+ if memberships == nil {
+ common.WriteError(w, http.StatusNotFound,
errors.New("membership not found for user"))
+ return
+ }
+
+ common.WriteJSON(w, http.StatusOK, memberships)
+}
diff --git a/connectors/TempAccount/pkg/tempaccount/loader.go
b/connectors/TempAccount/pkg/tempaccount/loader.go
new file mode 100644
index 000000000..6ad36f307
--- /dev/null
+++ b/connectors/TempAccount/pkg/tempaccount/loader.go
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package tempaccount
+
+import (
+ "context"
+ "net/http"
+ "sync"
+
+ "github.com/apache/airavata-custos/connectors/TempAccount/internal"
+ "github.com/apache/airavata-custos/internal/config"
+ "github.com/apache/airavata-custos/pkg/events"
+ "github.com/apache/airavata-custos/pkg/service"
+ "github.com/jmoiron/sqlx"
+)
+
+func LoadConnector(ctx context.Context, _ *sqlx.DB, eventBus *events.Bus,
coreService *service.Service, wg *sync.WaitGroup, mux *http.ServeMux,
connectorConfig *config.ConnectorConfig) error {
+ handlers := internal.NewHandlers(coreService)
+ handlers.RegisterRoutes(mux)
+ return nil
+}
diff --git a/internal/connectors/loader.go b/internal/connectors/loader.go
index a5e487a44..f9190d9c4 100644
--- a/internal/connectors/loader.go
+++ b/internal/connectors/loader.go
@@ -23,15 +23,15 @@ import (
"net/http"
"sync"
- "github.com/jmoiron/sqlx"
-
"github.com/apache/airavata-custos/connectors/ACCESS/AMIE-Processor/pkg/amie"
"github.com/apache/airavata-custos/connectors/COmanage/Identity-Provisioner/pkg/comanage"
"github.com/apache/airavata-custos/connectors/SLURM/Association-Mapper/pkg/smapper"
"github.com/apache/airavata-custos/connectors/SLURM/Usage-Monitor/pkg/monitor"
+
"github.com/apache/airavata-custos/connectors/TempAccount/pkg/tempaccount"
"github.com/apache/airavata-custos/internal/config"
"github.com/apache/airavata-custos/pkg/events"
"github.com/apache/airavata-custos/pkg/service"
+ "github.com/jmoiron/sqlx"
)
func LoadConnectorsFromConfig(ctx context.Context, cfg *config.Config,
database *sqlx.DB, eventBus *events.Bus, coreService *service.Service, wg
*sync.WaitGroup, mux *http.ServeMux) error {
@@ -42,6 +42,7 @@ func LoadConnectorsFromConfig(ctx context.Context, cfg
*config.Config, database
"amie-processor": amie.LoadConnector,
"comanage-identity-provisioner": comanage.LoadConnector,
"slurm-usage-monitor": monitor.LoadConnector,
+ "temp-account": tempaccount.LoadConnector,
}
for connectorName, connectorCfg := range cfg.Connectors {
diff --git a/internal/db/migrations/000015_user_type.down.sql
b/internal/db/migrations/000015_user_type.down.sql
new file mode 100644
index 000000000..f0849b478
--- /dev/null
+++ b/internal/db/migrations/000015_user_type.down.sql
@@ -0,0 +1,18 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+ALTER TABLE users DROP COLUMN type;
diff --git a/internal/db/migrations/000015_user_type.up.sql
b/internal/db/migrations/000015_user_type.up.sql
new file mode 100644
index 000000000..43501e547
--- /dev/null
+++ b/internal/db/migrations/000015_user_type.up.sql
@@ -0,0 +1,18 @@
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+
+ALTER TABLE users ADD COLUMN type VARCHAR(32) NOT NULL DEFAULT 'CLUSTER_LOCAL';
diff --git a/internal/server/audit_handlers.go
b/internal/server/audit_handlers.go
index e3ba7a450..ea785daf6 100644
--- a/internal/server/audit_handlers.go
+++ b/internal/server/audit_handlers.go
@@ -25,6 +25,7 @@ import (
"time"
"github.com/apache/airavata-custos/internal/store"
+ "github.com/apache/airavata-custos/pkg/common"
"github.com/apache/airavata-custos/pkg/models"
)
@@ -39,7 +40,7 @@ const (
func (s *Server) requireAuditStore(w http.ResponseWriter)
(store.AuditTraceStore, bool) {
if s.admin == nil || s.admin.AuditTraces == nil {
- writeError(w, http.StatusServiceUnavailable, errors.New("audit
trace store not configured"))
+ common.WriteError(w, http.StatusServiceUnavailable,
errors.New("audit trace store not configured"))
return nil, false
}
return s.admin.AuditTraces, true
@@ -68,15 +69,15 @@ func (s *Server) handleListTraces(w http.ResponseWriter, r
*http.Request) {
}
f, err := parseTraceFilter(r)
if err != nil {
- writeError(w, http.StatusBadRequest, err)
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
rows, total, err := ts.ListTraces(r.Context(), f)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
- writeJSON(w, http.StatusOK, map[string]any{
+ common.WriteJSON(w, http.StatusOK, map[string]any{
"traces": rows,
"total": total,
"limit": f.Limit,
@@ -101,16 +102,16 @@ func (s *Server) handleGetTrace(w http.ResponseWriter, r
*http.Request) {
}
traceID, err := validateHexID(r.PathValue("trace_id"), traceIDHexLen)
if err != nil {
- writeError(w, http.StatusBadRequest, err)
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
tree, truncated, err := ts.GetTraceTree(r.Context(), traceID)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
if tree == nil {
- writeError(w, http.StatusNotFound, errors.New("trace not
found"))
+ common.WriteError(w, http.StatusNotFound, errors.New("trace not
found"))
return
}
@@ -119,7 +120,7 @@ func (s *Server) handleGetTrace(w http.ResponseWriter, r
*http.Request) {
"tree": tree.Children,
"truncated": truncated,
}
- writeJSON(w, http.StatusOK, resp)
+ common.WriteJSON(w, http.StatusOK, resp)
}
// @Summary List audit events for a trace (optionally one span)
@@ -140,26 +141,26 @@ func (s *Server) handleListEvents(w http.ResponseWriter,
r *http.Request) {
q := r.URL.Query()
traceID, err := validateHexID(q.Get("trace_id"), traceIDHexLen)
if err != nil {
- writeError(w, http.StatusBadRequest, err)
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
var spanID string
if raw := q.Get("span_id"); raw != "" {
spanID, err = validateHexID(raw, spanIDHexLen)
if err != nil {
- writeError(w, http.StatusBadRequest, err)
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
}
events, err := ts.ListEvents(r.Context(), traceID, spanID)
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
if events == nil {
events = []models.TraceEvent{}
}
- writeJSON(w, http.StatusOK, map[string]any{"events": events})
+ common.WriteJSON(w, http.StatusOK, map[string]any{"events": events})
}
// @Summary List distinct audit-event sources
@@ -176,10 +177,10 @@ func (s *Server) handleListSources(w http.ResponseWriter,
r *http.Request) {
}
sources, err := ts.ListSources(r.Context())
if err != nil {
- writeError(w, http.StatusInternalServerError, err)
+ common.WriteError(w, http.StatusInternalServerError, err)
return
}
- writeJSON(w, http.StatusOK, map[string]any{"sources": sources})
+ common.WriteJSON(w, http.StatusOK, map[string]any{"sources": sources})
}
func parseTraceFilter(r *http.Request) (store.TraceFilter, error) {
diff --git a/internal/server/auth.go b/internal/server/auth.go
index b6aaf2a0d..14f5aaefc 100644
--- a/internal/server/auth.go
+++ b/internal/server/auth.go
@@ -24,6 +24,7 @@ import (
"sync"
"time"
+ "github.com/apache/airavata-custos/pkg/common"
"github.com/apache/airavata-custos/pkg/models"
)
@@ -122,16 +123,16 @@ func (s *Server) requirePrivilege(p models.PrivilegeKey,
next http.HandlerFunc)
return func(w http.ResponseWriter, r *http.Request) {
callerID := r.Header.Get(callerHeader)
if callerID == "" {
- writeError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
profile, err := s.lookupAuthProfile(r.Context(), callerID)
if err != nil {
- writeError(w, http.StatusServiceUnavailable,
errors.New("auth lookup failed"))
+ common.WriteError(w, http.StatusServiceUnavailable,
errors.New("auth lookup failed"))
return
}
if !profile.has(p) {
- writeError(w, http.StatusForbidden,
errors.New("insufficient privilege"))
+ common.WriteError(w, http.StatusForbidden,
errors.New("insufficient privilege"))
return
}
next(w, r)
diff --git a/internal/server/privilege.go b/internal/server/privilege.go
index e33b1acb1..401cb7d73 100644
--- a/internal/server/privilege.go
+++ b/internal/server/privilege.go
@@ -21,6 +21,7 @@ import (
"errors"
"net/http"
+ "github.com/apache/airavata-custos/pkg/common"
"github.com/apache/airavata-custos/pkg/models"
)
@@ -36,19 +37,19 @@ import (
func (s *Server) getCallerPrivileges(w http.ResponseWriter, r *http.Request) {
callerID := r.Header.Get(callerHeader)
if callerID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
profile, err := s.lookupAuthProfile(r.Context(), callerID)
if err != nil {
- writeError(w, http.StatusServiceUnavailable, errors.New("auth
lookup failed"))
+ common.WriteError(w, http.StatusServiceUnavailable,
errors.New("auth lookup failed"))
return
}
keys := make([]models.PrivilegeKey, 0, len(profile.privileges))
for k := range profile.privileges {
keys = append(keys, k)
}
- writeJSON(w, http.StatusOK, map[string]any{"privileges": keys})
+ common.WriteJSON(w, http.StatusOK, map[string]any{"privileges": keys})
}
// @Summary List the declared privilege catalog
@@ -60,7 +61,7 @@ func (s *Server) getCallerPrivileges(w http.ResponseWriter, r
*http.Request) {
// @Failure 403 {object} object{error=string} "Caller lacks
privileges:grant"
// @Router /privileges/catalog [get]
func (s *Server) getPrivilegeCatalog(w http.ResponseWriter, _ *http.Request) {
- writeJSON(w, http.StatusOK, s.svc.PrivilegeCatalog())
+ common.WriteJSON(w, http.StatusOK, s.svc.PrivilegeCatalog())
}
// @Summary List a user's direct privilege grants
@@ -76,15 +77,15 @@ func (s *Server) getPrivilegeCatalog(w http.ResponseWriter,
_ *http.Request) {
func (s *Server) listUserPrivileges(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
if userID == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
is required"))
return
}
rows, err := s.svc.ListUserPrivileges(r.Context(), userID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary List direct holders of a privilege
@@ -99,15 +100,15 @@ func (s *Server) listUserPrivileges(w http.ResponseWriter,
r *http.Request) {
func (s *Server) listPrivilegeHolders(w http.ResponseWriter, r *http.Request) {
key := models.PrivilegeKey(r.PathValue("key"))
if !models.IsKnownPrivilege(key) {
- writeError(w, http.StatusBadRequest, errors.New("unknown
privilege key"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("unknown
privilege key"))
return
}
rows, err := s.svc.ListPrivilegeHolders(r.Context(), key)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
type grantPrivilegeRequest struct {
@@ -131,26 +132,26 @@ type grantPrivilegeRequest struct {
func (s *Server) grantPrivilege(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
if userID == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
is required"))
return
}
granterID := r.Header.Get(callerHeader)
if granterID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req grantPrivilegeRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
grant, err := s.svc.GrantPrivilege(r.Context(), userID, req.Privilege,
granterID, req.Reason)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidate(userID)
- writeJSON(w, http.StatusCreated, grant)
+ common.WriteJSON(w, http.StatusCreated, grant)
}
type revokePrivilegeRequest struct {
@@ -175,18 +176,18 @@ func (s *Server) revokePrivilege(w http.ResponseWriter, r
*http.Request) {
userID := r.PathValue("id")
key := models.PrivilegeKey(r.PathValue("key"))
if userID == "" || key == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id and
privilege key are required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
and privilege key are required"))
return
}
revokerID := r.Header.Get(callerHeader)
if revokerID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req revokePrivilegeRequest
- _ = decodeJSON(r, &req)
+ _ = common.DecodeJSON(r, &req)
if err := s.svc.RevokePrivilege(r.Context(), userID, key, revokerID,
req.Reason); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidate(userID)
diff --git a/internal/server/role.go b/internal/server/role.go
index ee91ea7b7..e7a8fdbbe 100644
--- a/internal/server/role.go
+++ b/internal/server/role.go
@@ -21,6 +21,7 @@ import (
"errors"
"net/http"
+ "github.com/apache/airavata-custos/pkg/common"
"github.com/apache/airavata-custos/pkg/models"
)
@@ -35,10 +36,10 @@ import (
func (s *Server) listRoles(w http.ResponseWriter, r *http.Request) {
rows, err := s.svc.ListRoles(r.Context())
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Get a role with its privilege bundle
@@ -53,20 +54,20 @@ func (s *Server) listRoles(w http.ResponseWriter, r
*http.Request) {
func (s *Server) getRole(w http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
if roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
is required"))
return
}
role, err := s.svc.GetRole(r.Context(), roleID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
keys, err := s.svc.ListRolePrivileges(r.Context(), roleID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, map[string]any{
+ common.WriteJSON(w, http.StatusOK, map[string]any{
"role": role,
"privileges": keys,
})
@@ -91,20 +92,20 @@ type createRoleRequest struct {
func (s *Server) createRole(w http.ResponseWriter, r *http.Request) {
actorID := r.Header.Get(callerHeader)
if actorID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req createRoleRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
role, err := s.svc.CreateRole(r.Context(), req.Name, req.Description,
actorID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, role)
+ common.WriteJSON(w, http.StatusCreated, role)
}
type updateRoleRequest struct {
@@ -127,26 +128,26 @@ type updateRoleRequest struct {
func (s *Server) updateRole(w http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
if roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
is required"))
return
}
actorID := r.Header.Get(callerHeader)
if actorID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req updateRoleRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
role, err := s.svc.UpdateRole(r.Context(), roleID, req.Name,
req.Description, actorID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidateAll()
- writeJSON(w, http.StatusOK, role)
+ common.WriteJSON(w, http.StatusOK, role)
}
// @Summary Delete a role
@@ -161,16 +162,16 @@ func (s *Server) updateRole(w http.ResponseWriter, r
*http.Request) {
func (s *Server) deleteRole(w http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
if roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
is required"))
return
}
actorID := r.Header.Get(callerHeader)
if actorID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
if err := s.svc.DeleteRole(r.Context(), roleID, actorID); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidateAll()
@@ -196,21 +197,21 @@ type rolePrivilegeRequest struct {
func (s *Server) addRolePrivilege(w http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
if roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
is required"))
return
}
actorID := r.Header.Get(callerHeader)
if actorID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req rolePrivilegeRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
if err := s.svc.AddPrivilegeToRole(r.Context(), roleID, req.Privilege,
actorID); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidateAll()
@@ -232,16 +233,16 @@ func (s *Server) removeRolePrivilege(w
http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
key := models.PrivilegeKey(r.PathValue("key"))
if roleID == "" || key == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id and
privilege key are required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
and privilege key are required"))
return
}
actorID := r.Header.Get(callerHeader)
if actorID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
if err := s.svc.RemovePrivilegeFromRole(r.Context(), roleID, key,
actorID); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidateAll()
@@ -259,15 +260,15 @@ func (s *Server) removeRolePrivilege(w
http.ResponseWriter, r *http.Request) {
func (s *Server) listUserRoles(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
if userID == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
is required"))
return
}
rows, err := s.svc.ListUserRoles(r.Context(), userID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary List users holding the role
@@ -281,15 +282,15 @@ func (s *Server) listUserRoles(w http.ResponseWriter, r
*http.Request) {
func (s *Server) listRoleHolders(w http.ResponseWriter, r *http.Request) {
roleID := r.PathValue("id")
if roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("role id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("role id
is required"))
return
}
rows, err := s.svc.ListRoleHolders(r.Context(), roleID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
type grantRoleRequest struct {
@@ -312,26 +313,26 @@ type grantRoleRequest struct {
func (s *Server) grantRoleToUser(w http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
if userID == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id is
required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
is required"))
return
}
granterID := r.Header.Get(callerHeader)
if granterID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req grantRoleRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
assignment, err := s.svc.GrantRoleToUser(r.Context(), userID,
req.RoleID, granterID, req.Reason)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidate(userID)
- writeJSON(w, http.StatusCreated, assignment)
+ common.WriteJSON(w, http.StatusCreated, assignment)
}
type revokeRoleRequest struct {
@@ -355,18 +356,18 @@ func (s *Server) revokeRoleFromUser(w
http.ResponseWriter, r *http.Request) {
userID := r.PathValue("id")
roleID := r.PathValue("roleId")
if userID == "" || roleID == "" {
- writeError(w, http.StatusBadRequest, errors.New("user id and
role id are required"))
+ common.WriteError(w, http.StatusBadRequest, errors.New("user id
and role id are required"))
return
}
revokerID := r.Header.Get(callerHeader)
if revokerID == "" {
- writeError(w, http.StatusUnauthorized, errors.New("missing
"+callerHeader+" header"))
+ common.WriteError(w, http.StatusUnauthorized,
errors.New("missing "+callerHeader+" header"))
return
}
var req revokeRoleRequest
- _ = decodeJSON(r, &req)
+ _ = common.DecodeJSON(r, &req)
if err := s.svc.RevokeRoleFromUser(r.Context(), userID, roleID,
revokerID, req.Reason); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
s.authCache.invalidate(userID)
diff --git a/internal/server/server.go b/internal/server/server.go
index 622c2c703..72f24554c 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -19,7 +19,6 @@
package server
import (
- "encoding/json"
"errors"
"log/slog"
"net/http"
@@ -29,6 +28,7 @@ import (
"github.com/apache/airavata-custos/internal/httputil"
"github.com/apache/airavata-custos/internal/store"
+ "github.com/apache/airavata-custos/pkg/common"
"github.com/apache/airavata-custos/pkg/models"
"github.com/apache/airavata-custos/pkg/service"
)
@@ -193,7 +193,7 @@ func (s *Server) routes() {
}
func (s *Server) healthz(w http.ResponseWriter, _ *http.Request) {
- writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
+ common.WriteJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
// @Summary Create an organization
@@ -207,16 +207,16 @@ func (s *Server) healthz(w http.ResponseWriter, _
*http.Request) {
// @Router /organizations [post]
func (s *Server) createOrganization(w http.ResponseWriter, r *http.Request) {
var org models.Organization
- if err := decodeJSON(r, &org); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &org); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateOrganization(r.Context(), &org)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get an organization by ID
@@ -230,10 +230,10 @@ func (s *Server) createOrganization(w
http.ResponseWriter, r *http.Request) {
func (s *Server) getOrganization(w http.ResponseWriter, r *http.Request) {
org, err := s.svc.GetOrganization(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, org)
+ common.WriteJSON(w, http.StatusOK, org)
}
// @Summary Create a user
@@ -247,16 +247,16 @@ func (s *Server) getOrganization(w http.ResponseWriter, r
*http.Request) {
// @Router /users [post]
func (s *Server) createUser(w http.ResponseWriter, r *http.Request) {
var u models.User
- if err := decodeJSON(r, &u); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &u); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateUser(r.Context(), &u)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a user by ID
@@ -270,10 +270,10 @@ func (s *Server) createUser(w http.ResponseWriter, r
*http.Request) {
func (s *Server) getUser(w http.ResponseWriter, r *http.Request) {
u, err := s.svc.GetUser(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, u)
+ common.WriteJSON(w, http.StatusOK, u)
}
// @Summary Create a project
@@ -287,16 +287,16 @@ func (s *Server) getUser(w http.ResponseWriter, r
*http.Request) {
// @Router /projects [post]
func (s *Server) createProject(w http.ResponseWriter, r *http.Request) {
var p models.Project
- if err := decodeJSON(r, &p); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &p); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateProject(r.Context(), &p)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a project by ID
@@ -310,10 +310,10 @@ func (s *Server) createProject(w http.ResponseWriter, r
*http.Request) {
func (s *Server) getProject(w http.ResponseWriter, r *http.Request) {
p, err := s.svc.GetProjectWithPI(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, projectResponseFrom(p))
+ common.WriteJSON(w, http.StatusOK, projectResponseFrom(p))
}
// projectResponseFrom builds the API response shape from a JOIN-fetched row.
@@ -338,16 +338,16 @@ func projectResponseFrom(p *store.ProjectWithPI)
ProjectResponse {
// @Router /compute-clusters [post]
func (s *Server) createComputeCluster(w http.ResponseWriter, r *http.Request) {
var c models.ComputeCluster
- if err := decodeJSON(r, &c); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &c); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeCluster(r.Context(), &c)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute cluster by ID
@@ -361,10 +361,10 @@ func (s *Server) createComputeCluster(w
http.ResponseWriter, r *http.Request) {
func (s *Server) getComputeCluster(w http.ResponseWriter, r *http.Request) {
c, err := s.svc.GetComputeCluster(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, c)
+ common.WriteJSON(w, http.StatusOK, c)
}
// @Summary List compute clusters
@@ -377,10 +377,10 @@ func (s *Server) getComputeCluster(w http.ResponseWriter,
r *http.Request) {
func (s *Server) listComputeClusters(w http.ResponseWriter, r *http.Request) {
clusters, err := s.svc.ListComputeClusters(r.Context())
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, clusters)
+ common.WriteJSON(w, http.StatusOK, clusters)
}
// @Summary Create a compute cluster user
@@ -394,16 +394,16 @@ func (s *Server) listComputeClusters(w
http.ResponseWriter, r *http.Request) {
// @Router /compute-cluster-users [post]
func (s *Server) createComputeClusterUser(w http.ResponseWriter, r
*http.Request) {
var cu models.ComputeClusterUser
- if err := decodeJSON(r, &cu); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &cu); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeClusterUser(r.Context(), &cu)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute cluster user by ID
@@ -417,10 +417,10 @@ func (s *Server) createComputeClusterUser(w
http.ResponseWriter, r *http.Request
func (s *Server) getComputeClusterUser(w http.ResponseWriter, r *http.Request)
{
cu, err := s.svc.GetComputeClusterUser(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, cu)
+ common.WriteJSON(w, http.StatusOK, cu)
}
// @Summary Update a compute cluster user
@@ -436,16 +436,16 @@ func (s *Server) getComputeClusterUser(w
http.ResponseWriter, r *http.Request) {
// @Router /compute-cluster-users/{id} [put]
func (s *Server) updateComputeClusterUser(w http.ResponseWriter, r
*http.Request) {
var cu models.ComputeClusterUser
- if err := decodeJSON(r, &cu); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &cu); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
cu.ID = r.PathValue("id")
if err := s.svc.UpdateComputeClusterUser(r.Context(), &cu); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, &cu)
+ common.WriteJSON(w, http.StatusOK, &cu)
}
// @Summary Delete a compute cluster user
@@ -457,7 +457,7 @@ func (s *Server) updateComputeClusterUser(w
http.ResponseWriter, r *http.Request
// @Router /compute-cluster-users/{id} [delete]
func (s *Server) deleteComputeClusterUser(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DeleteComputeClusterUser(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -474,10 +474,10 @@ func (s *Server) deleteComputeClusterUser(w
http.ResponseWriter, r *http.Request
func (s *Server) listComputeClusterUsersByCluster(w http.ResponseWriter, r
*http.Request) {
users, err := s.svc.ListComputeClusterUsersByCluster(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, users)
+ common.WriteJSON(w, http.StatusOK, users)
}
// @Summary Get a compute cluster user by (cluster, user) pair
@@ -492,10 +492,10 @@ func (s *Server) listComputeClusterUsersByCluster(w
http.ResponseWriter, r *http
func (s *Server) getComputeClusterUserByPair(w http.ResponseWriter, r
*http.Request) {
cu, err := s.svc.GetComputeClusterUserByPair(r.Context(),
r.PathValue("id"), r.PathValue("userId"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, cu)
+ common.WriteJSON(w, http.StatusOK, cu)
}
// @Summary List compute cluster users for a user
@@ -509,10 +509,10 @@ func (s *Server) getComputeClusterUserByPair(w
http.ResponseWriter, r *http.Requ
func (s *Server) listComputeClusterUsersByUser(w http.ResponseWriter, r
*http.Request) {
users, err := s.svc.ListComputeClusterUsersByUser(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, users)
+ common.WriteJSON(w, http.StatusOK, users)
}
// @Summary Create a compute allocation
@@ -526,16 +526,16 @@ func (s *Server) listComputeClusterUsersByUser(w
http.ResponseWriter, r *http.Re
// @Router /compute-allocations [post]
func (s *Server) createComputeAllocation(w http.ResponseWriter, r
*http.Request) {
var a models.ComputeAllocation
- if err := decodeJSON(r, &a); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &a); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocation(r.Context(), &a)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation by ID
@@ -549,10 +549,10 @@ func (s *Server) createComputeAllocation(w
http.ResponseWriter, r *http.Request)
func (s *Server) getComputeAllocation(w http.ResponseWriter, r *http.Request) {
a, err := s.svc.GetComputeAllocation(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, a)
+ common.WriteJSON(w, http.StatusOK, a)
}
// @Summary Create a compute allocation resource
@@ -568,16 +568,16 @@ func (s *Server) getComputeAllocation(w
http.ResponseWriter, r *http.Request) {
// @Router /compute-allocation-resources [post]
func (s *Server) createComputeAllocationResource(w http.ResponseWriter, r
*http.Request) {
var res models.ComputeAllocationResource
- if err := decodeJSON(r, &res); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &res); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationResource(r.Context(), &res)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation resource
@@ -591,10 +591,10 @@ func (s *Server) createComputeAllocationResource(w
http.ResponseWriter, r *http.
func (s *Server) getComputeAllocationResource(w http.ResponseWriter, r
*http.Request) {
res, err := s.svc.GetComputeAllocationResource(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, res)
+ common.WriteJSON(w, http.StatusOK, res)
}
// @Summary List all compute allocation resources
@@ -607,10 +607,10 @@ func (s *Server) getComputeAllocationResource(w
http.ResponseWriter, r *http.Req
func (s *Server) listComputeAllocationResources(w http.ResponseWriter, r
*http.Request) {
resources, err := s.svc.ListComputeAllocationResources(r.Context())
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, resources)
+ common.WriteJSON(w, http.StatusOK, resources)
}
type attachResourceRequest struct {
@@ -633,16 +633,16 @@ type attachResourceRequest struct {
// @Router /compute-allocations/{id}/resources [post]
func (s *Server) attachResourceToAllocation(w http.ResponseWriter, r
*http.Request) {
var body attachResourceRequest
- if err := decodeJSON(r, &body); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &body); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
mapping, err := s.svc.AttachResourceToAllocation(r.Context(),
r.PathValue("id"), body.ComputeAllocationResourceID, body.ResourceAmount,
body.ResourceTime)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, mapping)
+ common.WriteJSON(w, http.StatusCreated, mapping)
}
type updateAllocationResourceMappingRequest struct {
@@ -664,16 +664,16 @@ type updateAllocationResourceMappingRequest struct {
// @Router /compute-allocations/{id}/resources/{resourceId} [put]
func (s *Server) updateAllocationResourceMapping(w http.ResponseWriter, r
*http.Request) {
var body updateAllocationResourceMappingRequest
- if err := decodeJSON(r, &body); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &body); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
mapping, err := s.svc.UpdateAllocationResourceMapping(r.Context(),
r.PathValue("id"), r.PathValue("resourceId"), body.ResourceAmount,
body.ResourceTime)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, mapping)
+ common.WriteJSON(w, http.StatusOK, mapping)
}
// @Summary Detach a resource from a compute allocation
@@ -686,7 +686,7 @@ func (s *Server) updateAllocationResourceMapping(w
http.ResponseWriter, r *http.
// @Router /compute-allocations/{id}/resources/{resourceId} [delete]
func (s *Server) detachResourceFromAllocation(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DetachResourceFromAllocation(r.Context(),
r.PathValue("id"), r.PathValue("resourceId")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -703,10 +703,10 @@ func (s *Server) detachResourceFromAllocation(w
http.ResponseWriter, r *http.Req
func (s *Server) listResourcesForAllocation(w http.ResponseWriter, r
*http.Request) {
resources, err := s.svc.ListResourcesForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, resources)
+ common.WriteJSON(w, http.StatusOK, resources)
}
// @Summary List compute allocations attached to a resource
@@ -720,10 +720,10 @@ func (s *Server) listResourcesForAllocation(w
http.ResponseWriter, r *http.Reque
func (s *Server) listAllocationsForResource(w http.ResponseWriter, r
*http.Request) {
allocs, err := s.svc.ListAllocationsForResource(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, allocs)
+ common.WriteJSON(w, http.StatusOK, allocs)
}
// @Summary Create a compute allocation resource rate
@@ -739,16 +739,16 @@ func (s *Server) listAllocationsForResource(w
http.ResponseWriter, r *http.Reque
// @Router /compute-allocation-resource-rates [post]
func (s *Server) createComputeAllocationResourceRate(w http.ResponseWriter, r
*http.Request) {
var rate models.ComputeAllocationResourceRate
- if err := decodeJSON(r, &rate); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &rate); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationResourceRate(r.Context(),
&rate)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation resource rate
@@ -762,10 +762,10 @@ func (s *Server) createComputeAllocationResourceRate(w
http.ResponseWriter, r *h
func (s *Server) getComputeAllocationResourceRate(w http.ResponseWriter, r
*http.Request) {
rate, err := s.svc.GetComputeAllocationResourceRate(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rate)
+ common.WriteJSON(w, http.StatusOK, rate)
}
// @Summary List rate history for a resource
@@ -779,10 +779,10 @@ func (s *Server) getComputeAllocationResourceRate(w
http.ResponseWriter, r *http
func (s *Server) listRatesForResource(w http.ResponseWriter, r *http.Request) {
rates, err := s.svc.ListRatesForResource(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rates)
+ common.WriteJSON(w, http.StatusOK, rates)
}
// @Summary Get the effective rate for a resource at a given time
@@ -801,17 +801,17 @@ func (s *Server) getEffectiveRateForResource(w
http.ResponseWriter, r *http.Requ
if raw := r.URL.Query().Get("at"); raw != "" {
parsed, err := time.Parse(time.RFC3339Nano, raw)
if err != nil {
- writeError(w, http.StatusBadRequest,
errors.New("invalid 'at' query parameter; expected RFC 3339"))
+ common.WriteError(w, http.StatusBadRequest,
errors.New("invalid 'at' query parameter; expected RFC 3339"))
return
}
at = parsed
}
rate, err := s.svc.GetEffectiveRateForResource(r.Context(),
r.PathValue("id"), at)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rate)
+ common.WriteJSON(w, http.StatusOK, rate)
}
// @Summary Create a compute allocation diff
@@ -827,16 +827,16 @@ func (s *Server) getEffectiveRateForResource(w
http.ResponseWriter, r *http.Requ
// @Router /compute-allocation-diffs [post]
func (s *Server) createComputeAllocationDiff(w http.ResponseWriter, r
*http.Request) {
var diff models.ComputeAllocationDiff
- if err := decodeJSON(r, &diff); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &diff); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationDiff(r.Context(), &diff)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation diff
@@ -850,10 +850,10 @@ func (s *Server) createComputeAllocationDiff(w
http.ResponseWriter, r *http.Requ
func (s *Server) getComputeAllocationDiff(w http.ResponseWriter, r
*http.Request) {
diff, err := s.svc.GetComputeAllocationDiff(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, diff)
+ common.WriteJSON(w, http.StatusOK, diff)
}
// @Summary Delete a compute allocation diff
@@ -865,7 +865,7 @@ func (s *Server) getComputeAllocationDiff(w
http.ResponseWriter, r *http.Request
// @Router /compute-allocation-diffs/{id} [delete]
func (s *Server) deleteComputeAllocationDiff(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DeleteComputeAllocationDiff(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -882,10 +882,10 @@ func (s *Server) deleteComputeAllocationDiff(w
http.ResponseWriter, r *http.Requ
func (s *Server) listDiffsForAllocation(w http.ResponseWriter, r
*http.Request) {
diffs, err := s.svc.ListDiffsForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, diffs)
+ common.WriteJSON(w, http.StatusOK, diffs)
}
// @Summary Get the most recent diff for a compute allocation
@@ -899,10 +899,10 @@ func (s *Server) listDiffsForAllocation(w
http.ResponseWriter, r *http.Request)
func (s *Server) getLatestDiffForAllocation(w http.ResponseWriter, r
*http.Request) {
diff, err := s.svc.GetLatestDiffForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, diff)
+ common.WriteJSON(w, http.StatusOK, diff)
}
// @Summary Create a compute allocation change request
@@ -916,16 +916,16 @@ func (s *Server) getLatestDiffForAllocation(w
http.ResponseWriter, r *http.Reque
// @Router /compute-allocation-change-requests [post]
func (s *Server) createComputeAllocationChangeRequest(w http.ResponseWriter, r
*http.Request) {
var req models.ComputeAllocationChangeRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationChangeRequest(r.Context(),
&req)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation change request
@@ -939,10 +939,10 @@ func (s *Server) createComputeAllocationChangeRequest(w
http.ResponseWriter, r *
func (s *Server) getComputeAllocationChangeRequest(w http.ResponseWriter, r
*http.Request) {
req, err := s.svc.GetComputeAllocationChangeRequest(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, req)
+ common.WriteJSON(w, http.StatusOK, req)
}
// @Summary Update a compute allocation change request
@@ -958,17 +958,17 @@ func (s *Server) getComputeAllocationChangeRequest(w
http.ResponseWriter, r *htt
// @Router /compute-allocation-change-requests/{id} [put]
func (s *Server) updateComputeAllocationChangeRequest(w http.ResponseWriter, r
*http.Request) {
var req models.ComputeAllocationChangeRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
req.ID = r.PathValue("id")
updated, err := s.svc.UpdateComputeAllocationChangeRequest(r.Context(),
&req)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, updated)
+ common.WriteJSON(w, http.StatusOK, updated)
}
// @Summary Delete a compute allocation change request
@@ -980,7 +980,7 @@ func (s *Server) updateComputeAllocationChangeRequest(w
http.ResponseWriter, r *
// @Router /compute-allocation-change-requests/{id} [delete]
func (s *Server) deleteComputeAllocationChangeRequest(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DeleteComputeAllocationChangeRequest(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -997,10 +997,10 @@ func (s *Server) deleteComputeAllocationChangeRequest(w
http.ResponseWriter, r *
func (s *Server) listChangeRequestsForAllocation(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListChangeRequestsForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary List change requests submitted by a user
@@ -1014,10 +1014,10 @@ func (s *Server) listChangeRequestsForAllocation(w
http.ResponseWriter, r *http.
func (s *Server) listChangeRequestsByRequester(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListChangeRequestsByRequester(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Create a change request event
@@ -1031,16 +1031,16 @@ func (s *Server) listChangeRequestsByRequester(w
http.ResponseWriter, r *http.Re
// @Router /compute-allocation-change-request-events [post]
func (s *Server) createComputeAllocationChangeRequestEvent(w
http.ResponseWriter, r *http.Request) {
var evt models.ComputeAllocationChangeRequestEvent
- if err := decodeJSON(r, &evt); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &evt); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err :=
s.svc.CreateComputeAllocationChangeRequestEvent(r.Context(), &evt)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a change request event
@@ -1054,10 +1054,10 @@ func (s *Server)
createComputeAllocationChangeRequestEvent(w http.ResponseWriter
func (s *Server) getComputeAllocationChangeRequestEvent(w http.ResponseWriter,
r *http.Request) {
evt, err := s.svc.GetComputeAllocationChangeRequestEvent(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, evt)
+ common.WriteJSON(w, http.StatusOK, evt)
}
// @Summary Delete a change request event
@@ -1069,7 +1069,7 @@ func (s *Server) getComputeAllocationChangeRequestEvent(w
http.ResponseWriter, r
// @Router /compute-allocation-change-request-events/{id} [delete]
func (s *Server) deleteComputeAllocationChangeRequestEvent(w
http.ResponseWriter, r *http.Request) {
if err := s.svc.DeleteComputeAllocationChangeRequestEvent(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -1086,10 +1086,10 @@ func (s *Server)
deleteComputeAllocationChangeRequestEvent(w http.ResponseWriter
func (s *Server) listEventsForChangeRequest(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListEventsForChangeRequest(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Get the most recent event for a change request
@@ -1103,10 +1103,10 @@ func (s *Server) listEventsForChangeRequest(w
http.ResponseWriter, r *http.Reque
func (s *Server) getLatestEventForChangeRequest(w http.ResponseWriter, r
*http.Request) {
evt, err := s.svc.GetLatestEventForChangeRequest(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, evt)
+ common.WriteJSON(w, http.StatusOK, evt)
}
// @Summary Create a compute allocation membership
@@ -1120,16 +1120,16 @@ func (s *Server) getLatestEventForChangeRequest(w
http.ResponseWriter, r *http.R
// @Router /compute-allocation-memberships [post]
func (s *Server) createComputeAllocationMembership(w http.ResponseWriter, r
*http.Request) {
var m models.ComputeAllocationMembership
- if err := decodeJSON(r, &m); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &m); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationMembership(r.Context(), &m)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation membership
@@ -1143,10 +1143,10 @@ func (s *Server) createComputeAllocationMembership(w
http.ResponseWriter, r *htt
func (s *Server) getComputeAllocationMembership(w http.ResponseWriter, r
*http.Request) {
m, err := s.svc.GetComputeAllocationMembership(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, m)
+ common.WriteJSON(w, http.StatusOK, m)
}
// @Summary Update a compute allocation membership
@@ -1162,17 +1162,17 @@ func (s *Server) getComputeAllocationMembership(w
http.ResponseWriter, r *http.R
// @Router /compute-allocation-memberships/{id} [put]
func (s *Server) updateComputeAllocationMembership(w http.ResponseWriter, r
*http.Request) {
var m models.ComputeAllocationMembership
- if err := decodeJSON(r, &m); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &m); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
m.ID = r.PathValue("id")
updated, err := s.svc.UpdateComputeAllocationMembership(r.Context(), &m)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, updated)
+ common.WriteJSON(w, http.StatusOK, updated)
}
// @Summary Update a membership's status
@@ -1190,16 +1190,16 @@ func (s *Server) updateMembershipStatus(w
http.ResponseWriter, r *http.Request)
var body struct {
MembershipStatus models.AllocationStatus
`json:"membership_status"`
}
- if err := decodeJSON(r, &body); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &body); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
updated, err := s.svc.UpdateMembershipStatus(r.Context(),
r.PathValue("id"), body.MembershipStatus)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, updated)
+ common.WriteJSON(w, http.StatusOK, updated)
}
// @Summary Delete a compute allocation membership
@@ -1211,7 +1211,7 @@ func (s *Server) updateMembershipStatus(w
http.ResponseWriter, r *http.Request)
// @Router /compute-allocation-memberships/{id} [delete]
func (s *Server) deleteComputeAllocationMembership(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DeleteComputeAllocationMembership(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -1228,7 +1228,7 @@ func (s *Server) deleteComputeAllocationMembership(w
http.ResponseWriter, r *htt
func (s *Server) listMembersForAllocation(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListMembersForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
out := make([]AllocationMembershipResponse, 0, len(rows))
@@ -1240,7 +1240,7 @@ func (s *Server) listMembersForAllocation(w
http.ResponseWriter, r *http.Request
Email: m.Email,
})
}
- writeJSON(w, http.StatusOK, out)
+ common.WriteJSON(w, http.StatusOK, out)
}
// @Summary List a user's compute allocation memberships
@@ -1254,10 +1254,10 @@ func (s *Server) listMembersForAllocation(w
http.ResponseWriter, r *http.Request
func (s *Server) listAllocationsForUser(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListAllocationsForUser(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Create a compute allocation usage record
@@ -1271,16 +1271,16 @@ func (s *Server) listAllocationsForUser(w
http.ResponseWriter, r *http.Request)
// @Router /compute-allocation-usages [post]
func (s *Server) createComputeAllocationUsage(w http.ResponseWriter, r
*http.Request) {
var u models.ComputeAllocationUsage
- if err := decodeJSON(r, &u); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &u); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateComputeAllocationUsage(r.Context(), &u)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a compute allocation usage record
@@ -1294,10 +1294,10 @@ func (s *Server) createComputeAllocationUsage(w
http.ResponseWriter, r *http.Req
func (s *Server) getComputeAllocationUsage(w http.ResponseWriter, r
*http.Request) {
u, err := s.svc.GetComputeAllocationUsage(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, u)
+ common.WriteJSON(w, http.StatusOK, u)
}
// @Summary Delete a compute allocation usage record
@@ -1309,7 +1309,7 @@ func (s *Server) getComputeAllocationUsage(w
http.ResponseWriter, r *http.Reques
// @Router /compute-allocation-usages/{id} [delete]
func (s *Server) deleteComputeAllocationUsage(w http.ResponseWriter, r
*http.Request) {
if err := s.svc.DeleteComputeAllocationUsage(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -1326,10 +1326,10 @@ func (s *Server) deleteComputeAllocationUsage(w
http.ResponseWriter, r *http.Req
func (s *Server) listUsagesForAllocation(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListUsagesForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary List usages submitted by a user
@@ -1343,10 +1343,10 @@ func (s *Server) listUsagesForAllocation(w
http.ResponseWriter, r *http.Request)
func (s *Server) listUsagesByUser(w http.ResponseWriter, r *http.Request) {
rows, err := s.svc.ListUsagesByUser(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Create a membership resource override
@@ -1360,16 +1360,16 @@ func (s *Server) listUsagesByUser(w
http.ResponseWriter, r *http.Request) {
// @Router /compute-allocation-membership-resource-overrides [post]
func (s *Server) createComputeAllocationMembershipResourceOverride(w
http.ResponseWriter, r *http.Request) {
var o models.ComputeAllocationMembershipResourceOverride
- if err := decodeJSON(r, &o); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &o); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err :=
s.svc.CreateComputeAllocationMembershipResourceOverride(r.Context(), &o)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a membership resource override
@@ -1383,10 +1383,10 @@ func (s *Server)
createComputeAllocationMembershipResourceOverride(w http.Respon
func (s *Server) getComputeAllocationMembershipResourceOverride(w
http.ResponseWriter, r *http.Request) {
o, err :=
s.svc.GetComputeAllocationMembershipResourceOverride(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, o)
+ common.WriteJSON(w, http.StatusOK, o)
}
// @Summary Update a membership resource override
@@ -1402,17 +1402,17 @@ func (s *Server)
getComputeAllocationMembershipResourceOverride(w http.ResponseW
// @Router /compute-allocation-membership-resource-overrides/{id} [put]
func (s *Server) updateComputeAllocationMembershipResourceOverride(w
http.ResponseWriter, r *http.Request) {
var o models.ComputeAllocationMembershipResourceOverride
- if err := decodeJSON(r, &o); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &o); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
o.ID = r.PathValue("id")
updated, err :=
s.svc.UpdateComputeAllocationMembershipResourceOverride(r.Context(), &o)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, updated)
+ common.WriteJSON(w, http.StatusOK, updated)
}
// @Summary Delete a membership resource override
@@ -1424,7 +1424,7 @@ func (s *Server)
updateComputeAllocationMembershipResourceOverride(w http.Respon
// @Router /compute-allocation-membership-resource-overrides/{id} [delete]
func (s *Server) deleteComputeAllocationMembershipResourceOverride(w
http.ResponseWriter, r *http.Request) {
if err :=
s.svc.DeleteComputeAllocationMembershipResourceOverride(r.Context(),
r.PathValue("id")); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -1441,10 +1441,10 @@ func (s *Server)
deleteComputeAllocationMembershipResourceOverride(w http.Respon
func (s *Server) listOverridesForMembership(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListOverridesForMembership(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary List membership overrides referencing a resource
@@ -1458,10 +1458,10 @@ func (s *Server) listOverridesForMembership(w
http.ResponseWriter, r *http.Reque
func (s *Server) listOverridesForResource(w http.ResponseWriter, r
*http.Request) {
rows, err := s.svc.ListOverridesForResource(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
// @Summary Get total SU usage for a compute allocation
@@ -1475,10 +1475,10 @@ func (s *Server) listOverridesForResource(w
http.ResponseWriter, r *http.Request
func (s *Server) getTotalSUUsageForAllocation(w http.ResponseWriter, r
*http.Request) {
total, err := s.svc.GetTotalSUUsageForAllocation(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, AllocationSUTotalResponse{
+ common.WriteJSON(w, http.StatusOK, AllocationSUTotalResponse{
ComputeAllocationID: r.PathValue("id"),
TotalSUAmount: total,
})
@@ -1498,10 +1498,10 @@ func (s *Server) getTotalSUUsageForUserInAllocation(w
http.ResponseWriter, r *ht
userID := r.PathValue("userId")
total, err := s.svc.GetTotalSUUsageForUserInAllocation(r.Context(),
allocationID, userID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, UserAllocationSUTotalResponse{
+ common.WriteJSON(w, http.StatusOK, UserAllocationSUTotalResponse{
ComputeAllocationID: allocationID,
UserID: userID,
TotalSUAmount: total,
@@ -1525,16 +1525,16 @@ type statusUpdateRequest struct {
// @Router /users/{id}/status [put]
func (s *Server) updateUserStatus(w http.ResponseWriter, r *http.Request) {
var req statusUpdateRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
u, err := s.svc.UpdateUserStatus(r.Context(), r.PathValue("id"),
models.UserStatus(req.Status))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, u)
+ common.WriteJSON(w, http.StatusOK, u)
}
// @Summary Update a project's status
@@ -1550,16 +1550,16 @@ func (s *Server) updateUserStatus(w
http.ResponseWriter, r *http.Request) {
// @Router /projects/{id}/status [put]
func (s *Server) updateProjectStatus(w http.ResponseWriter, r *http.Request) {
var req statusUpdateRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
p, err := s.svc.UpdateProjectStatus(r.Context(), r.PathValue("id"),
models.ProjectStatus(req.Status))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, p)
+ common.WriteJSON(w, http.StatusOK, p)
}
// @Summary Create a user identity
@@ -1573,16 +1573,16 @@ func (s *Server) updateProjectStatus(w
http.ResponseWriter, r *http.Request) {
// @Router /user-identities [post]
func (s *Server) createUserIdentity(w http.ResponseWriter, r *http.Request) {
var e models.UserIdentity
- if err := decodeJSON(r, &e); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &e); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
created, err := s.svc.CreateUserIdentity(r.Context(), &e)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusCreated, created)
+ common.WriteJSON(w, http.StatusCreated, created)
}
// @Summary Get a user identity
@@ -1596,10 +1596,10 @@ func (s *Server) createUserIdentity(w
http.ResponseWriter, r *http.Request) {
func (s *Server) getUserIdentity(w http.ResponseWriter, r *http.Request) {
e, err := s.svc.GetUserIdentity(r.Context(), r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, e)
+ common.WriteJSON(w, http.StatusOK, e)
}
// @Summary Get a user identity by source and external ID
@@ -1614,10 +1614,10 @@ func (s *Server) getUserIdentity(w http.ResponseWriter,
r *http.Request) {
func (s *Server) getUserIdentityBySourceAndExternalID(w http.ResponseWriter, r
*http.Request) {
e, err := s.svc.GetUserIdentityBySourceAndExternalID(r.Context(),
r.PathValue("source"), r.PathValue("externalId"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, e)
+ common.WriteJSON(w, http.StatusOK, e)
}
// @Summary Get a user identity by its OIDC subject claim
@@ -1631,10 +1631,10 @@ func (s *Server) getUserIdentityBySourceAndExternalID(w
http.ResponseWriter, r *
func (s *Server) getUserIdentityByOIDCSub(w http.ResponseWriter, r
*http.Request) {
e, err := s.svc.GetUserIdentityByOIDCSub(r.Context(),
r.PathValue("oidcSub"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, e)
+ common.WriteJSON(w, http.StatusOK, e)
}
// @Summary List a user's identities
@@ -1648,10 +1648,10 @@ func (s *Server) getUserIdentityByOIDCSub(w
http.ResponseWriter, r *http.Request
func (s *Server) listUserIdentitiesForUser(w http.ResponseWriter, r
*http.Request) {
out, err := s.svc.ListUserIdentitiesForUser(r.Context(),
r.PathValue("id"))
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, out)
+ common.WriteJSON(w, http.StatusOK, out)
}
// @Summary Update a user identity
@@ -1667,16 +1667,16 @@ func (s *Server) listUserIdentitiesForUser(w
http.ResponseWriter, r *http.Reques
// @Router /user-identities/{id} [put]
func (s *Server) updateUserIdentity(w http.ResponseWriter, r *http.Request) {
var e models.UserIdentity
- if err := decodeJSON(r, &e); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &e); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
e.ID = r.PathValue("id")
if err := s.svc.UpdateUserIdentity(r.Context(), &e); err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, &e)
+ common.WriteJSON(w, http.StatusOK, &e)
}
// @Summary Delete a user identity
@@ -1688,7 +1688,7 @@ func (s *Server) updateUserIdentity(w
http.ResponseWriter, r *http.Request) {
// @Router /user-identities/{id} [delete]
func (s *Server) deleteUserIdentity(w http.ResponseWriter, r *http.Request) {
if err := s.svc.DeleteUserIdentity(r.Context(), r.PathValue("id")); err
!= nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
@@ -1712,16 +1712,16 @@ type mergeUsersRequest struct {
// @Router /users/merge [post]
func (s *Server) mergeUsers(w http.ResponseWriter, r *http.Request) {
var req mergeUsersRequest
- if err := decodeJSON(r, &req); err != nil {
- writeError(w, http.StatusBadRequest, err)
+ if err := common.DecodeJSON(r, &req); err != nil {
+ common.WriteError(w, http.StatusBadRequest, err)
return
}
survivor, err := s.svc.MergeUsers(r.Context(), req.SurvivingUserID,
req.RetiringUserID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
- writeJSON(w, http.StatusOK, survivor)
+ common.WriteJSON(w, http.StatusOK, survivor)
}
// LoggingMiddleware logs every request once it completes. It wraps
@@ -1746,40 +1746,6 @@ func LoggingMiddleware(next http.Handler) http.Handler {
})
}
-func decodeJSON(r *http.Request, dst any) error {
- dec := json.NewDecoder(r.Body)
- dec.DisallowUnknownFields()
- return dec.Decode(dst)
-}
-
-func writeJSON(w http.ResponseWriter, status int, body any) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(status)
- if body == nil {
- return
- }
- _ = json.NewEncoder(w).Encode(body)
-}
-
-func writeError(w http.ResponseWriter, status int, err error) {
- writeJSON(w, status, map[string]string{"error": err.Error()})
-}
-
-func writeServiceError(w http.ResponseWriter, err error) {
- switch {
- case errors.Is(err, service.ErrNotFound):
- writeError(w, http.StatusNotFound, err)
- case errors.Is(err, service.ErrAlreadyExists):
- writeError(w, http.StatusConflict, err)
- case errors.Is(err, service.ErrInvalidInput):
- writeError(w, http.StatusBadRequest, err)
- default:
- // Avoid leaking driver messages to clients; log the full error.
- slog.Error("internal server error", "error", err.Error())
- writeError(w, http.StatusInternalServerError,
errors.New(strings.TrimSpace("internal server error")))
- }
-}
-
// @Summary List projects (filtered + paginated, PI joined)
// @Tags Projects
// @Security CustosUserHeader
@@ -1802,14 +1768,14 @@ func (s *Server) listProjects(w http.ResponseWriter, r
*http.Request) {
}
rows, total, err := s.svc.ListProjectsWithPI(r.Context(), f)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
items := make([]ProjectResponse, 0, len(rows))
for i := range rows {
items = append(items, projectResponseFrom(&rows[i]))
}
- writeJSON(w, http.StatusOK, ProjectListResponse{Items: items, Total:
total})
+ common.WriteJSON(w, http.StatusOK, ProjectListResponse{Items: items,
Total: total})
}
// @Summary List project members (one row per distinct user, with
allocations)
@@ -1824,7 +1790,7 @@ func (s *Server) listProjectMembers(w
http.ResponseWriter, r *http.Request) {
projectID := r.PathValue("id")
rows, err := s.svc.ListMembersForProject(r.Context(), projectID)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
@@ -1865,7 +1831,7 @@ func (s *Server) listProjectMembers(w
http.ResponseWriter, r *http.Request) {
Allocations: agg.allocations,
})
}
- writeJSON(w, http.StatusOK, out)
+ common.WriteJSON(w, http.StatusOK, out)
}
// @Summary List compute allocations (filtered + paginated)
@@ -1890,13 +1856,13 @@ func (s *Server) listComputeAllocations(w
http.ResponseWriter, r *http.Request)
}
rows, total, err := s.svc.ListComputeAllocations(r.Context(), f)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
if rows == nil {
rows = []models.ComputeAllocation{}
}
- writeJSON(w, http.StatusOK, ComputeAllocationListResponse{Items: rows,
Total: total})
+ common.WriteJSON(w, http.StatusOK, ComputeAllocationListResponse{Items:
rows, Total: total})
}
func (s *Server) listChangeRequests(w http.ResponseWriter, r *http.Request) {
@@ -1907,13 +1873,13 @@ func (s *Server) listChangeRequests(w
http.ResponseWriter, r *http.Request) {
}
rows, err := s.svc.ListChangeRequests(r.Context(), f)
if err != nil {
- writeServiceError(w, err)
+ common.WriteServiceError(w, err)
return
}
if rows == nil {
rows = []models.ComputeAllocationChangeRequest{}
}
- writeJSON(w, http.StatusOK, rows)
+ common.WriteJSON(w, http.StatusOK, rows)
}
func atoiOr(s string, def int) int {
diff --git a/internal/store/user_store.go b/internal/store/user_store.go
index 6c88f3e3f..32d89da1f 100644
--- a/internal/store/user_store.go
+++ b/internal/store/user_store.go
@@ -36,7 +36,7 @@ func NewUserStore(db *sqlx.DB) UserStore {
return &mysqlUserStore{db: db}
}
-const userColumns = `id, organization_id, first_name, last_name, middle_name,
email, status`
+const userColumns = `id, organization_id, first_name, last_name, middle_name,
email, status, type`
func (s *mysqlUserStore) FindByID(ctx context.Context, id string)
(*models.User, error) {
var u models.User
@@ -76,17 +76,17 @@ func (s *mysqlUserStore) FindByOrganization(ctx
context.Context, organizationID
func (s *mysqlUserStore) Create(ctx context.Context, tx *sql.Tx, u
*models.User) error {
_, err := tx.ExecContext(ctx,
- `INSERT INTO users (id, organization_id, first_name, last_name,
middle_name, email, status)
- VALUES (?, ?, ?, ?, ?, ?, ?)`,
- u.ID, u.OrganizationID, u.FirstName, u.LastName, u.MiddleName,
u.Email, u.Status)
+ `INSERT INTO users (id, organization_id, first_name, last_name,
middle_name, email, status, type)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
+ u.ID, u.OrganizationID, u.FirstName, u.LastName, u.MiddleName,
u.Email, u.Status, u.Type)
return err
}
func (s *mysqlUserStore) Update(ctx context.Context, tx *sql.Tx, u
*models.User) error {
_, err := tx.ExecContext(ctx,
- `UPDATE users SET organization_id = ?, first_name = ?,
last_name = ?, middle_name = ?, email = ?, status = ?
+ `UPDATE users SET organization_id = ?, first_name = ?,
last_name = ?, middle_name = ?, email = ?, status = ?, type = ?
WHERE id = ?`,
- u.OrganizationID, u.FirstName, u.LastName, u.MiddleName,
u.Email, u.Status, u.ID)
+ u.OrganizationID, u.FirstName, u.LastName, u.MiddleName,
u.Email, u.Status, u.Type, u.ID)
return err
}
diff --git a/pkg/common/support.go b/pkg/common/support.go
new file mode 100644
index 000000000..ddd8715d8
--- /dev/null
+++ b/pkg/common/support.go
@@ -0,0 +1,62 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package common
+
+import (
+ "encoding/json"
+ "errors"
+ "log/slog"
+ "net/http"
+ "strings"
+
+ "github.com/apache/airavata-custos/pkg/service"
+)
+
+func DecodeJSON(r *http.Request, dst any) error {
+ dec := json.NewDecoder(r.Body)
+ dec.DisallowUnknownFields()
+ return dec.Decode(dst)
+}
+
+func WriteJSON(w http.ResponseWriter, status int, body any) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(status)
+ if body == nil {
+ return
+ }
+ _ = json.NewEncoder(w).Encode(body)
+}
+
+func WriteError(w http.ResponseWriter, status int, err error) {
+ WriteJSON(w, status, map[string]string{"error": err.Error()})
+}
+
+func WriteServiceError(w http.ResponseWriter, err error) {
+ switch {
+ case errors.Is(err, service.ErrNotFound):
+ WriteError(w, http.StatusNotFound, err)
+ case errors.Is(err, service.ErrAlreadyExists):
+ WriteError(w, http.StatusConflict, err)
+ case errors.Is(err, service.ErrInvalidInput):
+ WriteError(w, http.StatusBadRequest, err)
+ default:
+ // Avoid leaking driver messages to clients; log the full error.
+ slog.Error("internal server error", "error", err.Error())
+ WriteError(w, http.StatusInternalServerError,
errors.New(strings.TrimSpace("internal server error")))
+ }
+}
diff --git a/pkg/models/project.go b/pkg/models/project.go
index f73ec63de..50a70756f 100644
--- a/pkg/models/project.go
+++ b/pkg/models/project.go
@@ -1,3 +1,20 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
package models
import "time"
@@ -37,6 +54,14 @@ type Organization struct {
Name string `json:"name" db:"name"`
}
+// UserType enumerates the types of users.
+type UserType string
+
+const (
+ UserTypeClusterLocal UserType = "CLUSTER_LOCAL"
+ UserTypeVirtual UserType = "VIRTUAL"
+)
+
type User struct {
ID string `json:"id" db:"id"`
OrganizationID string `json:"organization_id" db:"organization_id"`
@@ -45,4 +70,5 @@ type User struct {
MiddleName string `json:"middle_name,omitempty"
db:"middle_name"`
Email string `json:"email" db:"email"`
Status UserStatus `json:"status" db:"status"`
+ Type UserType `json:"type" db:"type"`
}
diff --git a/pkg/service/integration_common_test.go
b/pkg/service/integration_common_test.go
index 39508711a..10e19f508 100644
--- a/pkg/service/integration_common_test.go
+++ b/pkg/service/integration_common_test.go
@@ -121,8 +121,8 @@ func seedUser(t *testing.T, database *sqlx.DB, email
string) string {
orgID := seedOrg(t, database)
userID := uuid.NewString()
if _, err := database.Exec(
- "INSERT INTO users (id, organization_id, first_name, last_name,
middle_name, email, status) VALUES (?, ?, ?, ?, ?, ?, ?)",
- userID, orgID, "Test", "User", "", email,
string(models.UserActive),
+ "INSERT INTO users (id, organization_id, first_name, last_name,
middle_name, email, status, type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
+ userID, orgID, "Test", "User", "", email,
string(models.UserActive), string(models.UserTypeClusterLocal),
); err != nil {
t.Fatalf("seed user %s: %v", email, err)
}
diff --git a/pkg/service/user.go b/pkg/service/user.go
index 1da52c807..cc3be72fe 100644
--- a/pkg/service/user.go
+++ b/pkg/service/user.go
@@ -57,6 +57,9 @@ func (s *Service) CreateUser(ctx context.Context, user
*models.User) (*models.Us
if user.Status == "" {
user.Status = models.UserActive
}
+ if user.Type == "" {
+ user.Type = models.UserTypeClusterLocal
+ }
if err := s.inTx(ctx, func(tx *sql.Tx) error {
return s.users.Create(ctx, tx, user)
@@ -160,6 +163,9 @@ func (s *Service) UpdateUser(ctx context.Context, user
*models.User) error {
if user.Status == "" {
user.Status = existing.Status
}
+ if user.Type == "" {
+ user.Type = existing.Type
+ }
if err := s.inTx(ctx, func(tx *sql.Tx) error {
return s.users.Update(ctx, tx, user)