diff --git a/html/config.go b/html/config.go
new file mode 100644
index 00000000..ee6a63a7
--- /dev/null
+++ b/html/config.go
@@ -0,0 +1,15 @@
+package html
+
+import (
+ "github.com/Gleipnir-Technology/nidus-sync/config"
+)
+
+type ContentConfig struct {
+ IsProductionEnvironment bool
+}
+
+func NewContentConfig() ContentConfig {
+ return ContentConfig{
+ IsProductionEnvironment: config.IsProductionEnvironment(),
+ }
+}
diff --git a/html/content.go b/html/content.go
new file mode 100644
index 00000000..5aafd5b0
--- /dev/null
+++ b/html/content.go
@@ -0,0 +1,7 @@
+package html
+
+type Content[T any] struct {
+ C T
+ Config ContentConfig
+ URL ContentURL
+}
diff --git a/html/handler.go b/html/handler.go
new file mode 100644
index 00000000..a469fb84
--- /dev/null
+++ b/html/handler.go
@@ -0,0 +1,26 @@
+package html
+
+import (
+ "context"
+ "net/http"
+
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
+ "github.com/rs/zerolog/log"
+)
+
+type handlerFunctionGet[T any] func(context.Context, *http.Request) (*Response[T], *nhttp.ErrorWithStatus)
+
+func MakeGet[T any](f handlerFunctionGet[T]) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ resp, e := f(ctx, r)
+ if e != nil {
+ log.Warn().Int("status", e.Status)
+ http.Error(w, e.Error(), e.Status)
+ return
+ }
+ RenderOrError(w, resp.Template, Content[T]{
+ C: resp.Content,
+ })
+ }
+}
diff --git a/html/response.go b/html/response.go
index 33e1d386..d67a9bbc 100644
--- a/html/response.go
+++ b/html/response.go
@@ -38,3 +38,15 @@ func RespondError(w http.ResponseWriter, m string, e error, s int) {
log.Warn().Int("status", s).Err(e).Str("user message", m).Msg("Responding with an error")
http.Error(w, m, s)
}
+
+type Response[T any] struct {
+ Content T
+ Template string
+}
+
+func NewResponse[T any](template string, content T) *Response[T] {
+ return &Response[T]{
+ Content: content,
+ Template: template,
+ }
+}
diff --git a/sync/url.go b/html/url.go
similarity index 97%
rename from sync/url.go
rename to html/url.go
index bfbd13d1..3e7b4f1d 100644
--- a/sync/url.go
+++ b/html/url.go
@@ -1,4 +1,4 @@
-package sync
+package html
import (
"strconv"
@@ -6,7 +6,7 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/config"
)
-type contentURL struct {
+type ContentURL struct {
Configuration contentURLConfiguration
OAuthRefreshArcGIS string
Root string
@@ -16,8 +16,8 @@ type contentURL struct {
Upload contentURLUpload
}
-func newContentURL() contentURL {
- return contentURL{
+func NewContentURL() ContentURL {
+ return ContentURL{
Configuration: newContentURLConfiguration(),
OAuthRefreshArcGIS: config.MakeURLNidus("/arcgis/oauth/begin"),
Root: config.MakeURLNidus("/"),
diff --git a/http/error_with_status.go b/http/error_with_status.go
new file mode 100644
index 00000000..a23acbdd
--- /dev/null
+++ b/http/error_with_status.go
@@ -0,0 +1,32 @@
+package http
+
+import (
+ "fmt"
+ "net/http"
+)
+
+type ErrorWithStatus struct {
+ Message string
+ Status int
+}
+
+func (e *ErrorWithStatus) Error() string {
+ return e.Message
+}
+func NewError(mesg_format string, args ...any) *ErrorWithStatus {
+ return NewErrorStatus(http.StatusInternalServerError, mesg_format, args...)
+}
+func NewErrorMaybe(mesg_format string, err error, args ...any) *ErrorWithStatus {
+ if err == nil {
+ return nil
+ }
+ allArgs := append([]any{err}, args...)
+ return NewErrorStatus(http.StatusInternalServerError, mesg_format, allArgs...)
+}
+func NewErrorStatus(status int, mesg_format string, args ...any) *ErrorWithStatus {
+ w := fmt.Errorf(mesg_format, args...)
+ return &ErrorWithStatus{
+ Message: w.Error(),
+ Status: status,
+ }
+}
diff --git a/rmo/mailer.go b/rmo/mailer.go
index 9e9a09e1..3444509a 100644
--- a/rmo/mailer.go
+++ b/rmo/mailer.go
@@ -1,12 +1,67 @@
package rmo
import (
+ "context"
"net/http"
+
+ "github.com/Gleipnir-Technology/bob"
+ "github.com/Gleipnir-Technology/bob/dialect/psql"
+ "github.com/Gleipnir-Technology/bob/dialect/psql/sm"
+ "github.com/Gleipnir-Technology/nidus-sync/db"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
+ "github.com/go-chi/chi/v5"
+ "github.com/stephenafamo/scan"
//"github.com/Gleipnir-Technology/nidus-sync/config"
)
-type contentMailer struct{}
+type address struct {
+ Number int32 `db:"number_"`
+ Street string `db:"street"`
+ Locality string `db:"locality"`
+ PostalCode string `db:"postal_code"`
+ Country string `db:"country"`
+}
+type contentMailer struct {
+ Address address
+}
-func getMailer(w http.ResponseWriter, r *http.Request) {
+func getMailer(ctx context.Context, r *http.Request) (*html.Response[contentMailer], *nhttp.ErrorWithStatus) {
+ public_id := chi.URLParam(r, "public_id")
+ if public_id == "" {
+ return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No 'public_id' in the url params")
+ }
+
+ /*
+ compliance_request, err := models.ComplianceReportRequests.Query(
+ models.Preload.ComplianceReportRequest.Site(),
+ models.SelectWhere.ComplianceReportRequests.PublicID.EQ(public_id),
+ ).One(ctx, db.PGInstance.BobDB)
+ if err != nil {
+ respondError(w, "failed to get compliance request", err, http.StatusBadRequest)
+ }
+ site := compliance_request.
+ */
+ report, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
+ sm.Columns(
+ "address.number_",
+ "address.street",
+ "address.locality",
+ "address.postal_code",
+ "address.country",
+ ),
+ sm.From("compliance_report_request").As("crr"),
+ sm.InnerJoin("site").OnEQ(psql.Raw("crr.site_id"), psql.Raw("site.id")),
+ sm.InnerJoin("address").OnEQ(psql.Raw("site.address_id"), psql.Raw("address.id")),
+ sm.Where(psql.Raw("crr.public_id").EQ(psql.Arg(public_id))),
+ ), scan.StructMapper[address]())
+ if err != nil {
+ return nil, nhttp.NewErrorStatus(http.StatusNotFound, "No compliance report with that public ID")
+ }
+ return html.NewResponse(
+ "rmo/mailer.html", contentMailer{
+ Address: report,
+ },
+ ), nil
}
diff --git a/rmo/routes.go b/rmo/routes.go
index f727fbbe..ba5e40a5 100644
--- a/rmo/routes.go
+++ b/rmo/routes.go
@@ -32,7 +32,7 @@ func Router() chi.Router {
r.Get("/email/unsubscribe", getEmailUnsubscribe)
r.Get("/email/unsubscribe/report/{report_id}", getEmailReportUnsubscribe)
r.Get("/image/{uuid}", getImageByUUID)
- r.Get("/mailer/{public_id}", getMailer)
+ r.Get("/mailer/{public_id}", html.MakeGet(getMailer))
r.Route("/mock", addMockRoutes)
r.Post("/register-notifications", postRegisterNotifications)
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
diff --git a/sync/admin.go b/sync/admin.go
index bd30a135..7edf4d36 100644
--- a/sync/admin.go
+++ b/sync/admin.go
@@ -5,11 +5,13 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentAdminDash struct{}
-func getAdminDash(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentAdminDash], *errorWithStatus) {
+func getAdminDash(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentAdminDash], *nhttp.ErrorWithStatus) {
content := contentAdminDash{}
- return newResponse("sync/admin-dash.html", content), nil
+ return html.NewResponse("sync/admin-dash.html", content), nil
}
diff --git a/sync/cell.go b/sync/cell.go
index 4fc96b5a..eb9069e0 100644
--- a/sync/cell.go
+++ b/sync/cell.go
@@ -6,6 +6,8 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/go-chi/chi/v5"
"github.com/uber/h3-go/v4"
)
@@ -19,46 +21,46 @@ type contentCell struct {
Treatments []Treatment
}
-func getCellDetails(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentCell], *errorWithStatus) {
+func getCellDetails(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentCell], *nhttp.ErrorWithStatus) {
cell_str := chi.URLParam(r, "cell")
if cell_str == "" {
- return nil, newErrorStatus(http.StatusBadRequest, "There should always be a cell")
+ return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "There should always be a cell")
}
c, err := HexToInt64(cell_str)
if err != nil {
- return nil, newErrorStatus(http.StatusBadRequest, "Cannot convert provided cell to uint64")
+ return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "Cannot convert provided cell to uint64")
}
center, err := h3.Cell(c).LatLng()
if err != nil {
- return nil, newError("Failed to get center: %w", err)
+ return nil, nhttp.NewError("Failed to get center: %w", err)
}
boundary, err := h3.Cell(c).Boundary()
if err != nil {
- return nil, newError("Failed to get boundary: %w", err)
+ return nil, nhttp.NewError("Failed to get boundary: %w", err)
}
inspections, err := inspectionsByCell(ctx, org, h3.Cell(c))
if err != nil {
- return nil, newError("Failed to get inspections by cell: %w", err)
+ return nil, nhttp.NewError("Failed to get inspections by cell: %w", err)
}
geojson, err := h3utils.H3ToGeoJSON([]h3.Cell{h3.Cell(c)})
if err != nil {
- return nil, newError("Failed to get boundaries: %w", err)
+ return nil, nhttp.NewError("Failed to get boundaries: %w", err)
}
resolution := h3.Cell(c).Resolution()
sources, err := breedingSourcesByCell(ctx, org, h3.Cell(c))
if err != nil {
- return nil, newError("Failed to get sources: %w", err)
+ return nil, nhttp.NewError("Failed to get sources: %w", err)
}
traps, err := trapsByCell(ctx, org, h3.Cell(c))
if err != nil {
- return nil, newError("Failed to get traps: %w", err)
+ return nil, nhttp.NewError("Failed to get traps: %w", err)
}
treatments, err := treatmentsByCell(ctx, org, h3.Cell(c))
if err != nil {
- return nil, newError("Failed to get treatments: %w", err)
+ return nil, nhttp.NewError("Failed to get treatments: %w", err)
}
- return newResponse("sync/cell.html", contentCell{
+ return html.NewResponse("sync/cell.html", contentCell{
BreedingSources: sources,
CellBoundary: boundary,
Inspections: inspections,
diff --git a/sync/communication.go b/sync/communication.go
index bed9a5d4..32bc035b 100644
--- a/sync/communication.go
+++ b/sync/communication.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentCommunicationRoot struct{}
-func getCommunicationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentCommunicationRoot], *errorWithStatus) {
- return newResponse("sync/communication-root.html", contentCommunicationRoot{}), nil
+func getCommunicationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentCommunicationRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/communication-root.html", contentCommunicationRoot{}), nil
}
diff --git a/sync/configuration.go b/sync/configuration.go
index 4df3abef..03b8be9a 100644
--- a/sync/configuration.go
+++ b/sync/configuration.go
@@ -5,26 +5,17 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/arcgis"
- "github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
//"github.com/rs/zerolog/log"
)
-type contentConfig struct {
- IsProductionEnvironment bool
-}
-
-func newContentConfig() contentConfig {
- return contentConfig{
- IsProductionEnvironment: config.IsProductionEnvironment(),
- }
-}
-
type contentConfigurationRoot struct{}
-func getConfigurationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentConfigurationRoot], *errorWithStatus) {
- return newResponse("sync/configuration/root.html", contentConfigurationRoot{}), nil
+func getConfigurationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentConfigurationRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/configuration/root.html", contentConfigurationRoot{}), nil
}
type contentSettingOrganization struct {
@@ -35,10 +26,10 @@ type contentSettingIntegration struct {
ArcGISOAuth *models.ArcgisOauthToken
}
-func getConfigurationOrganization(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentSettingOrganization], *errorWithStatus) {
+func getConfigurationOrganization(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentSettingOrganization], *nhttp.ErrorWithStatus) {
org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
if err != nil {
- return nil, newError("get organization: %w", err)
+ return nil, nhttp.NewError("get organization: %w", err)
}
/*
var district contentDistrict
@@ -74,44 +65,44 @@ func getConfigurationOrganization(ctx context.Context, r *http.Request, org *mod
data := contentSettingOrganization{
Organization: org,
}
- return newResponse("sync/configuration/organization.html", data), nil
+ return html.NewResponse("sync/configuration/organization.html", data), nil
}
-func getConfigurationIntegration(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentSettingIntegration], *errorWithStatus) {
+func getConfigurationIntegration(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentSettingIntegration], *nhttp.ErrorWithStatus) {
oauth, err := arcgis.GetOAuthForUser(ctx, u)
if err != nil {
- return nil, newError("Failed to get oauth: %w", err)
+ return nil, nhttp.NewError("Failed to get oauth: %w", err)
}
data := contentSettingIntegration{
ArcGISOAuth: oauth,
}
- return newResponse("sync/configuration/integration.html", data), nil
+ return html.NewResponse("sync/configuration/integration.html", data), nil
}
-func getConfigurationIntegrationArcgis(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentSettingIntegration], *errorWithStatus) {
+func getConfigurationIntegrationArcgis(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentSettingIntegration], *nhttp.ErrorWithStatus) {
oauth, err := arcgis.GetOAuthForUser(ctx, u)
if err != nil {
- return nil, newError("Failed to get oauth: %w", err)
+ return nil, nhttp.NewError("Failed to get oauth: %w", err)
}
data := contentSettingIntegration{
ArcGISOAuth: oauth,
}
- return newResponse("sync/configuration/integration-arcgis.html", data), nil
+ return html.NewResponse("sync/configuration/integration-arcgis.html", data), nil
}
type contentSettingPlaceholder struct{}
-func getConfigurationPesticide(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSettingPlaceholder], *errorWithStatus) {
+func getConfigurationPesticide(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSettingPlaceholder], *nhttp.ErrorWithStatus) {
content := contentSettingPlaceholder{}
- return newResponse("sync/configuration/pesticide.html", content), nil
+ return html.NewResponse("sync/configuration/pesticide.html", content), nil
}
-func getConfigurationPesticideAdd(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSettingPlaceholder], *errorWithStatus) {
+func getConfigurationPesticideAdd(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSettingPlaceholder], *nhttp.ErrorWithStatus) {
content := contentSettingPlaceholder{}
- return newResponse("sync/configuration/pesticide-add.html", content), nil
+ return html.NewResponse("sync/configuration/pesticide-add.html", content), nil
}
-func getConfigurationUserAdd(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSettingPlaceholder], *errorWithStatus) {
+func getConfigurationUserAdd(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSettingPlaceholder], *nhttp.ErrorWithStatus) {
content := contentSettingPlaceholder{}
- return newResponse("sync/configuration/user-add.html", content), nil
+ return html.NewResponse("sync/configuration/user-add.html", content), nil
}
-func getConfigurationUserList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSettingPlaceholder], *errorWithStatus) {
+func getConfigurationUserList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSettingPlaceholder], *nhttp.ErrorWithStatus) {
content := contentSettingPlaceholder{}
- return newResponse("sync/configuration/user-list.html", content), nil
+ return html.NewResponse("sync/configuration/user-list.html", content), nil
}
diff --git a/sync/dash.go b/sync/dash.go
index 979c1998..73ffe07f 100644
--- a/sync/dash.go
+++ b/sync/dash.go
@@ -14,6 +14,7 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
)
@@ -61,8 +62,8 @@ func getDistrict(w http.ResponseWriter, r *http.Request) {
html.RenderOrError(w, "sync/district.html", &context)
}
-func getLayoutTest(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentLayoutTest], *errorWithStatus) {
- return newResponse("sync/layout-test.html", contentLayoutTest{}), nil
+func getLayoutTest(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentLayoutTest], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/layout-test.html", contentLayoutTest{}), nil
}
func getRoot(w http.ResponseWriter, r *http.Request) {
@@ -93,40 +94,40 @@ func getRoot(w http.ResponseWriter, r *http.Request) {
}
}
-func getSource(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSource], *errorWithStatus) {
+func getSource(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSource], *nhttp.ErrorWithStatus) {
globalid_s := chi.URLParam(r, "globalid")
if globalid_s == "" {
- return nil, newError("No globalid provided: %w", nil)
+ return nil, nhttp.NewError("No globalid provided: %w", nil)
}
globalid, err := uuid.Parse(globalid_s)
if err != nil {
- return nil, newError("globalid is not a UUID: %w", nil)
+ return nil, nhttp.NewError("globalid is not a UUID: %w", nil)
}
userContent, err := contentForUser(r.Context(), user)
if err != nil {
- return nil, newError("Failed to get user content: %w", err)
+ return nil, nhttp.NewError("Failed to get user content: %w", err)
}
s, err := sourceByGlobalId(r.Context(), org, globalid)
if err != nil {
- return nil, newError("Failed to get source: %w", err)
+ return nil, nhttp.NewError("Failed to get source: %w", err)
}
inspections, err := inspectionsBySource(r.Context(), org, globalid)
if err != nil {
- return nil, newError("Failed to get inspections: %w", err)
+ return nil, nhttp.NewError("Failed to get inspections: %w", err)
}
traps, err := trapsBySource(r.Context(), org, globalid)
if err != nil {
- return nil, newError("Failed to get traps: %w", err)
+ return nil, nhttp.NewError("Failed to get traps: %w", err)
}
treatments, err := treatmentsBySource(r.Context(), org, globalid)
if err != nil {
- return nil, newError("Failed to get treatments: %w", err)
+ return nil, nhttp.NewError("Failed to get treatments: %w", err)
}
treatment_models := modelTreatment(treatments)
latlng, err := s.H3Cell.LatLng()
if err != nil {
- return nil, newError("Failed to get latlng: %w", err)
+ return nil, nhttp.NewError("Failed to get latlng: %w", err)
}
data := contentSource{
Inspections: inspections,
@@ -148,40 +149,40 @@ func getSource(ctx context.Context, r *http.Request, org *models.Organization, u
User: userContent,
}
- return newResponse("sync/source.html", data), nil
+ return html.NewResponse("sync/source.html", data), nil
}
-func getStadia(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentDashboard], *errorWithStatus) {
+func getStadia(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentDashboard], *nhttp.ErrorWithStatus) {
data := contentDashboard{
MapData: ComponentMap{
MapboxToken: config.MapboxToken,
},
}
- return newResponse("sync/stadia.html", data), nil
+ return html.NewResponse("sync/stadia.html", data), nil
}
func getTemplateTest(w http.ResponseWriter, r *http.Request) {
html.RenderOrError(w, "sync/template-test.html", nil)
}
-func getTrap(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentTrap], *errorWithStatus) {
+func getTrap(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentTrap], *nhttp.ErrorWithStatus) {
globalid_s := chi.URLParam(r, "globalid")
if globalid_s == "" {
- return nil, newError("No globalid provided: %w", nil)
+ return nil, nhttp.NewError("No globalid provided: %w", nil)
}
globalid, err := uuid.Parse(globalid_s)
if err != nil {
- return nil, newError("globalid is not a UUID: %w", nil)
+ return nil, nhttp.NewError("globalid is not a UUID: %w", nil)
}
userContent, err := contentForUser(r.Context(), user)
if err != nil {
- return nil, newError("Failed to get user content: %w", err)
+ return nil, nhttp.NewError("Failed to get user content: %w", err)
}
t, err := trapByGlobalId(r.Context(), org, globalid)
if err != nil {
- return nil, newError("Failed to get trap: %w", err)
+ return nil, nhttp.NewError("Failed to get trap: %w", err)
}
latlng, err := t.H3Cell.LatLng()
if err != nil {
- return nil, newError("Failed to get latlng: %w", err)
+ return nil, nhttp.NewError("Failed to get latlng: %w", err)
}
data := contentTrap{
MapData: ComponentMap{
@@ -198,7 +199,7 @@ func getTrap(ctx context.Context, r *http.Request, org *models.Organization, use
Trap: t,
User: userContent,
}
- return newResponse("sync/trap.html", data), nil
+ return html.NewResponse("sync/trap.html", data), nil
}
func dashboard(ctx context.Context, w http.ResponseWriter, org *models.Organization, user *models.User) {
@@ -260,7 +261,7 @@ func dashboard(ctx context.Context, w http.ResponseWriter, org *models.Organizat
}
html.RenderOrError(w, "sync/dashboard.html", contentAuthenticated[contentDashboard]{
C: content,
- URL: newContentURL(),
+ URL: html.NewContentURL(),
User: userContent,
})
}
diff --git a/sync/download.go b/sync/download.go
index 4a151b4e..2217a5b3 100644
--- a/sync/download.go
+++ b/sync/download.go
@@ -5,11 +5,13 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentDownloadPlaceholder struct{}
-func getDownloadList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentDownloadPlaceholder], *errorWithStatus) {
+func getDownloadList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentDownloadPlaceholder], *nhttp.ErrorWithStatus) {
content := contentDownloadPlaceholder{}
- return newResponse("sync/download-list.html", content), nil
+ return html.NewResponse("sync/download-list.html", content), nil
}
diff --git a/sync/handler.go b/sync/handler.go
new file mode 100644
index 00000000..4937456f
--- /dev/null
+++ b/sync/handler.go
@@ -0,0 +1,119 @@
+package sync
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/Gleipnir-Technology/nidus-sync/auth"
+ "github.com/Gleipnir-Technology/nidus-sync/db"
+ "github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
+ "github.com/rs/zerolog/log"
+)
+
+type handlerFunctionGet[T any] func(context.Context, *http.Request, *models.Organization, *models.User) (*html.Response[T], *nhttp.ErrorWithStatus)
+type wrappedHandler func(http.ResponseWriter, *http.Request)
+type contentAuthenticated[T any] struct {
+ C T
+ Config html.ContentConfig
+ Organization *models.Organization
+ URL html.ContentURL
+ User User
+}
+
+// w http.ResponseWriter, r *http.Request, u *models.User) {
+func authenticatedHandler[T any](f handlerFunctionGet[T]) http.Handler {
+ return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
+ ctx := r.Context()
+ userContent, err := contentForUser(ctx, u)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if org == nil {
+ http.Error(w, "nil org", http.StatusInternalServerError)
+ return
+ }
+ resp, e := f(ctx, r, org, u)
+ //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 sync pages")
+ http.Error(w, e.Error(), e.Status)
+ return
+ }
+ html.RenderOrError(w, resp.Template, contentAuthenticated[T]{
+ C: resp.Content,
+ Config: html.NewContentConfig(),
+ Organization: org,
+ URL: html.NewContentURL(),
+ User: userContent,
+ })
+ })
+}
+
+type handlerFunctionPost[T any] func(context.Context, *http.Request, *models.Organization, *models.User, T) (string, *nhttp.ErrorWithStatus)
+
+func authenticatedHandlerPost[T any](f handlerFunctionPost[T]) http.Handler {
+ return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
+ err := r.ParseForm()
+ if err != nil {
+ respondError(w, "Failed to parse form", err, http.StatusBadRequest)
+ return
+ }
+
+ var content T
+
+ err = decoder.Decode(&content, r.PostForm)
+ if err != nil {
+ respondError(w, "Failed to decode form", err, http.StatusBadRequest)
+ return
+ }
+ ctx := r.Context()
+ org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ path, e := f(ctx, r, org, u, content)
+ if e != nil {
+ http.Error(w, e.Error(), e.Status)
+ return
+ }
+ http.Redirect(w, r, path, http.StatusFound)
+ })
+}
+func authenticatedHandlerPostMultipart[T any](f handlerFunctionPost[T]) http.Handler {
+ return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
+ err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
+ if err != nil {
+ respondError(w, "Failed to parse form", err, http.StatusBadRequest)
+ return
+ }
+
+ var content T
+
+ err = decoder.Decode(&content, r.PostForm)
+ if err != nil {
+ respondError(w, "Failed to decode form", err, http.StatusBadRequest)
+ return
+ }
+ ctx := r.Context()
+ org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ path, e := f(ctx, r, org, u, content)
+ if e != nil {
+ http.Error(w, e.Error(), e.Status)
+ return
+ }
+ http.Redirect(w, r, path, http.StatusFound)
+ })
+}
diff --git a/sync/intelligence.go b/sync/intelligence.go
index b8c1037c..13f45635 100644
--- a/sync/intelligence.go
+++ b/sync/intelligence.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentIntelligenceRoot struct{}
-func getIntelligenceRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentIntelligenceRoot], *errorWithStatus) {
- return newResponse("sync/intelligence-root.html", contentIntelligenceRoot{}), nil
+func getIntelligenceRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentIntelligenceRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/intelligence-root.html", contentIntelligenceRoot{}), nil
}
diff --git a/sync/mailer.go b/sync/mailer.go
index f791fe39..41cc2707 100644
--- a/sync/mailer.go
+++ b/sync/mailer.go
@@ -16,7 +16,7 @@ import (
)
type contentMailer struct {
- Config contentConfig
+ Config html.ContentConfig
DocumentID string
LogoURL string
Organization *models.Organization
@@ -71,7 +71,7 @@ func getMailerPreview(w http.ResponseWriter, r *http.Request) {
}
doc_id := uuid.New()
html.RenderOrError(w, "sync/mailer.html", contentMailer{
- Config: newContentConfig(),
+ Config: html.NewContentConfig(),
DocumentID: doc_id.String(),
LogoURL: config.MakeURLNidus("/api/district/%s/logo", org.Slug.GetOr("unset")),
Organization: org,
diff --git a/sync/messages.go b/sync/messages.go
index 6dc06422..5eae4108 100644
--- a/sync/messages.go
+++ b/sync/messages.go
@@ -5,11 +5,13 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentMessageList struct{}
-func getMessageList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentMessageList], *errorWithStatus) {
+func getMessageList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentMessageList], *nhttp.ErrorWithStatus) {
content := contentMessageList{}
- return newResponse("sync/message-list.html", content), nil
+ return html.NewResponse("sync/message-list.html", content), nil
}
diff --git a/sync/mock.go b/sync/mock.go
index 17c2d955..3c8c87b9 100644
--- a/sync/mock.go
+++ b/sync/mock.go
@@ -54,7 +54,7 @@ func addMock(r chi.Router, path string, template string) {
}
type contentMock struct {
- Config contentConfig
+ Config html.ContentConfig
DistrictName string
URLs ContentMockURLs
}
@@ -66,7 +66,7 @@ func renderMock(template_name string) http.HandlerFunc {
code = "abc-123"
}
data := contentMock{
- Config: newContentConfig(),
+ Config: html.NewContentConfig(),
DistrictName: "Delta MVCD",
URLs: ContentMockURLs{
Dispatch: "/mock/dispatch",
@@ -91,13 +91,13 @@ func renderMock(template_name string) http.HandlerFunc {
}
type contentMockList struct {
- Config contentConfig
+ Config html.ContentConfig
Mocks []mock
}
func renderMockList(w http.ResponseWriter, r *http.Request) {
data := contentMockList{
- Config: newContentConfig(),
+ Config: html.NewContentConfig(),
Mocks: mocks,
}
html.RenderOrError(w, "sync/mock/root.html", data)
diff --git a/sync/notification.go b/sync/notification.go
index 54fc808b..6f85c32d 100644
--- a/sync/notification.go
+++ b/sync/notification.go
@@ -8,6 +8,8 @@ import (
//"time"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/Gleipnir-Technology/nidus-sync/notification"
//"github.com/Gleipnir-Technology/bob"
//"github.com/Gleipnir-Technology/bob/dialect/psql"
@@ -22,12 +24,12 @@ type contentNotificationList struct {
Notifications []notification.Notification
}
-func getNotificationList(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentNotificationList], *errorWithStatus) {
+func getNotificationList(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentNotificationList], *nhttp.ErrorWithStatus) {
notifications, err := notification.ForUser(ctx, u)
if err != nil {
- return nil, newError("Failed to get notifications: %w", err)
+ return nil, nhttp.NewError("Failed to get notifications: %w", err)
}
- return newResponse("sync/notification-list.html", contentNotificationList{
+ return html.NewResponse("sync/notification-list.html", contentNotificationList{
Notifications: notifications,
}), nil
}
diff --git a/sync/oauth.go b/sync/oauth.go
index 35722b4f..2451f388 100644
--- a/sync/oauth.go
+++ b/sync/oauth.go
@@ -10,6 +10,8 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/background"
"github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/rs/zerolog/log"
)
@@ -65,7 +67,7 @@ func getArcgisOauthCallback(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, config.MakeURLNidus("/"), http.StatusFound)
}
-func getOAuthRefresh(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentOauthPrompt], *errorWithStatus) {
+func getOAuthRefresh(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentOauthPrompt], *nhttp.ErrorWithStatus) {
data := contentOauthPrompt{}
- return newResponse("sync/oauth-prompt.html", data), nil
+ return html.NewResponse("sync/oauth-prompt.html", data), nil
}
diff --git a/sync/operations.go b/sync/operations.go
index 1930a6cb..d56100d2 100644
--- a/sync/operations.go
+++ b/sync/operations.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentOperationsRoot struct{}
-func getOperationsRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentOperationsRoot], *errorWithStatus) {
- return newResponse("sync/operations-root.html", contentOperationsRoot{}), nil
+func getOperationsRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentOperationsRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/operations-root.html", contentOperationsRoot{}), nil
}
diff --git a/sync/parcel.go b/sync/parcel.go
index d3329cca..1f7a7d32 100644
--- a/sync/parcel.go
+++ b/sync/parcel.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentParcel struct{}
-func getParcel(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentParcel], *errorWithStatus) {
- return newResponse("sync/parcel.html", contentParcel{}), nil
+func getParcel(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentParcel], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/parcel.html", contentParcel{}), nil
}
diff --git a/sync/planning.go b/sync/planning.go
index bca944ce..b55df1ea 100644
--- a/sync/planning.go
+++ b/sync/planning.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentPlanningRoot struct{}
-func getPlanningRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPlanningRoot], *errorWithStatus) {
- return newResponse("sync/planning-root.html", contentPlanningRoot{}), nil
+func getPlanningRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPlanningRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/planning-root.html", contentPlanningRoot{}), nil
}
diff --git a/sync/pool.go b/sync/pool.go
index b5c8ec56..a2c4395d 100644
--- a/sync/pool.go
+++ b/sync/pool.go
@@ -5,16 +5,18 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentPoolList struct{}
-func getPoolList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPoolList], *errorWithStatus) {
- return newResponse("sync/pool-list.html", contentPoolList{}), nil
+func getPoolList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/pool-list.html", contentPoolList{}), nil
}
-func getPoolCreate(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPoolList], *errorWithStatus) {
- return newResponse("sync/pool-upload.html", contentPoolList{}), nil
+func getPoolCreate(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/pool-upload.html", contentPoolList{}), nil
}
-func getPoolByID(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPoolList], *errorWithStatus) {
- return newResponse("sync/pool-by-id.html", contentPoolList{}), nil
+func getPoolByID(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/pool-by-id.html", contentPoolList{}), nil
}
diff --git a/sync/radar.go b/sync/radar.go
index c2d74ea2..d70452e4 100644
--- a/sync/radar.go
+++ b/sync/radar.go
@@ -6,19 +6,21 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentRadar struct {
Organization *models.Organization
}
-func getRadar(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentRadar], *errorWithStatus) {
+func getRadar(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentRadar], *nhttp.ErrorWithStatus) {
org, err := user.Organization().One(ctx, db.PGInstance.BobDB)
if err != nil {
- return nil, newError("get org: %w", err)
+ return nil, nhttp.NewError("get org: %w", err)
}
data := contentRadar{
Organization: org,
}
- return newResponse("sync/radar.html", data), nil
+ return html.NewResponse("sync/radar.html", data), nil
}
diff --git a/sync/review.go b/sync/review.go
index 996cbeca..12facd2b 100644
--- a/sync/review.go
+++ b/sync/review.go
@@ -5,10 +5,12 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentReviewRoot struct{}
-func getReviewRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentReviewRoot], *errorWithStatus) {
- return newResponse("sync/review-root.html", contentReviewRoot{}), nil
+func getReviewRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentReviewRoot], *nhttp.ErrorWithStatus) {
+ return html.NewResponse("sync/review-root.html", contentReviewRoot{}), nil
}
diff --git a/sync/routes.go b/sync/routes.go
index 6a54ffc8..b8ad0325 100644
--- a/sync/routes.go
+++ b/sync/routes.go
@@ -1,17 +1,10 @@
package sync
import (
- "context"
- "fmt"
- "net/http"
-
"github.com/Gleipnir-Technology/nidus-sync/api"
"github.com/Gleipnir-Technology/nidus-sync/auth"
- "github.com/Gleipnir-Technology/nidus-sync/db"
- "github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/html"
"github.com/go-chi/chi/v5"
- "github.com/rs/zerolog/log"
)
func Router() chi.Router {
@@ -98,147 +91,3 @@ func Router() chi.Router {
html.AddStaticRoute(r, "/static")
return r
}
-
-type errorWithStatus struct {
- Message string
- Status int
-}
-
-func (e *errorWithStatus) Error() string {
- return e.Message
-}
-func newError(mesg_format string, args ...interface{}) *errorWithStatus {
- return newErrorStatus(http.StatusInternalServerError, mesg_format, args...)
-}
-func newErrorMaybe(mesg_format string, err error, args ...interface{}) *errorWithStatus {
- if err == nil {
- return nil
- }
- allArgs := append([]interface{}{err}, args...)
- return newErrorStatus(http.StatusInternalServerError, mesg_format, allArgs...)
-}
-func newErrorStatus(status int, mesg_format string, args ...interface{}) *errorWithStatus {
- w := fmt.Errorf(mesg_format, args...)
- return &errorWithStatus{
- Message: w.Error(),
- Status: status,
- }
-}
-
-type response[T any] struct {
- content T
- template string
-}
-
-func newResponse[T any](template string, content T) *response[T] {
- return &response[T]{
- content: content,
- template: template,
- }
-}
-
-type handlerFunctionGet[T any] func(context.Context, *http.Request, *models.Organization, *models.User) (*response[T], *errorWithStatus)
-type wrappedHandler func(http.ResponseWriter, *http.Request)
-type contentAuthenticated[T any] struct {
- C T
- Config contentConfig
- Organization *models.Organization
- URL contentURL
- User User
-}
-
-// w http.ResponseWriter, r *http.Request, u *models.User) {
-func authenticatedHandler[T any](f handlerFunctionGet[T]) http.Handler {
- return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
- ctx := r.Context()
- userContent, err := contentForUser(ctx, u)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- resp, e := f(ctx, r, org, u)
- //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 sync pages")
- http.Error(w, e.Error(), e.Status)
- return
- }
- if org == nil {
- http.Error(w, "nil org", http.StatusInternalServerError)
- return
- }
- html.RenderOrError(w, resp.template, contentAuthenticated[T]{
- C: resp.content,
- Config: newContentConfig(),
- Organization: org,
- URL: newContentURL(),
- User: userContent,
- })
- })
-}
-
-type handlerFunctionPost[T any] func(context.Context, *http.Request, *models.Organization, *models.User, T) (string, *errorWithStatus)
-
-func authenticatedHandlerPost[T any](f handlerFunctionPost[T]) http.Handler {
- return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
- err := r.ParseForm()
- if err != nil {
- respondError(w, "Failed to parse form", err, http.StatusBadRequest)
- return
- }
-
- var content T
-
- err = decoder.Decode(&content, r.PostForm)
- if err != nil {
- respondError(w, "Failed to decode form", err, http.StatusBadRequest)
- return
- }
- ctx := r.Context()
- org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- path, e := f(ctx, r, org, u, content)
- if e != nil {
- http.Error(w, e.Error(), e.Status)
- return
- }
- http.Redirect(w, r, path, http.StatusFound)
- })
-}
-func authenticatedHandlerPostMultipart[T any](f handlerFunctionPost[T]) http.Handler {
- return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u *models.User) {
- err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
- if err != nil {
- respondError(w, "Failed to parse form", err, http.StatusBadRequest)
- return
- }
-
- var content T
-
- err = decoder.Decode(&content, r.PostForm)
- if err != nil {
- respondError(w, "Failed to decode form", err, http.StatusBadRequest)
- return
- }
- ctx := r.Context()
- org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- path, e := f(ctx, r, org, u, content)
- if e != nil {
- http.Error(w, e.Error(), e.Status)
- return
- }
- http.Redirect(w, r, path, http.StatusFound)
- })
-}
diff --git a/sync/service-request.go b/sync/service-request.go
index 48b56944..2035dd6a 100644
--- a/sync/service-request.go
+++ b/sync/service-request.go
@@ -7,6 +7,8 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentActiveServiceRequest struct {
@@ -32,11 +34,11 @@ type contentServiceRequestList struct {
ClosedRequests []contentClosedServiceRequest
}
-func getServiceRequestDetail(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentServiceRequestDetail], *errorWithStatus) {
+func getServiceRequestDetail(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentServiceRequestDetail], *nhttp.ErrorWithStatus) {
content := contentServiceRequestDetail{}
- return newResponse("sync/service-request-detail.html", content), nil
+ return html.NewResponse("sync/service-request-detail.html", content), nil
}
-func getServiceRequestList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentServiceRequestList], *errorWithStatus) {
+func getServiceRequestList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentServiceRequestList], *nhttp.ErrorWithStatus) {
now := time.Now()
content := contentServiceRequestList{
ActiveRequests: []contentActiveServiceRequest{
@@ -112,5 +114,5 @@ func getServiceRequestList(ctx context.Context, r *http.Request, org *models.Org
},
},
}
- return newResponse("sync/service-request-list.html", content), nil
+ return html.NewResponse("sync/service-request-list.html", content), nil
}
diff --git a/sync/signin.go b/sync/signin.go
index 479a310e..cdb6c4aa 100644
--- a/sync/signin.go
+++ b/sync/signin.go
@@ -98,8 +98,8 @@ func postSignup(w http.ResponseWriter, r *http.Request) {
type contentUnauthenticated[T any] struct {
C T
- Config contentConfig
- URL contentURL
+ Config html.ContentConfig
+ URL html.ContentURL
}
func signin(w http.ResponseWriter, errorCode string, next string) {
@@ -111,8 +111,8 @@ func signin(w http.ResponseWriter, errorCode string, next string) {
InvalidCredentials: errorCode == "invalid-credentials",
Next: next,
},
- Config: newContentConfig(),
- URL: newContentURL(),
+ Config: html.NewContentConfig(),
+ URL: html.NewContentURL(),
}
html.RenderOrError(w, "sync/signin.html", data)
}
diff --git a/sync/sudo.go b/sync/sudo.go
index 2e485ac6..a28efe83 100644
--- a/sync/sudo.go
+++ b/sync/sudo.go
@@ -10,6 +10,8 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/gorilla/schema"
"github.com/rs/zerolog/log"
)
@@ -19,9 +21,9 @@ type contentSudo struct {
ForwardEmailNidusAddress string
}
-func getSudo(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentSudo], *errorWithStatus) {
+func getSudo(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentSudo], *nhttp.ErrorWithStatus) {
if user.Role != enums.UserroleRoot {
- return nil, &errorWithStatus{
+ return nil, &nhttp.ErrorWithStatus{
Message: "You have to be a root user to access this",
Status: http.StatusForbidden,
}
@@ -30,7 +32,7 @@ func getSudo(ctx context.Context, r *http.Request, org *models.Organization, use
ForwardEmailRMOAddress: config.ForwardEmailRMOAddress,
ForwardEmailNidusAddress: config.ForwardEmailNidusAddress,
}
- return newResponse("sync/sudo.html", content), nil
+ return html.NewResponse("sync/sudo.html", content), nil
}
var decoder = schema.NewDecoder()
@@ -42,9 +44,9 @@ type FormEmail struct {
To string `schema:"emailTo"`
}
-func postSudoEmail(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, e FormEmail) (string, *errorWithStatus) {
+func postSudoEmail(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, e FormEmail) (string, *nhttp.ErrorWithStatus) {
if u.Role != enums.UserroleRoot {
- return "", &errorWithStatus{
+ return "", &nhttp.ErrorWithStatus{
Message: "You must have sudo powers to do this",
Status: http.StatusForbidden,
}
@@ -71,9 +73,9 @@ type FormSMS struct {
Phone string `schema:"smsPhone"`
}
-func postSudoSMS(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, sms FormSMS) (string, *errorWithStatus) {
+func postSudoSMS(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, sms FormSMS) (string, *nhttp.ErrorWithStatus) {
if u.Role != enums.UserroleRoot {
- return "", &errorWithStatus{
+ return "", &nhttp.ErrorWithStatus{
Message: "You must have sudo powers to do this",
Status: http.StatusForbidden,
}
diff --git a/sync/text.go b/sync/text.go
index 6ddc774d..1d22f077 100644
--- a/sync/text.go
+++ b/sync/text.go
@@ -5,11 +5,13 @@ import (
"net/http"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
)
type contentTextMessages struct{}
-func getTextMessages(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentTextMessages], *errorWithStatus) {
+func getTextMessages(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentTextMessages], *nhttp.ErrorWithStatus) {
content := contentTextMessages{}
- return newResponse("sync/text-messages.html", content), nil
+ return html.NewResponse("sync/text-messages.html", content), nil
}
diff --git a/sync/upload.go b/sync/upload.go
index 47cd7cad..4e5c0388 100644
--- a/sync/upload.go
+++ b/sync/upload.go
@@ -8,10 +8,12 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
+ "github.com/Gleipnir-Technology/nidus-sync/html"
+ nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
"github.com/Gleipnir-Technology/nidus-sync/platform"
"github.com/Gleipnir-Technology/nidus-sync/userfile"
"github.com/go-chi/chi/v5"
- "github.com/rs/zerolog/log"
+ //"github.com/rs/zerolog/log"
)
type contentUploadList struct {
@@ -19,11 +21,11 @@ type contentUploadList struct {
}
type contentUploadPlaceholder struct{}
-func getUploadList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentUploadList], *errorWithStatus) {
+func getUploadList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentUploadList], *nhttp.ErrorWithStatus) {
rows, err := platform.UploadSummaryList(ctx, org)
- return newResponse("sync/upload-list.html", contentUploadList{
+ return html.NewResponse("sync/upload-list.html", contentUploadList{
RecentUploads: rows,
- }), newErrorMaybe("get upload list: %w", err)
+ }), nhttp.NewErrorMaybe("get upload list: %w", err)
}
type contentUploadDetail struct {
@@ -36,110 +38,108 @@ type contentUploadPoolList struct {
}
type contentUploadPool struct{}
-func getUploadPool(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadPool], *errorWithStatus) {
+func getUploadPool(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentUploadPool], *nhttp.ErrorWithStatus) {
data := contentUploadPool{}
- return newResponse("sync/upload-csv-pool.html", data), nil
+ return html.NewResponse("sync/upload-csv-pool.html", data), nil
}
type contentUploadPoolFlyoverCreate struct{}
-func getUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadPoolFlyoverCreate], *errorWithStatus) {
+func getUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentUploadPoolFlyoverCreate], *nhttp.ErrorWithStatus) {
data := contentUploadPoolFlyoverCreate{}
- return newResponse("sync/upload-csv-pool-flyover.html", data), nil
+ return html.NewResponse("sync/upload-csv-pool-flyover.html", data), nil
}
type contentUploadPoolCustomCreate struct{}
-func getUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadPoolCustomCreate], *errorWithStatus) {
+func getUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentUploadPoolCustomCreate], *nhttp.ErrorWithStatus) {
data := contentUploadPoolCustomCreate{}
- return newResponse("sync/upload-csv-pool-custom.html", data), nil
+ return html.NewResponse("sync/upload-csv-pool-custom.html", data), nil
}
-func getUploadByID(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*response[contentUploadDetail], *errorWithStatus) {
- test := newContentURLUpload()
- log.Info().Str("output", test.Discard(123)).Send()
+func getUploadByID(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentUploadDetail], *nhttp.ErrorWithStatus) {
file_id_str := chi.URLParam(r, "id")
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
if err != nil {
- return nil, newError("Failed to parse file_id: %w", err)
+ return nil, nhttp.NewError("Failed to parse file_id: %w", err)
}
file_id := int32(file_id_)
detail, err := platform.GetUploadPoolDetail(ctx, u.OrganizationID, file_id)
if err != nil {
- return nil, newError("Failed to get pool: %w", err)
+ return nil, nhttp.NewError("Failed to get pool: %w", err)
}
data := contentUploadDetail{
CSVFileID: file_id,
Organization: org,
Upload: detail,
}
- return newResponse("sync/upload-by-id.html", data), nil
+ return html.NewResponse("sync/upload-by-id.html", data), nil
}
type FormUploadCommit struct{}
-func postUploadCommit(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadCommit) (string, *errorWithStatus) {
+func postUploadCommit(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadCommit) (string, *nhttp.ErrorWithStatus) {
file_id_str := chi.URLParam(r, "id")
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
if err != nil {
- return "", newError("Failed to parse file_id: %w", err)
+ return "", nhttp.NewError("Failed to parse file_id: %w", err)
}
err = platform.UploadCommit(ctx, org, int32(file_id_))
if err != nil {
- return "", newError("Failed to mark discarded: %w", err)
+ return "", nhttp.NewError("Failed to mark discarded: %w", err)
}
return "/configuration/upload", nil
}
type FormUploadDiscard struct{}
-func postUploadDiscard(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadDiscard) (string, *errorWithStatus) {
+func postUploadDiscard(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadDiscard) (string, *nhttp.ErrorWithStatus) {
file_id_str := chi.URLParam(r, "id")
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
if err != nil {
- return "", newError("Failed to parse file_id: %w", err)
+ return "", nhttp.NewError("Failed to parse file_id: %w", err)
}
err = platform.UploadDiscard(ctx, org, int32(file_id_))
if err != nil {
- return "", newError("Failed to mark discarded: %w", err)
+ return "", nhttp.NewError("Failed to mark discarded: %w", err)
}
return "/configuration/upload", nil
}
type FormUploadPool struct{}
-func postUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *errorWithStatus) {
+func postUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *nhttp.ErrorWithStatus) {
uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV)
if err != nil {
- return "", newError("Failed to extract image uploads: %s", err)
+ return "", nhttp.NewError("Failed to extract image uploads: %s", err)
}
if len(uploads) == 0 {
- return "", newErrorStatus(http.StatusBadRequest, "No upload found")
+ return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
}
if len(uploads) != 1 {
- return "", newErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
+ return "", nhttp.NewErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
}
upload := uploads[0]
saved_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypeFlyover)
if err != nil {
- return "", newError("Failed to create new pool: %w", err)
+ return "", nhttp.NewError("Failed to create new pool: %w", err)
}
return fmt.Sprintf("/configuration/upload/%d", saved_upload.ID), nil
}
-func postUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *errorWithStatus) {
+func postUploadPoolCustomCreate(ctx context.Context, r *http.Request, org *models.Organization, u *models.User, f FormUploadPool) (string, *nhttp.ErrorWithStatus) {
uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV)
if err != nil {
- return "", newError("Failed to extract image uploads: %s", err)
+ return "", nhttp.NewError("Failed to extract image uploads: %s", err)
}
if len(uploads) == 0 {
- return "", newErrorStatus(http.StatusBadRequest, "No upload found")
+ return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
}
if len(uploads) != 1 {
- return "", newErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
+ return "", nhttp.NewErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
}
upload := uploads[0]
pool_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypePoollist)
if err != nil {
- return "", newError("Failed to create new pool: %w", err)
+ return "", nhttp.NewError("Failed to create new pool: %w", err)
}
return fmt.Sprintf("/configuration/upload/%d", pool_upload.ID), nil
}