diff --git a/api/handler.go b/api/handler.go index 85882efb..c5501f85 100644 --- a/api/handler.go +++ b/api/handler.go @@ -110,9 +110,10 @@ func authenticatedHandlerJSON[T any](f handlerFunctionGet[T]) http.Handler { }) } -type handlerFunctionGetSlice[T any] func(context.Context, *http.Request, platform.User, resource.QueryParams) ([]*T, *nhttp.ErrorWithStatus) +type handlerFunctionGetSlice[T any] func(context.Context, *http.Request, resource.QueryParams) ([]*T, *nhttp.ErrorWithStatus) +type handlerFunctionGetSliceAuthenticated[T any] func(context.Context, *http.Request, platform.User, resource.QueryParams) ([]*T, *nhttp.ErrorWithStatus) -func authenticatedHandlerJSONSlice[T any](f handlerFunctionGetSlice[T]) http.Handler { +func authenticatedHandlerJSONSlice[T any](f handlerFunctionGetSliceAuthenticated[T]) http.Handler { return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u platform.User) { ctx := r.Context() var body []byte @@ -146,6 +147,40 @@ func authenticatedHandlerJSONSlice[T any](f handlerFunctionGetSlice[T]) http.Han w.Write(body) }) } +func handlerJSONSlice[T any](f handlerFunctionGetSlice[T]) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var body []byte + var params resource.QueryParams + err := decoder.Decode(¶ms, r.URL.Query()) + if err != nil { + log.Error().Err(err).Msg("decode query failure") + http.Error(w, "failed to decode query", http.StatusInternalServerError) + return + } + resp, e := f(ctx, r, params) + w.Header().Set("Content-Type", "application/json") + //log.Info().Str("template", template).Err(e).Msg("handler done") + if e != nil { + log.Warn().Int("status", e.Status).Err(e).Str("user message", e.Message).Msg("Responding with an error from api") + body, err = json.Marshal(ErrorAPI{Message: e.Error()}) + if err != nil { + log.Error().Err(err).Msg("failed to marshal error") + http.Error(w, "{\"message\": \"boom. I can't even tell you what went wrong\"}", http.StatusInternalServerError) + return + } + http.Error(w, string(body), e.Status) + return + } + body, err = json.Marshal(resp) + if err != nil { + log.Error().Err(err).Msg("failed to marshal json") + http.Error(w, "{\"message\": \"failed to marshal json\"}", http.StatusInternalServerError) + return + } + w.Write(body) + } +} type handlerFunctionPost[ReqType any] func(context.Context, *http.Request, ReqType) (string, *nhttp.ErrorWithStatus) type handlerFunctionPostAuthenticated[RequestType any, ResponseType any] func(context.Context, *http.Request, platform.User, RequestType) (ResponseType, *nhttp.ErrorWithStatus) diff --git a/api/routes.go b/api/routes.go index d56baf1b..4c3d3187 100644 --- a/api/routes.go +++ b/api/routes.go @@ -66,8 +66,10 @@ func AddRoutes(r *mux.Router) { r.Handle("/user/{id}", authenticatedHandlerJSONPut(user.ByIDPut)).Methods("PUT") // Unauthenticated endpoints - r.HandleFunc("/district", apiGetDistrict).Methods("GET") - r.HandleFunc("/district/{slug}/logo", apiGetDistrictLogo).Methods("GET") + district := resource.District(router) + r.Handle("/district", handlerJSONSlice(district.List)).Methods("GET") + //r.HandleFunc("/district", apiGetDistrict).Methods("GET") + r.HandleFunc("/district/{slug}/logo", apiGetDistrictLogo).Methods("GET").Name("district.logo.BySlug") r.HandleFunc("/compliance-request/image/pool/{public_id}", getComplianceRequestImagePool).Methods("GET") r.HandleFunc("/twilio/call", twilioCallPost).Methods("POST") r.HandleFunc("/twilio/call/status", twilioCallStatusPost).Methods("POST") diff --git a/main.go b/main.go index f383faa9..6a3b2f88 100644 --- a/main.go +++ b/main.go @@ -120,7 +120,13 @@ func main() { // Set up routing by hostname nidussync.Router(sync_router) + sync_api_router := sync_router.PathPrefix("/api").Subrouter() + api.AddRoutes(sync_api_router) + rmo.Router(rmo_router) + rmo_api_router := rmo_router.PathPrefix("/api").Subrouter() + api.AddRoutes(rmo_api_router) + //hr.Map("", sr) // default //hr.Map("*", sr) // default diff --git a/platform/organization.go b/platform/organization.go index 6f42e3cc..3ed5c8d5 100644 --- a/platform/organization.go +++ b/platform/organization.go @@ -83,6 +83,9 @@ func (o Organization) ServiceRequestRecent(ctx context.Context) ([]*models.Field } return results, nil } +func (o Organization) Slug() string { + return o.model.Slug.GetOr("") +} func OrganizationByID(ctx context.Context, id int) (*Organization, error) { org, err := models.FindOrganization(ctx, db.PGInstance.BobDB, int32(id)) if err != nil { @@ -94,10 +97,7 @@ func OrganizationByID(ctx context.Context, id int) (*Organization, error) { o := newOrganization(org) return &o, nil } -func OrganizationList(ctx context.Context, user User) ([]*Organization, error) { - if !user.HasRoot() { - return []*Organization{&user.Organization}, nil - } +func OrganizationList(ctx context.Context) ([]*Organization, error) { rows, err := models.Organizations.Query().All(ctx, db.PGInstance.BobDB) if err != nil { return nil, fmt.Errorf("query orgs: %w", err) diff --git a/platform/user.go b/platform/user.go index 98461454..49b5822e 100644 --- a/platform/user.go +++ b/platform/user.go @@ -115,7 +115,7 @@ func UserList(ctx context.Context, user User) ([]*User, error) { var orgByID map[int32]*Organization if user.HasRoot() { query = models.Users.Query() - orgs, err := OrganizationList(ctx, user) + orgs, err := OrganizationList(ctx) if err != nil { return nil, fmt.Errorf("org list: %w", err) } diff --git a/resource/district.go b/resource/district.go new file mode 100644 index 00000000..3ab5fe5e --- /dev/null +++ b/resource/district.go @@ -0,0 +1,47 @@ +package resource + +import ( + "context" + nhttp "github.com/Gleipnir-Technology/nidus-sync/http" + "github.com/Gleipnir-Technology/nidus-sync/platform" + "net/http" + //"github.com/rs/zerolog/log" +) + +type districtR struct { + router *router +} + +type district struct { + Name string `json:"name"` + URLLogo string `json:"url_logo"` +} + +func District(r *router) *districtR { + return &districtR{ + router: r, + } +} + +func (res *districtR) List(ctx context.Context, r *http.Request, query QueryParams) ([]*district, *nhttp.ErrorWithStatus) { + organizations, err := platform.OrganizationList(ctx) + if err != nil { + return nil, nhttp.NewError("list orgs: %w", err) + } + districts := make([]*district, 0) + for _, org := range organizations { + slug := org.Slug() + if slug == "" { + continue + } + logo, err := res.router.SlugToURI("district.logo.BySlug", slug) + if err != nil { + return nil, nhttp.NewError("logo url: %w", err) + } + districts = append(districts, &district{ + Name: org.Name(), + URLLogo: logo, + }) + } + return districts, nil +} diff --git a/resource/router.go b/resource/router.go index 977c1384..cb64293d 100644 --- a/resource/router.go +++ b/resource/router.go @@ -59,6 +59,18 @@ func (r *router) IDToURI(route string, id int) (string, error) { uri.Scheme = "https" return uri.String(), nil } +func (r *router) SlugToURI(route string, slug string) (string, error) { + handler := r.router.Get(route) + if handler == nil { + return "", fmt.Errorf("nil handler '%s'", route) + } + uri, err := handler.URL("slug", slug) + if err != nil { + return "", fmt.Errorf("build uri: %w", err) + } + uri.Scheme = "https" + return uri.String(), nil +} func (r *router) UUIDToURI(route string, u *uuid.UUID) (*string, error) { if u == nil { diff --git a/sync/routes.go b/sync/routes.go index 7aea71aa..5a046caa 100644 --- a/sync/routes.go +++ b/sync/routes.go @@ -1,7 +1,6 @@ package sync import ( - "github.com/Gleipnir-Technology/nidus-sync/api" "github.com/Gleipnir-Technology/nidus-sync/static" "github.com/gorilla/mux" ) @@ -36,9 +35,6 @@ func Router(r *mux.Router) { r.HandleFunc("/qr-code/mailer/{code}", getQRCodeMailer) r.HandleFunc("/template-test", getTemplateTest) - api_router := r.PathPrefix("/api").Subrouter() - api.AddRoutes(api_router) - r.HandleFunc("/", getRoot) r.HandleFunc("/_/*", getRoot) diff --git a/vite/rmo/vite.config.js b/vite/rmo/vite.config.js index d533269e..082fffa1 100644 --- a/vite/rmo/vite.config.js +++ b/vite/rmo/vite.config.js @@ -60,12 +60,12 @@ export default defineConfig({ server: { allowedHosts: ["poweredge.local", "dev-report.mosquitoes.online"], port: 9001, - /*proxy: { + proxy: { "/api": { - target: "http://127.0.0.1:9002", + target: "http://127.0.0.1:9003", changeOrigin: false, }, - },*/ + }, strictPort: true, }, });