Move QueryParams to resource module
This commit is contained in:
parent
ab519020fc
commit
a656d45a6d
16 changed files with 641 additions and 583 deletions
|
|
@ -1,67 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/publicreport"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/types"
|
||||
"github.com/google/uuid"
|
||||
//"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type communication struct {
|
||||
Created time.Time `json:"created"`
|
||||
ID string `json:"id"`
|
||||
PublicReport types.PublicReport `json:"public_report"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type contentListCommunication struct {
|
||||
Communications []communication `json:"communications"`
|
||||
}
|
||||
|
||||
func listCommunication(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*contentListCommunication, *nhttp.ErrorWithStatus) {
|
||||
reports, err := publicreport.ReportsForOrganization(ctx, user.Organization.ID)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("nuisance report query: %w", err)
|
||||
}
|
||||
comms := make([]communication, len(reports))
|
||||
for i, report := range reports {
|
||||
comms[i] = communication{
|
||||
Created: report.Created,
|
||||
ID: report.PublicID,
|
||||
PublicReport: report,
|
||||
Type: "publicreport." + string(report.Type),
|
||||
}
|
||||
}
|
||||
_by_created := func(a, b communication) int {
|
||||
if a.Created == b.Created {
|
||||
return 0
|
||||
} else if a.Created.Before(b.Created) {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
slices.SortFunc(comms, _by_created)
|
||||
return &contentListCommunication{
|
||||
Communications: comms,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toImageURLs(m map[string][]uuid.UUID, id string) []string {
|
||||
uuids, ok := m[id]
|
||||
if !ok {
|
||||
return []string{}
|
||||
}
|
||||
urls := make([]string, len(uuids))
|
||||
for i, u := range uuids {
|
||||
urls[i] = config.MakeURLNidus("/api/image/%s/content", u.String())
|
||||
}
|
||||
return urls
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,14 @@ import (
|
|||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/file"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/resource"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var decoder = schema.NewDecoder()
|
||||
|
||||
type handlerFunctionGet[T any] func(context.Context, *http.Request, platform.User, queryParams) (*T, *nhttp.ErrorWithStatus)
|
||||
type handlerFunctionGet[T any] func(context.Context, *http.Request, platform.User, resource.QueryParams) (*T, *nhttp.ErrorWithStatus)
|
||||
type wrappedHandler func(http.ResponseWriter, *http.Request)
|
||||
type contentAuthenticated[T any] struct {
|
||||
C T
|
||||
|
|
@ -34,7 +35,7 @@ func authenticatedHandlerJSON[T any](f handlerFunctionGet[T]) http.Handler {
|
|||
return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u platform.User) {
|
||||
ctx := r.Context()
|
||||
var body []byte
|
||||
var params queryParams
|
||||
var params resource.QueryParams
|
||||
err := decoder.Decode(¶ms, r.URL.Query())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("decode query failure")
|
||||
|
|
|
|||
50
api/lead.go
50
api/lead.go
|
|
@ -1,51 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
)
|
||||
|
||||
type createLead struct {
|
||||
PoolLocations map[int]platform.Location `json:"pool_locations"`
|
||||
SignalIDs []int `json:"signal_ids"`
|
||||
}
|
||||
type contentListLead struct {
|
||||
Leads []lead `json:"leads"`
|
||||
}
|
||||
type lead struct {
|
||||
ID int32 `json:"id"`
|
||||
}
|
||||
|
||||
func listLead(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*contentListLead, *nhttp.ErrorWithStatus) {
|
||||
return &contentListLead{
|
||||
Leads: make([]lead, 0),
|
||||
}, nil
|
||||
}
|
||||
func postLeads(ctx context.Context, r *http.Request, user platform.User, req createLead) (string, *nhttp.ErrorWithStatus) {
|
||||
if len(req.SignalIDs) == 0 {
|
||||
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "can't make a lead with no signals")
|
||||
}
|
||||
if len(req.SignalIDs) > 1 {
|
||||
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "can't make a lead with multiple signals yet")
|
||||
}
|
||||
signal_id := req.SignalIDs[0]
|
||||
var pool_location *platform.Location
|
||||
l, ok := req.PoolLocations[signal_id]
|
||||
if ok {
|
||||
pool_location = &l
|
||||
}
|
||||
site_id, err := platform.SiteFromSignal(ctx, user, int32(signal_id))
|
||||
if err != nil || site_id == nil {
|
||||
return "", nhttp.NewError("site from signal: %w", err)
|
||||
}
|
||||
lead_id, err := platform.LeadCreate(ctx, user, int32(signal_id), *site_id, pool_location)
|
||||
if err != nil || lead_id == nil {
|
||||
return "", nhttp.NewError("lead create: %w", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("/lead/%d", *lead_id), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
package api
|
||||
|
||||
type queryParams struct {
|
||||
Limit *int `schema:"limit"`
|
||||
Query *string `schema:"query"`
|
||||
Sort *string `schema:"sort"`
|
||||
Type *string `schema:"type"`
|
||||
}
|
||||
|
||||
func (qp queryParams) SortOrDefault(default_name string, ascending bool) (string, bool) {
|
||||
if qp.Sort == nil {
|
||||
return default_name, ascending
|
||||
}
|
||||
s := *qp.Sort
|
||||
if s == "" {
|
||||
return default_name, ascending
|
||||
}
|
||||
a := true
|
||||
if s[0] == '-' {
|
||||
a = false
|
||||
}
|
||||
if s[0] == '+' || s[0] == '-' {
|
||||
s = s[1:]
|
||||
}
|
||||
return s, a
|
||||
}
|
||||
|
|
@ -1,15 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
//"encoding/json"
|
||||
)
|
||||
|
||||
type resource[T any] struct {
|
||||
inner *T
|
||||
}
|
||||
|
||||
func newResource[T any](inner *T) resource[T] {
|
||||
return resource[T]{
|
||||
inner: inner,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,153 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/types"
|
||||
//"github.com/aarondl/opt/null"
|
||||
"github.com/stephenafamo/scan"
|
||||
)
|
||||
|
||||
type reviewTask struct {
|
||||
Address types.Address `json:"address"`
|
||||
Created time.Time `json:"created"`
|
||||
Creator platform.User `json:"creator"`
|
||||
ID int32 `json:"id"`
|
||||
Location types.Location `json:"location"`
|
||||
Pool reviewTaskPool `json:"pool"`
|
||||
Reviewed *time.Time `json:"addressed"`
|
||||
Reviewer *platform.User `json:"addressor"`
|
||||
}
|
||||
type reviewTaskPool struct {
|
||||
Condition string `json:"condition"`
|
||||
Site types.Site `json:"site"`
|
||||
}
|
||||
type contentListReviewTask struct {
|
||||
Tasks []reviewTask `json:"tasks"`
|
||||
Total int32 `json:"total"`
|
||||
}
|
||||
|
||||
func listReviewTask(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*contentListReviewTask, *nhttp.ErrorWithStatus) {
|
||||
limit := 20
|
||||
if query.Limit != nil {
|
||||
limit = *query.Limit
|
||||
}
|
||||
type _RowTotal struct {
|
||||
Total int32 `db:"total"`
|
||||
}
|
||||
row_total, err := bob.One(ctx, db.PGInstance.BobDB, psql.Select(
|
||||
sm.Columns(
|
||||
"COUNT(*) AS total",
|
||||
),
|
||||
sm.From("review_task"),
|
||||
sm.Where(psql.Quote("review_task", "organization_id").EQ(psql.Arg(user.Organization.ID))),
|
||||
sm.Where(psql.Quote("review_task", "reviewed").IsNull()),
|
||||
), scan.StructMapper[_RowTotal]())
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("failed to total count: %w", err)
|
||||
}
|
||||
|
||||
type _Row struct {
|
||||
Address types.Address `db:"address"`
|
||||
Condition string `db:"condition"`
|
||||
Created time.Time `db:"created"`
|
||||
CreatorID int32 `db:"creator_id"`
|
||||
ID int32 `db:"id"`
|
||||
Latitude float64 `db:"latitude"`
|
||||
Longitude float64 `db:"longitude"`
|
||||
Reviewed *time.Time `db:"reviewed"`
|
||||
ReviewerID *int32 `db:"reviewer_id"`
|
||||
Species *string `db:"species"`
|
||||
Title string `db:"title"`
|
||||
Type string `db:"type"`
|
||||
}
|
||||
rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select(
|
||||
sm.Columns(
|
||||
"feature_pool.condition AS condition",
|
||||
"review_task.created AS created",
|
||||
"review_task.creator_id AS creator_id",
|
||||
"review_task.id AS id",
|
||||
"review_task.reviewed AS reviewed",
|
||||
"review_task.reviewer_id AS reviewer_id",
|
||||
"address.country AS \"address.country\"",
|
||||
"address.locality AS \"address.locality\"",
|
||||
"address.number_ AS \"address.number\"",
|
||||
"address.postal_code AS \"address.postal_code\"",
|
||||
"address.region AS \"address.region\"",
|
||||
"address.street AS \"address.street\"",
|
||||
"address.unit AS \"address.unit\"",
|
||||
"ST_Y(address.location) AS latitude",
|
||||
"ST_X(address.location) AS longitude",
|
||||
),
|
||||
sm.From("review_task_pool"),
|
||||
sm.InnerJoin("feature_pool").OnEQ(
|
||||
psql.Quote("review_task_pool", "feature_pool_id"),
|
||||
psql.Quote("feature_pool", "feature_id"),
|
||||
),
|
||||
sm.InnerJoin("review_task").OnEQ(
|
||||
psql.Quote("review_task_pool", "review_task_id"),
|
||||
psql.Quote("review_task", "id"),
|
||||
),
|
||||
sm.InnerJoin("feature").OnEQ(
|
||||
psql.Quote("feature_pool", "feature_id"),
|
||||
psql.Quote("feature", "id"),
|
||||
),
|
||||
sm.InnerJoin("site").On(
|
||||
psql.Quote("feature", "site_id").EQ(psql.Quote("site", "id")),
|
||||
),
|
||||
sm.InnerJoin("address").OnEQ(
|
||||
psql.Quote("site", "address_id"),
|
||||
psql.Quote("address", "id"),
|
||||
),
|
||||
sm.Where(psql.Quote("review_task", "organization_id").EQ(psql.Arg(user.Organization.ID))),
|
||||
sm.Where(psql.Quote("review_task", "reviewed").IsNull()),
|
||||
sm.Limit(limit),
|
||||
), scan.StructMapper[_Row]())
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("failed to get review tasks: %w", err)
|
||||
}
|
||||
users_by_id, err := platform.UsersByOrg(ctx, user.Organization)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("users by id: %w", err)
|
||||
}
|
||||
tasks := make([]reviewTask, len(rows))
|
||||
for i, row := range rows {
|
||||
tasks[i] = reviewTask{
|
||||
Address: row.Address,
|
||||
Created: row.Created,
|
||||
Creator: *users_by_id[row.CreatorID],
|
||||
ID: row.ID,
|
||||
Location: types.Location{
|
||||
Latitude: row.Latitude,
|
||||
Longitude: row.Longitude,
|
||||
},
|
||||
Pool: reviewTaskPool{
|
||||
Condition: row.Condition,
|
||||
},
|
||||
Reviewed: row.Reviewed,
|
||||
Reviewer: userOrNil(users_by_id, row.ReviewerID),
|
||||
}
|
||||
}
|
||||
return &contentListReviewTask{
|
||||
Tasks: tasks,
|
||||
Total: row_total.Total,
|
||||
}, nil
|
||||
}
|
||||
func userOrNil(usersByID map[int32]*platform.User, id *int32) *platform.User {
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
u, ok := usersByID[*id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package api
|
|||
import (
|
||||
"github.com/Gleipnir-Technology/nidus-sync/auth"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform/file"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/resource"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
|
@ -16,37 +17,45 @@ func AddRoutes(r *mux.Router) {
|
|||
r.Handle("/audio/{uuid}/content", auth.NewEnsureAuth(apiAudioContentPost)).Methods("POST")
|
||||
r.Handle("/avatar", authenticatedHandlerPostMultipart(avatarPost, file.CollectionAvatar)).Methods("POST")
|
||||
r.Handle("/client/ios", auth.NewEnsureAuth(handleClientIos)).Methods("GET")
|
||||
r.Handle("/communication", authenticatedHandlerJSON(listCommunication)).Methods("GET")
|
||||
communication := resource.Communication(r)
|
||||
r.Handle("/communication", authenticatedHandlerJSON(communication.List)).Methods("GET")
|
||||
r.Handle("/configuration/integration/arcgis", authenticatedHandlerJSONPost(postConfigurationIntegrationArcgis)).Methods("POST")
|
||||
r.Handle("/events", auth.NewEnsureAuth(streamEvents)).Methods("GET")
|
||||
r.Handle("/image/{uuid}", auth.NewEnsureAuth(apiImagePost)).Methods("POST")
|
||||
r.Handle("/image/{uuid}/content", auth.NewEnsureAuth(apiImageContentGet)).Methods("GET")
|
||||
r.Handle("/image/{uuid}/content", auth.NewEnsureAuth(apiImageContentPost)).Methods("POST")
|
||||
r.Handle("/leads", authenticatedHandlerJSON(listLead)).Methods("GET")
|
||||
r.Handle("/leads", authenticatedHandlerJSONPost(postLeads)).Methods("POST")
|
||||
lead := resource.Lead(r)
|
||||
r.Handle("/leads", authenticatedHandlerJSON(lead.List)).Methods("GET")
|
||||
r.Handle("/leads", authenticatedHandlerJSONPost(lead.Create)).Methods("POST")
|
||||
r.Handle("/mosquito-source", auth.NewEnsureAuth(apiMosquitoSource)).Methods("GET")
|
||||
r.Handle("/publicreport/invalid", authenticatedHandlerJSONPost(postPublicreportInvalid)).Methods("POST")
|
||||
r.Handle("/publicreport/signal", authenticatedHandlerJSONPost(postPublicreportSignal)).Methods("POST")
|
||||
r.Handle("/publicreport/message", authenticatedHandlerJSONPost(postPublicreportMessage)).Methods("POST")
|
||||
r.Handle("/review/pool", authenticatedHandlerJSONPost(postReviewPool)).Methods("POST")
|
||||
r.Handle("/review-task", authenticatedHandlerJSON(listReviewTask)).Methods("GET")
|
||||
review_task := resource.ReviewTask(r)
|
||||
r.Handle("/review-task", authenticatedHandlerJSON(review_task.List)).Methods("GET")
|
||||
r.Handle("/service-request", auth.NewEnsureAuth(apiServiceRequest)).Methods("GET")
|
||||
r.Handle("/signal", authenticatedHandlerJSON(listSignal)).Methods("GET")
|
||||
signal := resource.Signal(r)
|
||||
r.Handle("/signal", authenticatedHandlerJSON(signal.List)).Methods("GET")
|
||||
r.Handle("/sudo/email", authenticatedHandlerJSONPost(postSudoEmail)).Methods("POST")
|
||||
r.Handle("/sudo/sms", authenticatedHandlerJSONPost(postSudoSMS)).Methods("POST")
|
||||
r.Handle("/sudo/sse", authenticatedHandlerJSONPost(postSudoSSE)).Methods("POST")
|
||||
r.Handle("/trap-data", auth.NewEnsureAuth(apiTrapData)).Methods("GET")
|
||||
r.Handle("/tile/{z}/{y}/{x}", auth.NewEnsureAuth(getTile)).Methods("GET")
|
||||
r.Handle("/upload/pool/flyover", authenticatedHandlerPostMultipart(postUploadPoolFlyoverCreate, file.CollectionCSV)).Methods("POST")
|
||||
r.Handle("/upload/pool/custom", authenticatedHandlerPostMultipart(postUploadPoolCustomCreate, file.CollectionCSV)).Methods("POST")
|
||||
r.Handle("/upload", authenticatedHandlerJSON(getUploadList)).Methods("GET")
|
||||
r.Handle("/upload/{id}", authenticatedHandlerJSON(getUploadByID)).Methods("GET")
|
||||
r.Handle("/upload/{id}/commit", authenticatedHandlerJSONPost(postUploadCommit)).Methods("POST")
|
||||
r.Handle("/upload/{id}/discard", authenticatedHandlerJSONPost(postUploadDiscard)).Methods("POST")
|
||||
r.Handle("/user/self", authenticatedHandlerJSON(getUserSelf)).Methods("GET")
|
||||
r.Handle("/user/suggestion", authenticatedHandlerJSON(listUserSuggestion)).Methods("GET")
|
||||
r.Handle("/user", authenticatedHandlerJSON(listUser)).Methods("GET")
|
||||
r.Handle("/user/{id}", authenticatedHandlerJSONPut(userPut)).Methods("PUT")
|
||||
upload := resource.Upload(r)
|
||||
r.Handle("/upload/pool/flyover", authenticatedHandlerPostMultipart(upload.PoolFlyoverCreate, file.CollectionCSV)).Methods("POST")
|
||||
r.Handle("/upload/pool/custom", authenticatedHandlerPostMultipart(upload.PoolCustomCreate, file.CollectionCSV)).Methods("POST")
|
||||
r.Handle("/upload", authenticatedHandlerJSON(upload.List)).Methods("GET")
|
||||
r.Handle("/upload/{id}", authenticatedHandlerJSON(upload.ByIDGet)).Methods("GET")
|
||||
r.Handle("/upload/{id}/commit", authenticatedHandlerJSONPost(upload.Commit)).Methods("POST")
|
||||
r.Handle("/upload/{id}/discard", authenticatedHandlerJSONPost(upload.Discard)).Methods("POST")
|
||||
|
||||
user := resource.NewUser(r)
|
||||
r.Handle("/user/self", authenticatedHandlerJSON(user.SelfGet)).Methods("GET")
|
||||
r.Handle("/user/suggestion", authenticatedHandlerJSON(user.SuggestionGet)).Methods("GET")
|
||||
r.Handle("/user", authenticatedHandlerJSON(user.List)).Methods("GET")
|
||||
r.Handle("/user/{id}", authenticatedHandlerJSON(user.ByIDGet)).Methods("GET")
|
||||
r.Handle("/user/{id}", authenticatedHandlerJSONPut(user.ByIDPut)).Methods("PUT")
|
||||
|
||||
// Unauthenticated endpoints
|
||||
r.HandleFunc("/district", apiGetDistrict).Methods("GET")
|
||||
|
|
|
|||
|
|
@ -1,28 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
//"github.com/aarondl/opt/null"
|
||||
)
|
||||
|
||||
type contentListSignal struct {
|
||||
Signals []*platform.Signal `json:"signals"`
|
||||
}
|
||||
|
||||
func listSignal(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*contentListSignal, *nhttp.ErrorWithStatus) {
|
||||
limit := 20
|
||||
if query.Limit != nil {
|
||||
limit = *query.Limit
|
||||
}
|
||||
signals, err := platform.SignalList(ctx, user, limit)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("list signals: %w", err)
|
||||
}
|
||||
return &contentListSignal{
|
||||
Signals: signals,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
140
api/upload.go
140
api/upload.go
|
|
@ -1,141 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
"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/file"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func getUploadByID(ctx context.Context, r *http.Request, u platform.User, query queryParams) (*platform.Upload, *nhttp.ErrorWithStatus) {
|
||||
vars := mux.Vars(r)
|
||||
file_id_str := vars["id"]
|
||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("Failed to parse file_id: %w", err)
|
||||
}
|
||||
file_id := int32(file_id_)
|
||||
detail, err := platform.GetUploadDetail(ctx, u.Organization.ID, file_id)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("Failed to get pool: %w", err)
|
||||
}
|
||||
return detail, nil
|
||||
}
|
||||
|
||||
type contentUploadList struct {
|
||||
RecentUploads []platform.Upload
|
||||
}
|
||||
type contentUploadPlaceholder struct{}
|
||||
|
||||
func getUploadList(ctx context.Context, r *http.Request, user platform.User, req queryParams) (*contentUploadPoolList, *nhttp.ErrorWithStatus) {
|
||||
rows, err := platform.UploadList(ctx, user.Organization)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("Get upload list: %w", err)
|
||||
}
|
||||
return &contentUploadPoolList{
|
||||
Uploads: rows,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type contentUploadDetail struct {
|
||||
CSVFileID int32
|
||||
Organization platform.Organization
|
||||
Upload platform.Upload
|
||||
}
|
||||
type contentUploadPoolList struct {
|
||||
Uploads []platform.Upload `json:"uploads"`
|
||||
}
|
||||
type contentUploadPool struct{}
|
||||
|
||||
func getUploadPool(ctx context.Context, r *http.Request, u platform.User) (*html.Response[contentUploadPool], *nhttp.ErrorWithStatus) {
|
||||
data := contentUploadPool{}
|
||||
return html.NewResponse("sync/upload-csv-pool.html", data), nil
|
||||
}
|
||||
|
||||
type contentUploadPoolFlyoverCreate struct{}
|
||||
|
||||
func getUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, u platform.User) (*html.Response[contentUploadPoolFlyoverCreate], *nhttp.ErrorWithStatus) {
|
||||
data := contentUploadPoolFlyoverCreate{}
|
||||
return html.NewResponse("sync/upload-csv-pool-flyover.html", data), nil
|
||||
}
|
||||
|
||||
type contentUploadPoolCustomCreate struct{}
|
||||
|
||||
func getUploadPoolCustomCreate(ctx context.Context, r *http.Request, u platform.User) (*html.Response[contentUploadPoolCustomCreate], *nhttp.ErrorWithStatus) {
|
||||
data := contentUploadPoolCustomCreate{}
|
||||
return html.NewResponse("sync/upload-csv-pool-custom.html", data), nil
|
||||
}
|
||||
|
||||
type FormUploadCommit struct{}
|
||||
|
||||
func postUploadCommit(ctx context.Context, r *http.Request, u platform.User, f FormUploadCommit) (string, *nhttp.ErrorWithStatus) {
|
||||
vars := mux.Vars(r)
|
||||
file_id_str := vars["id"]
|
||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||
if err != nil {
|
||||
return "", nhttp.NewError("Failed to parse file_id: %w", err)
|
||||
}
|
||||
err = platform.UploadCommit(ctx, u.Organization, int32(file_id_), u)
|
||||
if err != nil {
|
||||
return "", nhttp.NewError("Failed to mark committed: %w", err)
|
||||
}
|
||||
log.Debug().Int64("file_id", file_id_).Int("user_id", u.ID).Msg("Committed file")
|
||||
return "/configuration/upload", nil
|
||||
}
|
||||
|
||||
type FormUploadDiscard struct{}
|
||||
|
||||
func postUploadDiscard(ctx context.Context, r *http.Request, u platform.User, f FormUploadDiscard) (string, *nhttp.ErrorWithStatus) {
|
||||
vars := mux.Vars(r)
|
||||
file_id_str := vars["id"]
|
||||
file_id_, err := strconv.ParseInt(file_id_str, 10, 32)
|
||||
if err != nil {
|
||||
return "", nhttp.NewError("Failed to parse file_id: %w", err)
|
||||
}
|
||||
err = platform.UploadDiscard(ctx, u.Organization, int32(file_id_))
|
||||
if err != nil {
|
||||
return "", nhttp.NewError("Failed to mark discarded: %w", err)
|
||||
}
|
||||
return "/configuration/upload", nil
|
||||
}
|
||||
|
||||
func postUploadPoolFlyoverCreate(ctx context.Context, r *http.Request, u platform.User, uploads []file.Upload) (string, *nhttp.ErrorWithStatus) {
|
||||
// If the organization we're uploading to doesn't have a service area, we can't process the upload correctly
|
||||
if !(u.Organization.HasServiceArea() || u.Organization.IsCatchall()) {
|
||||
return "", nhttp.NewErrorStatus(http.StatusConflict, "Your organization does not yet have a service area")
|
||||
}
|
||||
if len(uploads) == 0 {
|
||||
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
|
||||
}
|
||||
if len(uploads) != 1 {
|
||||
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 "", nhttp.NewError("Failed to create new pool: %w", err)
|
||||
}
|
||||
return fmt.Sprintf("/configuration/upload/%d", *saved_upload), nil
|
||||
}
|
||||
func postUploadPoolCustomCreate(ctx context.Context, r *http.Request, u platform.User, uploads []file.Upload) (string, *nhttp.ErrorWithStatus) {
|
||||
if len(uploads) == 0 {
|
||||
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
|
||||
}
|
||||
if len(uploads) != 1 {
|
||||
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 "", nhttp.NewError("Failed to create new pool: %w", err)
|
||||
}
|
||||
return fmt.Sprintf("/configuration/upload/%d", *pool_upload), nil
|
||||
}
|
||||
|
|
|
|||
114
api/user.go
114
api/user.go
|
|
@ -1,115 +1 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/html"
|
||||
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type contentURLAPI struct {
|
||||
Avatar string `json:"avatar"`
|
||||
Communication string `json:"communication"`
|
||||
PublicreportMessage string `json:"publicreport_message"`
|
||||
ReviewTask string `json:"review_task"`
|
||||
Signal string `json:"signal"`
|
||||
Upload string `json:"upload"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
type contentURLs struct {
|
||||
API contentURLAPI `json:"api"`
|
||||
Tegola string `json:"tegola"`
|
||||
Tile string `json:"tile"`
|
||||
}
|
||||
type contentUserSelf struct {
|
||||
Self platform.User `json:"self"`
|
||||
URLs contentURLs `json:"urls"`
|
||||
}
|
||||
|
||||
func getUserSelf(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*contentUserSelf, *nhttp.ErrorWithStatus) {
|
||||
counts, err := platform.NotificationCountsForUser(ctx, user)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("get notifications: %w", err)
|
||||
}
|
||||
org, err := platform.OrganizationByID(ctx, int(user.Organization.ID))
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("get org: %w", err)
|
||||
}
|
||||
user.Organization = *org
|
||||
user.NotificationCounts = *counts
|
||||
urls := html.NewContentURL()
|
||||
return &contentUserSelf{
|
||||
Self: user,
|
||||
URLs: contentURLs{
|
||||
API: contentURLAPI{
|
||||
Avatar: config.MakeURLNidus("/api/avatar"),
|
||||
Communication: urls.API.Communication,
|
||||
PublicreportMessage: urls.API.Publicreport.Message,
|
||||
ReviewTask: config.MakeURLNidus("/api/review-task"),
|
||||
Signal: config.MakeURLNidus("/api/signal"),
|
||||
Upload: config.MakeURLNidus("/api/upload"),
|
||||
User: config.MakeURLNidus("/api/user"),
|
||||
},
|
||||
Tegola: urls.Tegola,
|
||||
Tile: config.MakeURLNidus("/api/tile/{z}/{y}/{x}"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type responseListUser struct {
|
||||
Users []*platform.User `json:"users"`
|
||||
}
|
||||
|
||||
func listUser(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*responseListUser, *nhttp.ErrorWithStatus) {
|
||||
users, err := platform.UsersByOrg(ctx, user.Organization)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("list users: %w", err)
|
||||
}
|
||||
results := make([]*platform.User, len(users))
|
||||
i := 0
|
||||
for _, v := range users {
|
||||
results[i] = v
|
||||
i++
|
||||
}
|
||||
return &responseListUser{
|
||||
Users: results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type responseListUserSuggestion struct {
|
||||
Users []*platform.User `json:"users"`
|
||||
}
|
||||
|
||||
func listUserSuggestion(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*responseListUserSuggestion, *nhttp.ErrorWithStatus) {
|
||||
if query.Query == nil {
|
||||
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "you need to include a query")
|
||||
}
|
||||
users, err := platform.UserSuggestion(ctx, user, *query.Query)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("query suggestions: %w", err)
|
||||
}
|
||||
return &responseListUserSuggestion{
|
||||
Users: users,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func userPut(ctx context.Context, r *http.Request, user platform.User, updates platform.UserChangeRequest) (string, *nhttp.ErrorWithStatus) {
|
||||
log.Info().Str("avatar", updates.Avatar).Msg("doing updates")
|
||||
vars := mux.Vars(r)
|
||||
user_id_str := vars["id"]
|
||||
user_id, err := strconv.Atoi(user_id_str)
|
||||
if err != nil {
|
||||
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "user update: %w", err)
|
||||
}
|
||||
err = platform.UserUpdate(ctx, user, user_id, updates)
|
||||
if err != nil {
|
||||
return "", nhttp.NewError("user update: %w", err)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue