Move handler objects to common location to share with RMO
This commit is contained in:
parent
87fe5ec2e5
commit
0f6da8e25f
33 changed files with 449 additions and 308 deletions
15
html/config.go
Normal file
15
html/config.go
Normal file
|
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
7
html/content.go
Normal file
7
html/content.go
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
package html
|
||||||
|
|
||||||
|
type Content[T any] struct {
|
||||||
|
C T
|
||||||
|
Config ContentConfig
|
||||||
|
URL ContentURL
|
||||||
|
}
|
||||||
26
html/handler.go
Normal file
26
html/handler.go
Normal file
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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")
|
log.Warn().Int("status", s).Err(e).Str("user message", m).Msg("Responding with an error")
|
||||||
http.Error(w, m, s)
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package sync
|
package html
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type contentURL struct {
|
type ContentURL struct {
|
||||||
Configuration contentURLConfiguration
|
Configuration contentURLConfiguration
|
||||||
OAuthRefreshArcGIS string
|
OAuthRefreshArcGIS string
|
||||||
Root string
|
Root string
|
||||||
|
|
@ -16,8 +16,8 @@ type contentURL struct {
|
||||||
Upload contentURLUpload
|
Upload contentURLUpload
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContentURL() contentURL {
|
func NewContentURL() ContentURL {
|
||||||
return contentURL{
|
return ContentURL{
|
||||||
Configuration: newContentURLConfiguration(),
|
Configuration: newContentURLConfiguration(),
|
||||||
OAuthRefreshArcGIS: config.MakeURLNidus("/arcgis/oauth/begin"),
|
OAuthRefreshArcGIS: config.MakeURLNidus("/arcgis/oauth/begin"),
|
||||||
Root: config.MakeURLNidus("/"),
|
Root: config.MakeURLNidus("/"),
|
||||||
32
http/error_with_status.go
Normal file
32
http/error_with_status.go
Normal file
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,67 @@
|
||||||
package rmo
|
package rmo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"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"
|
//"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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func Router() chi.Router {
|
||||||
r.Get("/email/unsubscribe", getEmailUnsubscribe)
|
r.Get("/email/unsubscribe", getEmailUnsubscribe)
|
||||||
r.Get("/email/unsubscribe/report/{report_id}", getEmailReportUnsubscribe)
|
r.Get("/email/unsubscribe/report/{report_id}", getEmailReportUnsubscribe)
|
||||||
r.Get("/image/{uuid}", getImageByUUID)
|
r.Get("/image/{uuid}", getImageByUUID)
|
||||||
r.Get("/mailer/{public_id}", getMailer)
|
r.Get("/mailer/{public_id}", html.MakeGet(getMailer))
|
||||||
r.Route("/mock", addMockRoutes)
|
r.Route("/mock", addMockRoutes)
|
||||||
r.Post("/register-notifications", postRegisterNotifications)
|
r.Post("/register-notifications", postRegisterNotifications)
|
||||||
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
|
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
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{}
|
content := contentAdminDash{}
|
||||||
return newResponse("sync/admin-dash.html", content), nil
|
return html.NewResponse("sync/admin-dash.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
sync/cell.go
24
sync/cell.go
|
|
@ -6,6 +6,8 @@ import (
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
|
"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/go-chi/chi/v5"
|
||||||
"github.com/uber/h3-go/v4"
|
"github.com/uber/h3-go/v4"
|
||||||
)
|
)
|
||||||
|
|
@ -19,46 +21,46 @@ type contentCell struct {
|
||||||
Treatments []Treatment
|
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")
|
cell_str := chi.URLParam(r, "cell")
|
||||||
if cell_str == "" {
|
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)
|
c, err := HexToInt64(cell_str)
|
||||||
if err != nil {
|
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()
|
center, err := h3.Cell(c).LatLng()
|
||||||
if err != nil {
|
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()
|
boundary, err := h3.Cell(c).Boundary()
|
||||||
if err != nil {
|
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))
|
inspections, err := inspectionsByCell(ctx, org, h3.Cell(c))
|
||||||
if err != nil {
|
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)})
|
geojson, err := h3utils.H3ToGeoJSON([]h3.Cell{h3.Cell(c)})
|
||||||
if err != nil {
|
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()
|
resolution := h3.Cell(c).Resolution()
|
||||||
sources, err := breedingSourcesByCell(ctx, org, h3.Cell(c))
|
sources, err := breedingSourcesByCell(ctx, org, h3.Cell(c))
|
||||||
if err != nil {
|
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))
|
traps, err := trapsByCell(ctx, org, h3.Cell(c))
|
||||||
if err != nil {
|
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))
|
treatments, err := treatmentsByCell(ctx, org, h3.Cell(c))
|
||||||
if err != nil {
|
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,
|
BreedingSources: sources,
|
||||||
CellBoundary: boundary,
|
CellBoundary: boundary,
|
||||||
Inspections: inspections,
|
Inspections: inspections,
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentCommunicationRoot struct{}
|
||||||
|
|
||||||
func getCommunicationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentCommunicationRoot], *errorWithStatus) {
|
func getCommunicationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentCommunicationRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/communication-root.html", contentCommunicationRoot{}), nil
|
return html.NewResponse("sync/communication-root.html", contentCommunicationRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,26 +5,17 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/arcgis"
|
"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"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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"
|
//"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type contentConfig struct {
|
|
||||||
IsProductionEnvironment bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContentConfig() contentConfig {
|
|
||||||
return contentConfig{
|
|
||||||
IsProductionEnvironment: config.IsProductionEnvironment(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type contentConfigurationRoot struct{}
|
type contentConfigurationRoot struct{}
|
||||||
|
|
||||||
func getConfigurationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentConfigurationRoot], *errorWithStatus) {
|
func getConfigurationRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentConfigurationRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/configuration/root.html", contentConfigurationRoot{}), nil
|
return html.NewResponse("sync/configuration/root.html", contentConfigurationRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentSettingOrganization struct {
|
type contentSettingOrganization struct {
|
||||||
|
|
@ -35,10 +26,10 @@ type contentSettingIntegration struct {
|
||||||
ArcGISOAuth *models.ArcgisOauthToken
|
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)
|
org, err := u.Organization().One(ctx, db.PGInstance.BobDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("get organization: %w", err)
|
return nil, nhttp.NewError("get organization: %w", err)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
var district contentDistrict
|
var district contentDistrict
|
||||||
|
|
@ -74,44 +65,44 @@ func getConfigurationOrganization(ctx context.Context, r *http.Request, org *mod
|
||||||
data := contentSettingOrganization{
|
data := contentSettingOrganization{
|
||||||
Organization: org,
|
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)
|
oauth, err := arcgis.GetOAuthForUser(ctx, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Failed to get oauth: %w", err)
|
return nil, nhttp.NewError("Failed to get oauth: %w", err)
|
||||||
}
|
}
|
||||||
data := contentSettingIntegration{
|
data := contentSettingIntegration{
|
||||||
ArcGISOAuth: oauth,
|
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)
|
oauth, err := arcgis.GetOAuthForUser(ctx, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Failed to get oauth: %w", err)
|
return nil, nhttp.NewError("Failed to get oauth: %w", err)
|
||||||
}
|
}
|
||||||
data := contentSettingIntegration{
|
data := contentSettingIntegration{
|
||||||
ArcGISOAuth: oauth,
|
ArcGISOAuth: oauth,
|
||||||
}
|
}
|
||||||
return newResponse("sync/configuration/integration-arcgis.html", data), nil
|
return html.NewResponse("sync/configuration/integration-arcgis.html", data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentSettingPlaceholder struct{}
|
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{}
|
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{}
|
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{}
|
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{}
|
content := contentSettingPlaceholder{}
|
||||||
return newResponse("sync/configuration/user-list.html", content), nil
|
return html.NewResponse("sync/configuration/user-list.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
45
sync/dash.go
45
sync/dash.go
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/html"
|
"github.com/Gleipnir-Technology/nidus-sync/html"
|
||||||
|
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
@ -61,8 +62,8 @@ func getDistrict(w http.ResponseWriter, r *http.Request) {
|
||||||
html.RenderOrError(w, "sync/district.html", &context)
|
html.RenderOrError(w, "sync/district.html", &context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLayoutTest(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentLayoutTest], *errorWithStatus) {
|
func getLayoutTest(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentLayoutTest], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/layout-test.html", contentLayoutTest{}), nil
|
return html.NewResponse("sync/layout-test.html", contentLayoutTest{}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRoot(w http.ResponseWriter, r *http.Request) {
|
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")
|
globalid_s := chi.URLParam(r, "globalid")
|
||||||
if globalid_s == "" {
|
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)
|
globalid, err := uuid.Parse(globalid_s)
|
||||||
if err != nil {
|
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)
|
userContent, err := contentForUser(r.Context(), user)
|
||||||
if err != nil {
|
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)
|
s, err := sourceByGlobalId(r.Context(), org, globalid)
|
||||||
if err != nil {
|
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)
|
inspections, err := inspectionsBySource(r.Context(), org, globalid)
|
||||||
if err != nil {
|
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)
|
traps, err := trapsBySource(r.Context(), org, globalid)
|
||||||
if err != nil {
|
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)
|
treatments, err := treatmentsBySource(r.Context(), org, globalid)
|
||||||
if err != nil {
|
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)
|
treatment_models := modelTreatment(treatments)
|
||||||
latlng, err := s.H3Cell.LatLng()
|
latlng, err := s.H3Cell.LatLng()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Failed to get latlng: %w", err)
|
return nil, nhttp.NewError("Failed to get latlng: %w", err)
|
||||||
}
|
}
|
||||||
data := contentSource{
|
data := contentSource{
|
||||||
Inspections: inspections,
|
Inspections: inspections,
|
||||||
|
|
@ -148,40 +149,40 @@ func getSource(ctx context.Context, r *http.Request, org *models.Organization, u
|
||||||
User: userContent,
|
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{
|
data := contentDashboard{
|
||||||
MapData: ComponentMap{
|
MapData: ComponentMap{
|
||||||
MapboxToken: config.MapboxToken,
|
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) {
|
func getTemplateTest(w http.ResponseWriter, r *http.Request) {
|
||||||
html.RenderOrError(w, "sync/template-test.html", nil)
|
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")
|
globalid_s := chi.URLParam(r, "globalid")
|
||||||
if globalid_s == "" {
|
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)
|
globalid, err := uuid.Parse(globalid_s)
|
||||||
if err != nil {
|
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)
|
userContent, err := contentForUser(r.Context(), user)
|
||||||
if err != nil {
|
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)
|
t, err := trapByGlobalId(r.Context(), org, globalid)
|
||||||
if err != nil {
|
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()
|
latlng, err := t.H3Cell.LatLng()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Failed to get latlng: %w", err)
|
return nil, nhttp.NewError("Failed to get latlng: %w", err)
|
||||||
}
|
}
|
||||||
data := contentTrap{
|
data := contentTrap{
|
||||||
MapData: ComponentMap{
|
MapData: ComponentMap{
|
||||||
|
|
@ -198,7 +199,7 @@ func getTrap(ctx context.Context, r *http.Request, org *models.Organization, use
|
||||||
Trap: t,
|
Trap: t,
|
||||||
User: userContent,
|
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) {
|
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]{
|
html.RenderOrError(w, "sync/dashboard.html", contentAuthenticated[contentDashboard]{
|
||||||
C: content,
|
C: content,
|
||||||
URL: newContentURL(),
|
URL: html.NewContentURL(),
|
||||||
User: userContent,
|
User: userContent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
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{}
|
content := contentDownloadPlaceholder{}
|
||||||
return newResponse("sync/download-list.html", content), nil
|
return html.NewResponse("sync/download-list.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
119
sync/handler.go
Normal file
119
sync/handler.go
Normal file
|
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentIntelligenceRoot struct{}
|
||||||
|
|
||||||
func getIntelligenceRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentIntelligenceRoot], *errorWithStatus) {
|
func getIntelligenceRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentIntelligenceRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/intelligence-root.html", contentIntelligenceRoot{}), nil
|
return html.NewResponse("sync/intelligence-root.html", contentIntelligenceRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type contentMailer struct {
|
type contentMailer struct {
|
||||||
Config contentConfig
|
Config html.ContentConfig
|
||||||
DocumentID string
|
DocumentID string
|
||||||
LogoURL string
|
LogoURL string
|
||||||
Organization *models.Organization
|
Organization *models.Organization
|
||||||
|
|
@ -71,7 +71,7 @@ func getMailerPreview(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
doc_id := uuid.New()
|
doc_id := uuid.New()
|
||||||
html.RenderOrError(w, "sync/mailer.html", contentMailer{
|
html.RenderOrError(w, "sync/mailer.html", contentMailer{
|
||||||
Config: newContentConfig(),
|
Config: html.NewContentConfig(),
|
||||||
DocumentID: doc_id.String(),
|
DocumentID: doc_id.String(),
|
||||||
LogoURL: config.MakeURLNidus("/api/district/%s/logo", org.Slug.GetOr("unset")),
|
LogoURL: config.MakeURLNidus("/api/district/%s/logo", org.Slug.GetOr("unset")),
|
||||||
Organization: org,
|
Organization: org,
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
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{}
|
content := contentMessageList{}
|
||||||
return newResponse("sync/message-list.html", content), nil
|
return html.NewResponse("sync/message-list.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func addMock(r chi.Router, path string, template string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentMock struct {
|
type contentMock struct {
|
||||||
Config contentConfig
|
Config html.ContentConfig
|
||||||
DistrictName string
|
DistrictName string
|
||||||
URLs ContentMockURLs
|
URLs ContentMockURLs
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ func renderMock(template_name string) http.HandlerFunc {
|
||||||
code = "abc-123"
|
code = "abc-123"
|
||||||
}
|
}
|
||||||
data := contentMock{
|
data := contentMock{
|
||||||
Config: newContentConfig(),
|
Config: html.NewContentConfig(),
|
||||||
DistrictName: "Delta MVCD",
|
DistrictName: "Delta MVCD",
|
||||||
URLs: ContentMockURLs{
|
URLs: ContentMockURLs{
|
||||||
Dispatch: "/mock/dispatch",
|
Dispatch: "/mock/dispatch",
|
||||||
|
|
@ -91,13 +91,13 @@ func renderMock(template_name string) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentMockList struct {
|
type contentMockList struct {
|
||||||
Config contentConfig
|
Config html.ContentConfig
|
||||||
Mocks []mock
|
Mocks []mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderMockList(w http.ResponseWriter, r *http.Request) {
|
func renderMockList(w http.ResponseWriter, r *http.Request) {
|
||||||
data := contentMockList{
|
data := contentMockList{
|
||||||
Config: newContentConfig(),
|
Config: html.NewContentConfig(),
|
||||||
Mocks: mocks,
|
Mocks: mocks,
|
||||||
}
|
}
|
||||||
html.RenderOrError(w, "sync/mock/root.html", data)
|
html.RenderOrError(w, "sync/mock/root.html", data)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ import (
|
||||||
//"time"
|
//"time"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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/nidus-sync/notification"
|
||||||
//"github.com/Gleipnir-Technology/bob"
|
//"github.com/Gleipnir-Technology/bob"
|
||||||
//"github.com/Gleipnir-Technology/bob/dialect/psql"
|
//"github.com/Gleipnir-Technology/bob/dialect/psql"
|
||||||
|
|
@ -22,12 +24,12 @@ type contentNotificationList struct {
|
||||||
Notifications []notification.Notification
|
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)
|
notifications, err := notification.ForUser(ctx, u)
|
||||||
if err != nil {
|
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,
|
Notifications: notifications,
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/background"
|
"github.com/Gleipnir-Technology/nidus-sync/background"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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"
|
"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)
|
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{}
|
data := contentOauthPrompt{}
|
||||||
return newResponse("sync/oauth-prompt.html", data), nil
|
return html.NewResponse("sync/oauth-prompt.html", data), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentOperationsRoot struct{}
|
||||||
|
|
||||||
func getOperationsRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentOperationsRoot], *errorWithStatus) {
|
func getOperationsRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentOperationsRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/operations-root.html", contentOperationsRoot{}), nil
|
return html.NewResponse("sync/operations-root.html", contentOperationsRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentParcel struct{}
|
||||||
|
|
||||||
func getParcel(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentParcel], *errorWithStatus) {
|
func getParcel(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentParcel], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/parcel.html", contentParcel{}), nil
|
return html.NewResponse("sync/parcel.html", contentParcel{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentPlanningRoot struct{}
|
||||||
|
|
||||||
func getPlanningRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPlanningRoot], *errorWithStatus) {
|
func getPlanningRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPlanningRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/planning-root.html", contentPlanningRoot{}), nil
|
return html.NewResponse("sync/planning-root.html", contentPlanningRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
sync/pool.go
14
sync/pool.go
|
|
@ -5,16 +5,18 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentPoolList struct{}
|
||||||
|
|
||||||
func getPoolList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentPoolList], *errorWithStatus) {
|
func getPoolList(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/pool-list.html", contentPoolList{}), nil
|
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) {
|
func getPoolCreate(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/pool-upload.html", contentPoolList{}), nil
|
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) {
|
func getPoolByID(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentPoolList], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/pool-by-id.html", contentPoolList{}), nil
|
return html.NewResponse("sync/pool-by-id.html", contentPoolList{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,21 @@ import (
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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 {
|
type contentRadar struct {
|
||||||
Organization *models.Organization
|
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)
|
org, err := user.Organization().One(ctx, db.PGInstance.BobDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("get org: %w", err)
|
return nil, nhttp.NewError("get org: %w", err)
|
||||||
}
|
}
|
||||||
data := contentRadar{
|
data := contentRadar{
|
||||||
Organization: org,
|
Organization: org,
|
||||||
}
|
}
|
||||||
return newResponse("sync/radar.html", data), nil
|
return html.NewResponse("sync/radar.html", data), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
type contentReviewRoot struct{}
|
||||||
|
|
||||||
func getReviewRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*response[contentReviewRoot], *errorWithStatus) {
|
func getReviewRoot(ctx context.Context, r *http.Request, org *models.Organization, user *models.User) (*html.Response[contentReviewRoot], *nhttp.ErrorWithStatus) {
|
||||||
return newResponse("sync/review-root.html", contentReviewRoot{}), nil
|
return html.NewResponse("sync/review-root.html", contentReviewRoot{}), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
151
sync/routes.go
151
sync/routes.go
|
|
@ -1,17 +1,10 @@
|
||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/api"
|
"github.com/Gleipnir-Technology/nidus-sync/api"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/auth"
|
"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/Gleipnir-Technology/nidus-sync/html"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Router() chi.Router {
|
func Router() chi.Router {
|
||||||
|
|
@ -98,147 +91,3 @@ func Router() chi.Router {
|
||||||
html.AddStaticRoute(r, "/static")
|
html.AddStaticRoute(r, "/static")
|
||||||
return r
|
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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 {
|
type contentActiveServiceRequest struct {
|
||||||
|
|
@ -32,11 +34,11 @@ type contentServiceRequestList struct {
|
||||||
ClosedRequests []contentClosedServiceRequest
|
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{}
|
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()
|
now := time.Now()
|
||||||
content := contentServiceRequestList{
|
content := contentServiceRequestList{
|
||||||
ActiveRequests: []contentActiveServiceRequest{
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ func postSignup(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
type contentUnauthenticated[T any] struct {
|
type contentUnauthenticated[T any] struct {
|
||||||
C T
|
C T
|
||||||
Config contentConfig
|
Config html.ContentConfig
|
||||||
URL contentURL
|
URL html.ContentURL
|
||||||
}
|
}
|
||||||
|
|
||||||
func signin(w http.ResponseWriter, errorCode string, next string) {
|
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",
|
InvalidCredentials: errorCode == "invalid-credentials",
|
||||||
Next: next,
|
Next: next,
|
||||||
},
|
},
|
||||||
Config: newContentConfig(),
|
Config: html.NewContentConfig(),
|
||||||
URL: newContentURL(),
|
URL: html.NewContentURL(),
|
||||||
}
|
}
|
||||||
html.RenderOrError(w, "sync/signin.html", data)
|
html.RenderOrError(w, "sync/signin.html", data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
sync/sudo.go
16
sync/sudo.go
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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/gorilla/schema"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
@ -19,9 +21,9 @@ type contentSudo struct {
|
||||||
ForwardEmailNidusAddress string
|
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 {
|
if user.Role != enums.UserroleRoot {
|
||||||
return nil, &errorWithStatus{
|
return nil, &nhttp.ErrorWithStatus{
|
||||||
Message: "You have to be a root user to access this",
|
Message: "You have to be a root user to access this",
|
||||||
Status: http.StatusForbidden,
|
Status: http.StatusForbidden,
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +32,7 @@ func getSudo(ctx context.Context, r *http.Request, org *models.Organization, use
|
||||||
ForwardEmailRMOAddress: config.ForwardEmailRMOAddress,
|
ForwardEmailRMOAddress: config.ForwardEmailRMOAddress,
|
||||||
ForwardEmailNidusAddress: config.ForwardEmailNidusAddress,
|
ForwardEmailNidusAddress: config.ForwardEmailNidusAddress,
|
||||||
}
|
}
|
||||||
return newResponse("sync/sudo.html", content), nil
|
return html.NewResponse("sync/sudo.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var decoder = schema.NewDecoder()
|
var decoder = schema.NewDecoder()
|
||||||
|
|
@ -42,9 +44,9 @@ type FormEmail struct {
|
||||||
To string `schema:"emailTo"`
|
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 {
|
if u.Role != enums.UserroleRoot {
|
||||||
return "", &errorWithStatus{
|
return "", &nhttp.ErrorWithStatus{
|
||||||
Message: "You must have sudo powers to do this",
|
Message: "You must have sudo powers to do this",
|
||||||
Status: http.StatusForbidden,
|
Status: http.StatusForbidden,
|
||||||
}
|
}
|
||||||
|
|
@ -71,9 +73,9 @@ type FormSMS struct {
|
||||||
Phone string `schema:"smsPhone"`
|
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 {
|
if u.Role != enums.UserroleRoot {
|
||||||
return "", &errorWithStatus{
|
return "", &nhttp.ErrorWithStatus{
|
||||||
Message: "You must have sudo powers to do this",
|
Message: "You must have sudo powers to do this",
|
||||||
Status: http.StatusForbidden,
|
Status: http.StatusForbidden,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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{}
|
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{}
|
content := contentTextMessages{}
|
||||||
return newResponse("sync/text-messages.html", content), nil
|
return html.NewResponse("sync/text-messages.html", content), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ import (
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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/platform"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/userfile"
|
"github.com/Gleipnir-Technology/nidus-sync/userfile"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/rs/zerolog/log"
|
//"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type contentUploadList struct {
|
type contentUploadList struct {
|
||||||
|
|
@ -19,11 +21,11 @@ type contentUploadList struct {
|
||||||
}
|
}
|
||||||
type contentUploadPlaceholder 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)
|
rows, err := platform.UploadSummaryList(ctx, org)
|
||||||
return newResponse("sync/upload-list.html", contentUploadList{
|
return html.NewResponse("sync/upload-list.html", contentUploadList{
|
||||||
RecentUploads: rows,
|
RecentUploads: rows,
|
||||||
}), newErrorMaybe("get upload list: %w", err)
|
}), nhttp.NewErrorMaybe("get upload list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentUploadDetail struct {
|
type contentUploadDetail struct {
|
||||||
|
|
@ -36,110 +38,108 @@ type contentUploadPoolList struct {
|
||||||
}
|
}
|
||||||
type contentUploadPool 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{}
|
data := contentUploadPool{}
|
||||||
return newResponse("sync/upload-csv-pool.html", data), nil
|
return html.NewResponse("sync/upload-csv-pool.html", data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type contentUploadPoolFlyoverCreate struct{}
|
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{}
|
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{}
|
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{}
|
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) {
|
func getUploadByID(ctx context.Context, r *http.Request, org *models.Organization, u *models.User) (*html.Response[contentUploadDetail], *nhttp.ErrorWithStatus) {
|
||||||
test := newContentURLUpload()
|
|
||||||
log.Info().Str("output", test.Discard(123)).Send()
|
|
||||||
file_id_str := chi.URLParam(r, "id")
|
file_id_str := chi.URLParam(r, "id")
|
||||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||||
if err != nil {
|
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_)
|
file_id := int32(file_id_)
|
||||||
detail, err := platform.GetUploadPoolDetail(ctx, u.OrganizationID, file_id)
|
detail, err := platform.GetUploadPoolDetail(ctx, u.OrganizationID, file_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Failed to get pool: %w", err)
|
return nil, nhttp.NewError("Failed to get pool: %w", err)
|
||||||
}
|
}
|
||||||
data := contentUploadDetail{
|
data := contentUploadDetail{
|
||||||
CSVFileID: file_id,
|
CSVFileID: file_id,
|
||||||
Organization: org,
|
Organization: org,
|
||||||
Upload: detail,
|
Upload: detail,
|
||||||
}
|
}
|
||||||
return newResponse("sync/upload-by-id.html", data), nil
|
return html.NewResponse("sync/upload-by-id.html", data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormUploadCommit struct{}
|
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_str := chi.URLParam(r, "id")
|
||||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||||
if err != nil {
|
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_))
|
err = platform.UploadCommit(ctx, org, int32(file_id_))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", newError("Failed to mark discarded: %w", err)
|
return "", nhttp.NewError("Failed to mark discarded: %w", err)
|
||||||
}
|
}
|
||||||
return "/configuration/upload", nil
|
return "/configuration/upload", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormUploadDiscard struct{}
|
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_str := chi.URLParam(r, "id")
|
||||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||||
if err != nil {
|
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_))
|
err = platform.UploadDiscard(ctx, org, int32(file_id_))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", newError("Failed to mark discarded: %w", err)
|
return "", nhttp.NewError("Failed to mark discarded: %w", err)
|
||||||
}
|
}
|
||||||
return "/configuration/upload", nil
|
return "/configuration/upload", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type FormUploadPool struct{}
|
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)
|
uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV)
|
||||||
if err != nil {
|
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 {
|
if len(uploads) == 0 {
|
||||||
return "", newErrorStatus(http.StatusBadRequest, "No upload found")
|
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
|
||||||
}
|
}
|
||||||
if len(uploads) != 1 {
|
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]
|
upload := uploads[0]
|
||||||
saved_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypeFlyover)
|
saved_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypeFlyover)
|
||||||
if err != nil {
|
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
|
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)
|
uploads, err := userfile.SaveFileUpload(r, "csvfile", userfile.CollectionCSV)
|
||||||
if err != nil {
|
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 {
|
if len(uploads) == 0 {
|
||||||
return "", newErrorStatus(http.StatusBadRequest, "No upload found")
|
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
|
||||||
}
|
}
|
||||||
if len(uploads) != 1 {
|
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]
|
upload := uploads[0]
|
||||||
pool_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypePoollist)
|
pool_upload, err := platform.NewUpload(r.Context(), u, upload, enums.FileuploadCsvtypePoollist)
|
||||||
if err != nil {
|
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
|
return fmt.Sprintf("/configuration/upload/%d", pool_upload.ID), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue