This in a pretty huge change. At a high level we're adding the concept of a 'contact' which is a person or organization that has zero or more contact methods (email, phone). This ended up cascading a number of changes, including critically to the publicreprt schema. In the end it seemed safer to get to the point where I'm confident we aren't using any of the old fields for storing reporter information (though I haven't deleted the columns yet) so I removed the code for defining those columns. At this point I think it's not possible for me to regenerate the bob schema due to the interdependencies between my various schemas, so the migration is well-and-truly happening.
262 lines
11 KiB
Go
262 lines
11 KiB
Go
package resource
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
|
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"
|
|
|
|
"github.com/aarondl/opt/omit"
|
|
"github.com/aarondl/opt/omitnull"
|
|
//"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/types"
|
|
"github.com/google/uuid"
|
|
"github.com/gorilla/mux"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func PublicReportCompliance(r *router) *complianceR {
|
|
return &complianceR{
|
|
router: r,
|
|
}
|
|
}
|
|
|
|
type complianceR struct {
|
|
router *router
|
|
}
|
|
|
|
type publicReportComplianceForm struct {
|
|
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"`
|
|
}
|
|
|
|
func (res *complianceR) ByID(ctx context.Context, r *http.Request, u platform.User, query QueryParams) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
|
return res.byID(ctx, r, false)
|
|
}
|
|
func (res *complianceR) ByIDPublic(ctx context.Context, r *http.Request, query QueryParams) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
|
return res.byID(ctx, r, true)
|
|
}
|
|
func (res *complianceR) Create(ctx context.Context, r *http.Request, n publicReportComplianceForm) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
|
if n.District.IsUnset() && n.MailerID.IsUnset() {
|
|
return nil, nhttp.NewBadRequest("You must provide a district_id or mailer_id")
|
|
}
|
|
user_agent := r.Header.Get("User-Agent")
|
|
err := platform.EnsureClient(ctx, n.ClientID, user_agent)
|
|
if err != nil {
|
|
return nil, nhttp.NewError("Failed to ensure client: %w", err)
|
|
}
|
|
setter_report := modelpublicreport.Report{
|
|
//AddressID: omitnull.From(...),
|
|
AddressGid: "",
|
|
AddressRaw: "",
|
|
ClientUUID: &n.ClientID,
|
|
Created: time.Now(),
|
|
//H3cell: omitnull.From(latlng.Cell.String()),
|
|
LatlngAccuracyType: modelpublicreport.Accuracytype_Browser,
|
|
LatlngAccuracyValue: float32(0.0),
|
|
//Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)),
|
|
Location: nil,
|
|
MapZoom: float32(0.0),
|
|
//OrganizationID: ,
|
|
//PublicID:
|
|
ReportType: modelpublicreport.Reporttype_Compliance,
|
|
Status: modelpublicreport.Reportstatustype_Reported,
|
|
}
|
|
setter_compliance := modelpublicreport.Compliance{
|
|
AccessInstructions: "",
|
|
AvailabilityNotes: "",
|
|
Comments: "",
|
|
GateCode: "",
|
|
HasDog: nil,
|
|
PermissionType: modelpublicreport.Permissionaccess_Unselected,
|
|
//ReportID omit.Val[int32]
|
|
WantsScheduled: nil,
|
|
}
|
|
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)
|
|
}
|
|
setter_report.PublicID = public_id
|
|
}
|
|
if n.MailerID.IsValue() {
|
|
public_id := n.MailerID.MustGet()
|
|
setter_report.PublicID = public_id
|
|
|
|
// 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)
|
|
}
|
|
|
|
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)
|
|
}
|
|
setter_report.AddressID = address.ID
|
|
setter_report.AddressGid = address.GID
|
|
}
|
|
report, err := platform.PublicReportComplianceCreate(ctx, setter_report, setter_compliance, org_id)
|
|
if err != nil {
|
|
return nil, nhttp.NewError("create compliance report: %w", err)
|
|
}
|
|
// Return a fully-fleshed-out report object, even though it's a bit more expensive
|
|
result, err := platform.PublicReportByIDCompliance(ctx, report.PublicID, true)
|
|
if err != nil {
|
|
return nil, nhttp.NewError("get report after creation: %w", err)
|
|
}
|
|
return res.complianceHydrate(result, true)
|
|
}
|
|
func (res *complianceR) Update(ctx context.Context, r *http.Request, prf publicReportComplianceForm) (*types.PublicReportCompliance, *nhttp.ErrorWithStatus) {
|
|
var err error
|
|
vars := mux.Vars(r)
|
|
public_id := vars["id"]
|
|
if public_id == "" {
|
|
return nil, nhttp.NewBadRequest("You must provide an ID")
|
|
}
|
|
report_updater := querypublicreport.NewReportUpdater()
|
|
//report_setter := models.PublicreportReportSetter{}
|
|
compliance_updater := querypublicreport.NewComplianceUpdater()
|
|
//compliance_setter := models.PublicreportComplianceSetter{}
|
|
var location *types.Location
|
|
if prf.Location.IsValue() {
|
|
l := prf.Location.MustGet()
|
|
location = &l
|
|
if location.Accuracy != nil {
|
|
//report_setter.LatlngAccuracyValue = omit.From(*location.Accuracy)
|
|
report_updater.Model.LatlngAccuracyValue = *location.Accuracy
|
|
report_updater.Set(tablepublicreport.Report.LatlngAccuracyValue)
|
|
}
|
|
}
|
|
var reporter *types.Contact
|
|
if prf.Reporter.IsValue() {
|
|
l := prf.Reporter.MustGet()
|
|
reporter = &l
|
|
}
|
|
var address *types.Address
|
|
if prf.Address.IsValue() {
|
|
a := prf.Address.MustGet()
|
|
address = &a
|
|
}
|
|
if prf.AccessInstructions.IsValue() {
|
|
//compliance_setter.AccessInstructions = prf.AccessInstructions
|
|
compliance_updater.Model.AccessInstructions = prf.AccessInstructions.MustGet()
|
|
compliance_updater.Set(tablepublicreport.Compliance.AccessInstructions)
|
|
}
|
|
if prf.AvailabilityNotes.IsValue() {
|
|
//compliance_setter.AvailabilityNotes = prf.AvailabilityNotes
|
|
compliance_updater.Model.AvailabilityNotes = prf.AvailabilityNotes.MustGet()
|
|
compliance_updater.Set(tablepublicreport.Compliance.AvailabilityNotes)
|
|
}
|
|
if prf.Comments.IsValue() {
|
|
//compliance_setter.Comments = prf.Comments
|
|
compliance_updater.Model.Comments = prf.Comments.MustGet()
|
|
compliance_updater.Set(tablepublicreport.Compliance.Comments)
|
|
}
|
|
if prf.GateCode.IsValue() {
|
|
//compliance_setter.GateCode = prf.GateCode
|
|
compliance_updater.Model.GateCode = prf.GateCode.MustGet()
|
|
compliance_updater.Set(tablepublicreport.Compliance.GateCode)
|
|
}
|
|
if prf.HasDog.IsValue() {
|
|
//compliance_setter.HasDog = prf.HasDog
|
|
has_dog := prf.HasDog.MustGet()
|
|
compliance_updater.Model.HasDog = &has_dog
|
|
compliance_updater.Set(tablepublicreport.Compliance.HasDog)
|
|
}
|
|
if prf.PermissionType.IsValue() {
|
|
//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)
|
|
}
|
|
if prf.WantsScheduled.IsValue() {
|
|
//compliance_setter.WantsScheduled = prf.WantsScheduled
|
|
wants_scheduled := prf.WantsScheduled.MustGet()
|
|
compliance_updater.Model.WantsScheduled = &wants_scheduled
|
|
compliance_updater.Set(tablepublicreport.Compliance.WantsScheduled)
|
|
}
|
|
if prf.Submitted.IsValue() {
|
|
log.Debug().Str("submitted", prf.Submitted.MustGet().String()).Msg("got submitted")
|
|
//compliance_setter.Submitted = omitnull.From(time.Now())
|
|
now := time.Now()
|
|
compliance_updater.Model.Submitted = &now
|
|
compliance_updater.Set(tablepublicreport.Compliance.Submitted)
|
|
}
|
|
err = platform.PublicReportUpdateCompliance(ctx, public_id, report_updater, compliance_updater, address, location, reporter)
|
|
if err != nil {
|
|
return nil, nhttp.NewError("platform update report compliance: %w", err)
|
|
}
|
|
// Return a fully-fleshed-out report object, even though it's a bit more expensive
|
|
report, err := platform.PublicReportByIDCompliance(ctx, public_id, true)
|
|
if err != nil {
|
|
return nil, nhttp.NewError("get report after update: %w", err)
|
|
}
|
|
return res.complianceHydrate(report, true)
|
|
}
|
|
|
|
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) {
|
|
if err := populateDistrictURI(&report.PublicReport, res.router); err != nil {
|
|
return nil, nhttp.NewError("populate district URI: %w", err)
|
|
}
|
|
if err := populateReportURI(&report.PublicReport, res.router, is_public); err != nil {
|
|
return nil, nhttp.NewError("populate report URI: %w", err)
|
|
}
|
|
for _, e := range report.Concerns {
|
|
if err := e.PopulateURL(res.router.router); err != nil {
|
|
return nil, nhttp.NewError("populate concern URL: %w", err)
|
|
}
|
|
}
|
|
return report, nil
|
|
}
|