diff --git a/api/address.go b/api/address.go new file mode 100644 index 00000000..3cfa61bc --- /dev/null +++ b/api/address.go @@ -0,0 +1,11 @@ +package api + +type Address struct { + Country string `db:"country" json:"country"` + Locality string `db:"locality" json:"locality"` + Number string `db:"number" json:"number"` + PostalCode string `db:"postal_code" json:"postal_code"` + Region string `db:"region" json:"region"` + Street string `db:"street" json:"street"` + Unit string `db:"unit" json:"unit"` +} diff --git a/api/communication.go b/api/communication.go new file mode 100644 index 00000000..e6cf9b1b --- /dev/null +++ b/api/communication.go @@ -0,0 +1,118 @@ +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/config" + "github.com/Gleipnir-Technology/nidus-sync/db" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + nhttp "github.com/Gleipnir-Technology/nidus-sync/http" + "github.com/google/uuid" + //"github.com/Gleipnir-Technology/nidus-sync/platform" + //"github.com/aarondl/opt/null" + "github.com/stephenafamo/scan" +) + +type reporter struct { + HasEmail bool `json:"has_email"` + HasPhone bool `json:"has_phone"` + Name string `json:"name"` +} +type publicReport struct { + Address Address `json:"address"` + Images []string `json:"images"` + Reporter reporter `json:"reporter"` +} +type communication struct { + Created time.Time `json:"created"` + ID string `json:"id"` + PublicReport publicReport `json:"public_report"` + Type string `json:"type"` +} +type contentListCommunication struct { + Communications []communication `json:"communications"` +} + +func listCommunication(ctx context.Context, r *http.Request, org *models.Organization, user *models.User, query queryParams) (*contentListCommunication, *nhttp.ErrorWithStatus) { + reports, err := models.PublicreportNuisances.Query( + models.SelectWhere.PublicreportNuisances.OrganizationID.EQ(org.ID), + ).All(ctx, db.PGInstance.BobDB) + if err != nil { + return nil, nhttp.NewError("get reports: %w") + } + type _Row struct { + PublicID string `db:"nuisance_public_id"` + StorageUUID uuid.UUID `db:"storage_uuid"` + } + rows, err := bob.All(ctx, db.PGInstance.BobDB, psql.Select( + sm.Columns( + "n.public_id AS nuisance_public_id", + "i.storage_uuid AS storage_uuid", + ), + sm.From("publicreport.nuisance").As("n"), + sm.InnerJoin("publicreport.nuisance_image").As("ni").OnEQ( + psql.Quote("n", "id"), + psql.Quote("ni", "nuisance_id"), + ), + sm.InnerJoin("publicreport.image").As("i").OnEQ( + psql.Quote("ni", "image_id"), + psql.Quote("i", "id"), + ), + sm.Where(psql.Quote("n", "organization_id").EQ(psql.Arg(org.ID))), + ), scan.StructMapper[_Row]()) + if err != nil { + return nil, nhttp.NewError("get images: %w") + } + id_to_images := make(map[string][]uuid.UUID, len(reports)) + for _, row := range rows { + r, ok := id_to_images[row.PublicID] + if !ok { + r = make([]uuid.UUID, 0) + } + r = append(r, row.StorageUUID) + id_to_images[row.PublicID] = r + } + comms := make([]communication, len(reports)) + for i, report := range reports { + comms[i] = communication{ + PublicReport: publicReport{ + Address: Address{ + Country: report.AddressCountry, + Locality: report.AddressPlace, + //Number: report.Address + PostalCode: report.AddressPostcode, + Region: report.AddressRegion, + Street: report.AddressStreet, + }, + Images: toImageURLs(id_to_images, report.PublicID), + Reporter: reporter{ + Name: report.ReporterName.GetOr(""), + HasEmail: report.ReporterEmail.IsValue(), + HasPhone: report.ReporterPhone.IsValue(), + }, + }, + Created: report.Created, + ID: report.PublicID, + } + } + 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 _, u := range uuids { + urls = append(urls, config.MakeURLNidus("/api/image/%s", u.String())) + } + return urls +} diff --git a/api/handler.go b/api/handler.go index d3e933e5..451d60af 100644 --- a/api/handler.go +++ b/api/handler.go @@ -22,6 +22,7 @@ var decoder = schema.NewDecoder() type queryParams struct { Limit *int `schema:"limit"` Sort *string `schema:"sort"` + Type *string `schema:"type"` } type handlerFunctionGet[T any] func(context.Context, *http.Request, *models.Organization, *models.User, queryParams) (*T, *nhttp.ErrorWithStatus) diff --git a/api/routes.go b/api/routes.go index 6740b389..b0ed5c18 100644 --- a/api/routes.go +++ b/api/routes.go @@ -10,6 +10,7 @@ import ( func AddRoutes(r chi.Router) { // Authenticated endpoints r.Use(render.SetContentType(render.ContentTypeJSON)) + r.Method("GET", "/communication", authenticatedHandlerJSON(listCommunication)) r.Method("GET", "/mosquito-source", auth.NewEnsureAuth(apiMosquitoSource)) r.Method("GET", "/review-task/pool", authenticatedHandlerJSON(listReviewTaskPool)) r.Method("GET", "/service-request", auth.NewEnsureAuth(apiServiceRequest)) diff --git a/api/signal.go b/api/signal.go index 7a665803..343a81a0 100644 --- a/api/signal.go +++ b/api/signal.go @@ -16,15 +16,6 @@ import ( "github.com/stephenafamo/scan" ) -type Address struct { - Country string `db:"country" json:"country"` - Locality string `db:"locality" json:"locality"` - Number string `db:"number" json:"number"` - PostalCode string `db:"postal_code" json:"postal_code"` - Region string `db:"region" json:"region"` - Street string `db:"street" json:"street"` - Unit string `db:"unit" json:"unit"` -} type signal struct { Address Address `json:"address"` Addressed *time.Time `json:"addressed"` diff --git a/html/template/sync/communication-root.html b/html/template/sync/communication-root.html index a7163305..faa3e3da 100644 --- a/html/template/sync/communication-root.html +++ b/html/template/sync/communication-root.html @@ -14,72 +14,18 @@ function onLoad() {} window.addEventListener("load", onLoad); -