2026-04-09 23:38:20 +00:00
|
|
|
package resource
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"net/http"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
2026-05-07 10:39:17 +00:00
|
|
|
modelpublicreport "github.com/Gleipnir-Technology/nidus-sync/db/gen/nidus-sync/publicreport/model"
|
|
|
|
|
tablepublicreport "github.com/Gleipnir-Technology/nidus-sync/db/gen/nidus-sync/publicreport/table"
|
|
|
|
|
querypublicreport "github.com/Gleipnir-Technology/nidus-sync/db/query/publicreport"
|
|
|
|
|
|
2026-04-10 16:59:29 +00:00
|
|
|
"github.com/aarondl/opt/omit"
|
|
|
|
|
"github.com/aarondl/opt/omitnull"
|
|
|
|
|
//"github.com/Gleipnir-Technology/nidus-sync/html"
|
2026-04-09 23:38:20 +00:00
|
|
|
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
|
|
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/platform"
|
2026-04-12 18:33:41 +00:00
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/platform/types"
|
2026-04-14 14:38:22 +00:00
|
|
|
"github.com/google/uuid"
|
2026-04-12 18:33:41 +00:00
|
|
|
"github.com/gorilla/mux"
|
2026-04-13 20:42:03 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
2026-04-09 23:38:20 +00:00
|
|
|
)
|
|
|
|
|
|
2026-04-16 10:15:28 +00:00
|
|
|
func PublicReportCompliance(r *router) *complianceR {
|
2026-04-09 23:38:20 +00:00
|
|
|
return &complianceR{
|
|
|
|
|
router: r,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type complianceR struct {
|
|
|
|
|
router *router
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-01 21:27:17 +00:00
|
|
|
type publicReportComplianceForm struct {
|
2026-05-07 10:39:17 +00:00
|
|
|
AccessInstructions omit.Val[string] `schema:"access_instructions" json:"access_instructions"`
|
|
|
|
|
Address omit.Val[types.Address] `schema:"address" json:"address"`
|
|
|
|
|
AvailabilityNotes omit.Val[string] `schema:"availability_notes" json:"availability_notes"`
|
|
|
|
|
ClientID uuid.UUID `schema:"client_id" json:"client_id"`
|
|
|
|
|
Comments omit.Val[string] `schema:"comments" json:"comments"`
|
|
|
|
|
District omit.Val[string] `schema:"district" json:"district"`
|
|
|
|
|
GateCode omit.Val[string] `schema:"gate_code" json:"gate_code"`
|
|
|
|
|
HasDog omitnull.Val[bool] `schema:"has_dog" json:"has_dog"`
|
|
|
|
|
Location omit.Val[types.Location] `schema:"location" json:"location"`
|
|
|
|
|
MailerID omit.Val[string] `schema:"mailer_id" json:"mailer_id"`
|
|
|
|
|
PermissionType omit.Val[enums.PublicreportPermissionaccess] `schema:"permission_type" json:"permission_type"`
|
|
|
|
|
Reporter omit.Val[types.Contact] `schema:"reporter" json:"reporter"`
|
|
|
|
|
ReportPhoneCanSMS omitnull.Val[bool] `schema:"report_phone_can_text" json:"report_phone_can_text"`
|
|
|
|
|
Submitted omitnull.Val[time.Time] `schema:"submitted" json:"submitted"`
|
|
|
|
|
WantsScheduled omitnull.Val[bool] `schema:"wants_scheduled" json:"wants_scheduled"`
|
2026-04-20 16:21:08 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 06:36:55 +00:00
|
|
|
func (res *complianceR) ByID(ctx context.Context, r *http.Request, u platform.User, query QueryParams) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
2026-04-28 07:12:12 +00:00
|
|
|
return res.byID(ctx, r, false)
|
2026-04-28 06:36:55 +00:00
|
|
|
}
|
|
|
|
|
func (res *complianceR) ByIDPublic(ctx context.Context, r *http.Request, query QueryParams) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
2026-04-28 07:12:12 +00:00
|
|
|
return res.byID(ctx, r, true)
|
2026-04-12 18:33:41 +00:00
|
|
|
}
|
2026-05-01 21:27:17 +00:00
|
|
|
func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicReportComplianceForm) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
2026-04-22 19:54:06 +00:00
|
|
|
if n.District.IsUnset() && n.MailerID.IsUnset() {
|
|
|
|
|
return nil, nhttp.NewBadRequest("You must provide a district_id or mailer_id")
|
2026-04-20 16:21:08 +00:00
|
|
|
}
|
2026-04-14 14:38:22 +00:00
|
|
|
user_agent := r.Header.Get("User-Agent")
|
2026-04-22 21:22:33 +00:00
|
|
|
err := platform.EnsureClient(ctx, n.ClientID, user_agent)
|
2026-04-14 15:11:07 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("Failed to ensure client: %w", err)
|
|
|
|
|
}
|
2026-05-07 10:39:17 +00:00
|
|
|
setter_report := modelpublicreport.Report{
|
2026-04-22 21:22:33 +00:00
|
|
|
//AddressID: omitnull.From(...),
|
2026-05-07 10:39:17 +00:00
|
|
|
AddressGid: "",
|
|
|
|
|
AddressRaw: "",
|
|
|
|
|
ClientUUID: &n.ClientID,
|
|
|
|
|
Created: time.Now(),
|
2026-04-09 23:38:20 +00:00
|
|
|
//H3cell: omitnull.From(latlng.Cell.String()),
|
2026-05-07 10:39:17 +00:00
|
|
|
LatlngAccuracyType: modelpublicreport.Accuracytype_Browser,
|
|
|
|
|
LatlngAccuracyValue: float32(0.0),
|
2026-04-09 23:38:20 +00:00
|
|
|
//Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)),
|
2026-05-07 10:39:17 +00:00
|
|
|
Location: nil,
|
|
|
|
|
MapZoom: float32(0.0),
|
|
|
|
|
//OrganizationID: ,
|
|
|
|
|
//PublicID:
|
|
|
|
|
ReporterEmail: "",
|
|
|
|
|
ReporterName: "",
|
|
|
|
|
ReporterPhone: "",
|
|
|
|
|
ReporterPhoneCanSms: true,
|
|
|
|
|
ReportType: modelpublicreport.Reporttype_Compliance,
|
|
|
|
|
Status: modelpublicreport.Reportstatustype_Reported,
|
|
|
|
|
}
|
|
|
|
|
setter_compliance := modelpublicreport.Compliance{
|
|
|
|
|
AccessInstructions: "",
|
|
|
|
|
AvailabilityNotes: "",
|
|
|
|
|
Comments: "",
|
|
|
|
|
GateCode: "",
|
|
|
|
|
HasDog: nil,
|
|
|
|
|
PermissionType: modelpublicreport.Permissionaccess_Unselected,
|
2026-04-09 23:38:20 +00:00
|
|
|
//ReportID omit.Val[int32]
|
2026-05-07 10:39:17 +00:00
|
|
|
WantsScheduled: nil,
|
2026-04-09 23:38:20 +00:00
|
|
|
}
|
2026-04-22 21:22:33 +00:00
|
|
|
var org_id int32
|
|
|
|
|
if n.District.IsValue() {
|
|
|
|
|
district_str := n.District.MustGet()
|
|
|
|
|
var district_id_ptr *int
|
|
|
|
|
district_id_ptr, err := res.router.IDFromURI("district.ByIDGet", district_str)
|
|
|
|
|
if err != nil || district_id_ptr == nil {
|
|
|
|
|
return nil, nhttp.NewBadRequest("parse district ID: %w", err)
|
|
|
|
|
}
|
|
|
|
|
org_id = int32(*district_id_ptr)
|
|
|
|
|
public_id, err := platform.GenerateReportID()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("generate public ID: %w", err)
|
|
|
|
|
}
|
2026-05-07 10:39:17 +00:00
|
|
|
setter_report.PublicID = public_id
|
2026-04-22 21:22:33 +00:00
|
|
|
}
|
|
|
|
|
if n.MailerID.IsValue() {
|
|
|
|
|
public_id := n.MailerID.MustGet()
|
2026-05-07 10:39:17 +00:00
|
|
|
setter_report.PublicID = public_id
|
2026-04-22 21:22:33 +00:00
|
|
|
|
2026-04-29 19:30:43 +00:00
|
|
|
// If it already exists, just return it
|
|
|
|
|
report, err := platform.PublicReportByIDCompliance(ctx, public_id, true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("check existing report: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if report != nil {
|
|
|
|
|
return res.complianceHydrate(report, true)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 21:22:33 +00:00
|
|
|
org_id, err = platform.OrganizationIDForComplianceReportRequest(ctx, public_id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewBadRequest("no such mailer")
|
|
|
|
|
}
|
|
|
|
|
address, err := platform.AddressFromComplianceReportRequestID(ctx, public_id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("get address gid: %w", err)
|
|
|
|
|
}
|
2026-05-07 10:39:17 +00:00
|
|
|
setter_report.AddressID = address.ID
|
|
|
|
|
setter_report.AddressGid = address.GID
|
2026-04-22 21:22:33 +00:00
|
|
|
}
|
|
|
|
|
report, err := platform.PublicReportComplianceCreate(ctx, setter_report, setter_compliance, org_id)
|
2026-04-09 23:38:20 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("create compliance report: %w", err)
|
|
|
|
|
}
|
2026-04-21 15:01:01 +00:00
|
|
|
// Return a fully-fleshed-out report object, even though it's a bit more expensive
|
2026-04-28 06:36:55 +00:00
|
|
|
result, err := platform.PublicReportByIDCompliance(ctx, report.PublicID, true)
|
2026-04-09 23:38:20 +00:00
|
|
|
if err != nil {
|
2026-04-21 15:01:01 +00:00
|
|
|
return nil, nhttp.NewError("get report after creation: %w", err)
|
2026-04-09 23:38:20 +00:00
|
|
|
}
|
2026-04-28 07:12:12 +00:00
|
|
|
return res.complianceHydrate(result, true)
|
2026-04-09 23:38:20 +00:00
|
|
|
}
|
2026-05-01 21:27:17 +00:00
|
|
|
func (res *complianceR) Update(ctx context.Context, r *http.Request, prf publicReportComplianceForm) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
2026-05-07 10:39:17 +00:00
|
|
|
var err error
|
2026-04-13 19:32:22 +00:00
|
|
|
vars := mux.Vars(r)
|
|
|
|
|
public_id := vars["id"]
|
|
|
|
|
if public_id == "" {
|
|
|
|
|
return nil, nhttp.NewBadRequest("You must provide an ID")
|
|
|
|
|
}
|
2026-05-07 10:39:17 +00:00
|
|
|
report_updater := querypublicreport.ReportUpdater{}
|
|
|
|
|
//report_setter := models.PublicreportReportSetter{}
|
|
|
|
|
compliance_updater := querypublicreport.ComplianceUpdater{}
|
|
|
|
|
//compliance_setter := models.PublicreportComplianceSetter{}
|
2026-04-13 20:42:03 +00:00
|
|
|
var location *types.Location
|
|
|
|
|
if prf.Location.IsValue() {
|
|
|
|
|
l := prf.Location.MustGet()
|
|
|
|
|
location = &l
|
|
|
|
|
if location.Accuracy != nil {
|
2026-05-07 10:39:17 +00:00
|
|
|
//report_setter.LatlngAccuracyValue = omit.From(*location.Accuracy)
|
|
|
|
|
report_updater.Model.LatlngAccuracyValue = *location.Accuracy
|
|
|
|
|
report_updater.Set(tablepublicreport.Report.LatlngAccuracyValue)
|
2026-04-13 19:32:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
2026-04-13 20:42:03 +00:00
|
|
|
if prf.Reporter.IsValue() {
|
|
|
|
|
reporter := prf.Reporter.MustGet()
|
|
|
|
|
if reporter.Email != nil {
|
2026-05-07 10:39:17 +00:00
|
|
|
//report_setter.ReporterEmail = omit.From(*reporter.Email)
|
|
|
|
|
report_updater.Model.ReporterEmail = *reporter.Email
|
|
|
|
|
report_updater.Set(tablepublicreport.Report.ReporterEmail)
|
2026-04-13 19:32:22 +00:00
|
|
|
}
|
2026-04-13 20:42:03 +00:00
|
|
|
if reporter.Name != nil {
|
2026-05-07 10:39:17 +00:00
|
|
|
//report_setter.ReporterName = omit.From(*reporter.Name)
|
|
|
|
|
report_updater.Model.ReporterName = *reporter.Name
|
|
|
|
|
report_updater.Set(tablepublicreport.Report.ReporterName)
|
2026-04-13 19:32:22 +00:00
|
|
|
}
|
2026-04-13 20:42:03 +00:00
|
|
|
if reporter.Phone != nil {
|
2026-05-07 10:39:17 +00:00
|
|
|
//report_setter.ReporterPhone = omit.From(*reporter.Phone)
|
|
|
|
|
report_updater.Model.ReporterPhone = *reporter.Phone
|
|
|
|
|
report_updater.Set(tablepublicreport.Report.ReporterPhone)
|
2026-04-13 19:32:22 +00:00
|
|
|
}
|
2026-04-13 22:07:56 +00:00
|
|
|
if reporter.CanSMS != nil {
|
2026-05-07 10:39:17 +00:00
|
|
|
//report_setter.ReporterPhoneCanSMS = omit.FromPtr(reporter.CanSMS)
|
|
|
|
|
report_updater.Model.ReporterPhoneCanSms = *reporter.CanSMS
|
|
|
|
|
report_updater.Set(tablepublicreport.Report.ReporterPhoneCanSms)
|
2026-04-13 22:07:56 +00:00
|
|
|
}
|
2026-04-13 19:32:22 +00:00
|
|
|
}
|
2026-04-13 20:42:03 +00:00
|
|
|
var address *types.Address
|
|
|
|
|
if prf.Address.IsValue() {
|
|
|
|
|
a := prf.Address.MustGet()
|
|
|
|
|
address = &a
|
|
|
|
|
}
|
|
|
|
|
if prf.AccessInstructions.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.AccessInstructions = prf.AccessInstructions
|
|
|
|
|
compliance_updater.Model.AccessInstructions = prf.AccessInstructions.MustGet()
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.AccessInstructions)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.AvailabilityNotes.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.AvailabilityNotes = prf.AvailabilityNotes
|
|
|
|
|
compliance_updater.Model.AvailabilityNotes = prf.AvailabilityNotes.MustGet()
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.AvailabilityNotes)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.Comments.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.Comments = prf.Comments
|
|
|
|
|
compliance_updater.Model.Comments = prf.Comments.MustGet()
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.Comments)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.GateCode.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.GateCode = prf.GateCode
|
|
|
|
|
compliance_updater.Model.GateCode = prf.GateCode.MustGet()
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.GateCode)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.HasDog.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.HasDog = prf.HasDog
|
|
|
|
|
has_dog := prf.HasDog.MustGet()
|
|
|
|
|
compliance_updater.Model.HasDog = &has_dog
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.HasDog)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.PermissionType.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.PermissionType = prf.PermissionType
|
|
|
|
|
var perm_type modelpublicreport.Permissionaccess
|
|
|
|
|
pt := prf.PermissionType.MustGet()
|
|
|
|
|
err = perm_type.Scan(pt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewBadRequest("permission type %s can't be scanned: %w", pt, err)
|
|
|
|
|
}
|
|
|
|
|
compliance_updater.Model.PermissionType = perm_type
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.PermissionType)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
|
|
|
|
if prf.WantsScheduled.IsValue() {
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.WantsScheduled = prf.WantsScheduled
|
|
|
|
|
wants_scheduled := prf.WantsScheduled.MustGet()
|
|
|
|
|
compliance_updater.Model.WantsScheduled = &wants_scheduled
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.WantsScheduled)
|
2026-04-13 20:42:03 +00:00
|
|
|
}
|
2026-05-01 21:27:17 +00:00
|
|
|
if prf.Submitted.IsValue() {
|
|
|
|
|
log.Debug().Str("submitted", prf.Submitted.MustGet().String()).Msg("got submitted")
|
2026-05-07 10:39:17 +00:00
|
|
|
//compliance_setter.Submitted = omitnull.From(time.Now())
|
|
|
|
|
now := time.Now()
|
|
|
|
|
compliance_updater.Model.Submitted = &now
|
|
|
|
|
compliance_updater.Set(tablepublicreport.Compliance.Submitted)
|
2026-05-01 21:27:17 +00:00
|
|
|
}
|
2026-05-07 10:39:17 +00:00
|
|
|
err = platform.PublicReportUpdateCompliance(ctx, public_id, report_updater, compliance_updater, address, location)
|
2026-04-13 19:32:22 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("platform update report compliance: %w", err)
|
|
|
|
|
}
|
2026-04-14 02:38:36 +00:00
|
|
|
// Return a fully-fleshed-out report object, even though it's a bit more expensive
|
2026-05-07 10:39:17 +00:00
|
|
|
report, err := platform.PublicReportByIDCompliance(ctx, public_id, true)
|
2026-04-14 02:38:36 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("get report after update: %w", err)
|
|
|
|
|
}
|
2026-04-28 07:12:12 +00:00
|
|
|
return res.complianceHydrate(report, true)
|
2026-04-21 21:35:40 +00:00
|
|
|
}
|
2026-04-27 16:23:16 +00:00
|
|
|
|
2026-04-28 07:12:12 +00:00
|
|
|
func (res *complianceR) byID(ctx context.Context, r *http.Request, is_public bool) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
|
public_id := vars["id"]
|
|
|
|
|
if public_id == "" {
|
|
|
|
|
return nil, nhttp.NewBadRequest("You must provid an ID")
|
|
|
|
|
}
|
|
|
|
|
report, err := platform.PublicReportByIDCompliance(ctx, public_id, true)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, nhttp.NewError("get report: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return res.complianceHydrate(report, is_public)
|
|
|
|
|
}
|
|
|
|
|
func (res *complianceR) complianceHydrate(report *types.PublicReportCompliance, is_public bool) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
2026-04-21 21:35:40 +00:00
|
|
|
populateDistrictURI(&report.PublicReport, res.router)
|
2026-04-28 07:12:12 +00:00
|
|
|
populateReportURI(&report.PublicReport, res.router, is_public)
|
2026-04-22 21:22:03 +00:00
|
|
|
for _, e := range report.Concerns {
|
2026-04-21 21:35:40 +00:00
|
|
|
e.PopulateURL(res.router.router)
|
|
|
|
|
}
|
2026-04-13 19:32:22 +00:00
|
|
|
return report, nil
|
|
|
|
|
}
|