Finish green pool report submission
Also start the pattern of breaking out pool pages together in their own file. I think its easier to read this way.
This commit is contained in:
parent
9680fb6a68
commit
01ed2d6086
31 changed files with 5925 additions and 375 deletions
26
db/dberrors/publicreport.pool.bob.go
Normal file
26
db/dberrors/publicreport.pool.bob.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package dberrors
|
||||
|
||||
var PublicreportPoolErrors = &publicreportPoolErrors{
|
||||
ErrUniquePoolPkey: &UniqueConstraintError{
|
||||
schema: "publicreport",
|
||||
table: "pool",
|
||||
columns: []string{"id"},
|
||||
s: "pool_pkey",
|
||||
},
|
||||
|
||||
ErrUniquePoolPublicIdKey: &UniqueConstraintError{
|
||||
schema: "publicreport",
|
||||
table: "pool",
|
||||
columns: []string{"public_id"},
|
||||
s: "pool_public_id_key",
|
||||
},
|
||||
}
|
||||
|
||||
type publicreportPoolErrors struct {
|
||||
ErrUniquePoolPkey *UniqueConstraintError
|
||||
|
||||
ErrUniquePoolPublicIdKey *UniqueConstraintError
|
||||
}
|
||||
17
db/dberrors/publicreport.pool_photo.bob.go
Normal file
17
db/dberrors/publicreport.pool_photo.bob.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package dberrors
|
||||
|
||||
var PublicreportPoolPhotoErrors = &publicreportPoolPhotoErrors{
|
||||
ErrUniquePoolPhotoPkey: &UniqueConstraintError{
|
||||
schema: "publicreport",
|
||||
table: "pool_photo",
|
||||
columns: []string{"id"},
|
||||
s: "pool_photo_pkey",
|
||||
},
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoErrors struct {
|
||||
ErrUniquePoolPhotoPkey *UniqueConstraintError
|
||||
}
|
||||
402
db/dbinfo/publicreport.pool.bob.go
Normal file
402
db/dbinfo/publicreport.pool.bob.go
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package dbinfo
|
||||
|
||||
import "github.com/aarondl/opt/null"
|
||||
|
||||
var PublicreportPools = Table[
|
||||
publicreportPoolColumns,
|
||||
publicreportPoolIndexes,
|
||||
publicreportPoolForeignKeys,
|
||||
publicreportPoolUniques,
|
||||
publicreportPoolChecks,
|
||||
]{
|
||||
Schema: "publicreport",
|
||||
Name: "pool",
|
||||
Columns: publicreportPoolColumns{
|
||||
ID: column{
|
||||
Name: "id",
|
||||
DBType: "integer",
|
||||
Default: "nextval('publicreport.pool_id_seq'::regclass)",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessComments: column{
|
||||
Name: "access_comments",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessGate: column{
|
||||
Name: "access_gate",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessFence: column{
|
||||
Name: "access_fence",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessLocked: column{
|
||||
Name: "access_locked",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessDog: column{
|
||||
Name: "access_dog",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AccessOther: column{
|
||||
Name: "access_other",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Address: column{
|
||||
Name: "address",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AddressCountry: column{
|
||||
Name: "address_country",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AddressPostCode: column{
|
||||
Name: "address_post_code",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AddressPlace: column{
|
||||
Name: "address_place",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AddressStreet: column{
|
||||
Name: "address_street",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
AddressRegion: column{
|
||||
Name: "address_region",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Comments: column{
|
||||
Name: "comments",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Created: column{
|
||||
Name: "created",
|
||||
DBType: "timestamp without time zone",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
H3cell: column{
|
||||
Name: "h3cell",
|
||||
DBType: "h3index",
|
||||
Default: "NULL",
|
||||
Comment: "",
|
||||
Nullable: true,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
HasAdult: column{
|
||||
Name: "has_adult",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
HasLarvae: column{
|
||||
Name: "has_larvae",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
HasPupae: column{
|
||||
Name: "has_pupae",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Location: column{
|
||||
Name: "location",
|
||||
DBType: "geography",
|
||||
Default: "NULL",
|
||||
Comment: "",
|
||||
Nullable: true,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
MapZoom: column{
|
||||
Name: "map_zoom",
|
||||
DBType: "double precision",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
OwnerEmail: column{
|
||||
Name: "owner_email",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
OwnerName: column{
|
||||
Name: "owner_name",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
OwnerPhone: column{
|
||||
Name: "owner_phone",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
PublicID: column{
|
||||
Name: "public_id",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
ReporterEmail: column{
|
||||
Name: "reporter_email",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
ReporterName: column{
|
||||
Name: "reporter_name",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
ReporterPhone: column{
|
||||
Name: "reporter_phone",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Subscribe: column{
|
||||
Name: "subscribe",
|
||||
DBType: "boolean",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
},
|
||||
Indexes: publicreportPoolIndexes{
|
||||
PoolPkey: index{
|
||||
Type: "btree",
|
||||
Name: "pool_pkey",
|
||||
Columns: []indexColumn{
|
||||
{
|
||||
Name: "id",
|
||||
Desc: null.FromCond(false, true),
|
||||
IsExpression: false,
|
||||
},
|
||||
},
|
||||
Unique: true,
|
||||
Comment: "",
|
||||
NullsFirst: []bool{false},
|
||||
NullsDistinct: false,
|
||||
Where: "",
|
||||
Include: []string{},
|
||||
},
|
||||
PoolPublicIDKey: index{
|
||||
Type: "btree",
|
||||
Name: "pool_public_id_key",
|
||||
Columns: []indexColumn{
|
||||
{
|
||||
Name: "public_id",
|
||||
Desc: null.FromCond(false, true),
|
||||
IsExpression: false,
|
||||
},
|
||||
},
|
||||
Unique: true,
|
||||
Comment: "",
|
||||
NullsFirst: []bool{false},
|
||||
NullsDistinct: false,
|
||||
Where: "",
|
||||
Include: []string{},
|
||||
},
|
||||
},
|
||||
PrimaryKey: &constraint{
|
||||
Name: "pool_pkey",
|
||||
Columns: []string{"id"},
|
||||
Comment: "",
|
||||
},
|
||||
|
||||
Uniques: publicreportPoolUniques{
|
||||
PoolPublicIDKey: constraint{
|
||||
Name: "pool_public_id_key",
|
||||
Columns: []string{"public_id"},
|
||||
Comment: "",
|
||||
},
|
||||
},
|
||||
|
||||
Comment: "",
|
||||
}
|
||||
|
||||
type publicreportPoolColumns struct {
|
||||
ID column
|
||||
AccessComments column
|
||||
AccessGate column
|
||||
AccessFence column
|
||||
AccessLocked column
|
||||
AccessDog column
|
||||
AccessOther column
|
||||
Address column
|
||||
AddressCountry column
|
||||
AddressPostCode column
|
||||
AddressPlace column
|
||||
AddressStreet column
|
||||
AddressRegion column
|
||||
Comments column
|
||||
Created column
|
||||
H3cell column
|
||||
HasAdult column
|
||||
HasLarvae column
|
||||
HasPupae column
|
||||
Location column
|
||||
MapZoom column
|
||||
OwnerEmail column
|
||||
OwnerName column
|
||||
OwnerPhone column
|
||||
PublicID column
|
||||
ReporterEmail column
|
||||
ReporterName column
|
||||
ReporterPhone column
|
||||
Subscribe column
|
||||
}
|
||||
|
||||
func (c publicreportPoolColumns) AsSlice() []column {
|
||||
return []column{
|
||||
c.ID, c.AccessComments, c.AccessGate, c.AccessFence, c.AccessLocked, c.AccessDog, c.AccessOther, c.Address, c.AddressCountry, c.AddressPostCode, c.AddressPlace, c.AddressStreet, c.AddressRegion, c.Comments, c.Created, c.H3cell, c.HasAdult, c.HasLarvae, c.HasPupae, c.Location, c.MapZoom, c.OwnerEmail, c.OwnerName, c.OwnerPhone, c.PublicID, c.ReporterEmail, c.ReporterName, c.ReporterPhone, c.Subscribe,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolIndexes struct {
|
||||
PoolPkey index
|
||||
PoolPublicIDKey index
|
||||
}
|
||||
|
||||
func (i publicreportPoolIndexes) AsSlice() []index {
|
||||
return []index{
|
||||
i.PoolPkey, i.PoolPublicIDKey,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolForeignKeys struct{}
|
||||
|
||||
func (f publicreportPoolForeignKeys) AsSlice() []foreignKey {
|
||||
return []foreignKey{}
|
||||
}
|
||||
|
||||
type publicreportPoolUniques struct {
|
||||
PoolPublicIDKey constraint
|
||||
}
|
||||
|
||||
func (u publicreportPoolUniques) AsSlice() []constraint {
|
||||
return []constraint{
|
||||
u.PoolPublicIDKey,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolChecks struct{}
|
||||
|
||||
func (c publicreportPoolChecks) AsSlice() []check {
|
||||
return []check{}
|
||||
}
|
||||
147
db/dbinfo/publicreport.pool_photo.bob.go
Normal file
147
db/dbinfo/publicreport.pool_photo.bob.go
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package dbinfo
|
||||
|
||||
import "github.com/aarondl/opt/null"
|
||||
|
||||
var PublicreportPoolPhotos = Table[
|
||||
publicreportPoolPhotoColumns,
|
||||
publicreportPoolPhotoIndexes,
|
||||
publicreportPoolPhotoForeignKeys,
|
||||
publicreportPoolPhotoUniques,
|
||||
publicreportPoolPhotoChecks,
|
||||
]{
|
||||
Schema: "publicreport",
|
||||
Name: "pool_photo",
|
||||
Columns: publicreportPoolPhotoColumns{
|
||||
ID: column{
|
||||
Name: "id",
|
||||
DBType: "integer",
|
||||
Default: "nextval('publicreport.pool_photo_id_seq'::regclass)",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Size: column{
|
||||
Name: "size",
|
||||
DBType: "bigint",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
Filename: column{
|
||||
Name: "filename",
|
||||
DBType: "text",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
PoolID: column{
|
||||
Name: "pool_id",
|
||||
DBType: "integer",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
UUID: column{
|
||||
Name: "uuid",
|
||||
DBType: "uuid",
|
||||
Default: "",
|
||||
Comment: "",
|
||||
Nullable: false,
|
||||
Generated: false,
|
||||
AutoIncr: false,
|
||||
},
|
||||
},
|
||||
Indexes: publicreportPoolPhotoIndexes{
|
||||
PoolPhotoPkey: index{
|
||||
Type: "btree",
|
||||
Name: "pool_photo_pkey",
|
||||
Columns: []indexColumn{
|
||||
{
|
||||
Name: "id",
|
||||
Desc: null.FromCond(false, true),
|
||||
IsExpression: false,
|
||||
},
|
||||
},
|
||||
Unique: true,
|
||||
Comment: "",
|
||||
NullsFirst: []bool{false},
|
||||
NullsDistinct: false,
|
||||
Where: "",
|
||||
Include: []string{},
|
||||
},
|
||||
},
|
||||
PrimaryKey: &constraint{
|
||||
Name: "pool_photo_pkey",
|
||||
Columns: []string{"id"},
|
||||
Comment: "",
|
||||
},
|
||||
ForeignKeys: publicreportPoolPhotoForeignKeys{
|
||||
PublicreportPoolPhotoPoolPhotoPoolIDFkey: foreignKey{
|
||||
constraint: constraint{
|
||||
Name: "publicreport.pool_photo.pool_photo_pool_id_fkey",
|
||||
Columns: []string{"pool_id"},
|
||||
Comment: "",
|
||||
},
|
||||
ForeignTable: "publicreport.pool",
|
||||
ForeignColumns: []string{"id"},
|
||||
},
|
||||
},
|
||||
|
||||
Comment: "",
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoColumns struct {
|
||||
ID column
|
||||
Size column
|
||||
Filename column
|
||||
PoolID column
|
||||
UUID column
|
||||
}
|
||||
|
||||
func (c publicreportPoolPhotoColumns) AsSlice() []column {
|
||||
return []column{
|
||||
c.ID, c.Size, c.Filename, c.PoolID, c.UUID,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoIndexes struct {
|
||||
PoolPhotoPkey index
|
||||
}
|
||||
|
||||
func (i publicreportPoolPhotoIndexes) AsSlice() []index {
|
||||
return []index{
|
||||
i.PoolPhotoPkey,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoForeignKeys struct {
|
||||
PublicreportPoolPhotoPoolPhotoPoolIDFkey foreignKey
|
||||
}
|
||||
|
||||
func (f publicreportPoolPhotoForeignKeys) AsSlice() []foreignKey {
|
||||
return []foreignKey{
|
||||
f.PublicreportPoolPhotoPoolPhotoPoolIDFkey,
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoUniques struct{}
|
||||
|
||||
func (u publicreportPoolPhotoUniques) AsSlice() []constraint {
|
||||
return []constraint{}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoChecks struct{}
|
||||
|
||||
func (c publicreportPoolPhotoChecks) AsSlice() []check {
|
||||
return []check{}
|
||||
}
|
||||
|
|
@ -890,3 +890,88 @@ func (e *PublicreportNuisancepreferredtimetype) Scan(value any) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Enum values for PublicreportPoolsourceduration
|
||||
const (
|
||||
PublicreportPoolsourcedurationNone PublicreportPoolsourceduration = "none"
|
||||
PublicreportPoolsourcedurationLessThanWeek PublicreportPoolsourceduration = "less-than-week"
|
||||
PublicreportPoolsourceduration12Weeks PublicreportPoolsourceduration = "1-2-weeks"
|
||||
PublicreportPoolsourceduration24Weeks PublicreportPoolsourceduration = "2-4-weeks"
|
||||
PublicreportPoolsourceduration13Months PublicreportPoolsourceduration = "1-3-months"
|
||||
PublicreportPoolsourcedurationMoreThan3Months PublicreportPoolsourceduration = "more-than-3-months"
|
||||
)
|
||||
|
||||
func AllPublicreportPoolsourceduration() []PublicreportPoolsourceduration {
|
||||
return []PublicreportPoolsourceduration{
|
||||
PublicreportPoolsourcedurationNone,
|
||||
PublicreportPoolsourcedurationLessThanWeek,
|
||||
PublicreportPoolsourceduration12Weeks,
|
||||
PublicreportPoolsourceduration24Weeks,
|
||||
PublicreportPoolsourceduration13Months,
|
||||
PublicreportPoolsourcedurationMoreThan3Months,
|
||||
}
|
||||
}
|
||||
|
||||
type PublicreportPoolsourceduration string
|
||||
|
||||
func (e PublicreportPoolsourceduration) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e PublicreportPoolsourceduration) Valid() bool {
|
||||
switch e {
|
||||
case PublicreportPoolsourcedurationNone,
|
||||
PublicreportPoolsourcedurationLessThanWeek,
|
||||
PublicreportPoolsourceduration12Weeks,
|
||||
PublicreportPoolsourceduration24Weeks,
|
||||
PublicreportPoolsourceduration13Months,
|
||||
PublicreportPoolsourcedurationMoreThan3Months:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// useful when testing in other packages
|
||||
func (e PublicreportPoolsourceduration) All() []PublicreportPoolsourceduration {
|
||||
return AllPublicreportPoolsourceduration()
|
||||
}
|
||||
|
||||
func (e PublicreportPoolsourceduration) MarshalText() ([]byte, error) {
|
||||
return []byte(e), nil
|
||||
}
|
||||
|
||||
func (e *PublicreportPoolsourceduration) UnmarshalText(text []byte) error {
|
||||
return e.Scan(text)
|
||||
}
|
||||
|
||||
func (e PublicreportPoolsourceduration) MarshalBinary() ([]byte, error) {
|
||||
return []byte(e), nil
|
||||
}
|
||||
|
||||
func (e *PublicreportPoolsourceduration) UnmarshalBinary(data []byte) error {
|
||||
return e.Scan(data)
|
||||
}
|
||||
|
||||
func (e PublicreportPoolsourceduration) Value() (driver.Value, error) {
|
||||
return string(e), nil
|
||||
}
|
||||
|
||||
func (e *PublicreportPoolsourceduration) Scan(value any) error {
|
||||
switch x := value.(type) {
|
||||
case string:
|
||||
*e = PublicreportPoolsourceduration(x)
|
||||
case []byte:
|
||||
*e = PublicreportPoolsourceduration(x)
|
||||
case nil:
|
||||
return fmt.Errorf("cannot nil into PublicreportPoolsourceduration")
|
||||
default:
|
||||
return fmt.Errorf("cannot scan type %T: %v", value, value)
|
||||
}
|
||||
|
||||
if !e.Valid() {
|
||||
return fmt.Errorf("invalid PublicreportPoolsourceduration value: %s", *e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,14 @@ var (
|
|||
// Relationship Contexts for publicreport.nuisance
|
||||
publicreportNuisanceWithParentsCascadingCtx = newContextual[bool]("publicreportNuisanceWithParentsCascading")
|
||||
|
||||
// Relationship Contexts for publicreport.pool
|
||||
publicreportPoolWithParentsCascadingCtx = newContextual[bool]("publicreportPoolWithParentsCascading")
|
||||
publicreportPoolRelPoolPhotosCtx = newContextual[bool]("publicreport.pool.publicreport.pool_photo.publicreport.pool_photo.pool_photo_pool_id_fkey")
|
||||
|
||||
// Relationship Contexts for publicreport.pool_photo
|
||||
publicreportPoolPhotoWithParentsCascadingCtx = newContextual[bool]("publicreportPoolPhotoWithParentsCascading")
|
||||
publicreportPoolPhotoRelPoolCtx = newContextual[bool]("publicreport.pool.publicreport.pool_photo.publicreport.pool_photo.pool_photo_pool_id_fkey")
|
||||
|
||||
// Relationship Contexts for publicreport.quick
|
||||
publicreportQuickWithParentsCascadingCtx = newContextual[bool]("publicreportQuickWithParentsCascading")
|
||||
publicreportQuickRelQuickPhotosCtx = newContextual[bool]("publicreport.quick.publicreport.quick_photo.publicreport.quick_photo.quick_photo_quick_id_fkey")
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ type Factory struct {
|
|||
baseOauthTokenMods OauthTokenModSlice
|
||||
baseOrganizationMods OrganizationModSlice
|
||||
basePublicreportNuisanceMods PublicreportNuisanceModSlice
|
||||
basePublicreportPoolMods PublicreportPoolModSlice
|
||||
basePublicreportPoolPhotoMods PublicreportPoolPhotoModSlice
|
||||
basePublicreportQuickMods PublicreportQuickModSlice
|
||||
basePublicreportQuickPhotoMods PublicreportQuickPhotoModSlice
|
||||
baseRasterColumnMods RasterColumnModSlice
|
||||
|
|
@ -2420,6 +2422,96 @@ func (f *Factory) FromExistingPublicreportNuisance(m *models.PublicreportNuisanc
|
|||
return o
|
||||
}
|
||||
|
||||
func (f *Factory) NewPublicreportPool(mods ...PublicreportPoolMod) *PublicreportPoolTemplate {
|
||||
return f.NewPublicreportPoolWithContext(context.Background(), mods...)
|
||||
}
|
||||
|
||||
func (f *Factory) NewPublicreportPoolWithContext(ctx context.Context, mods ...PublicreportPoolMod) *PublicreportPoolTemplate {
|
||||
o := &PublicreportPoolTemplate{f: f}
|
||||
|
||||
if f != nil {
|
||||
f.basePublicreportPoolMods.Apply(ctx, o)
|
||||
}
|
||||
|
||||
PublicreportPoolModSlice(mods).Apply(ctx, o)
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (f *Factory) FromExistingPublicreportPool(m *models.PublicreportPool) *PublicreportPoolTemplate {
|
||||
o := &PublicreportPoolTemplate{f: f, alreadyPersisted: true}
|
||||
|
||||
o.ID = func() int32 { return m.ID }
|
||||
o.AccessComments = func() string { return m.AccessComments }
|
||||
o.AccessGate = func() bool { return m.AccessGate }
|
||||
o.AccessFence = func() bool { return m.AccessFence }
|
||||
o.AccessLocked = func() bool { return m.AccessLocked }
|
||||
o.AccessDog = func() bool { return m.AccessDog }
|
||||
o.AccessOther = func() bool { return m.AccessOther }
|
||||
o.Address = func() string { return m.Address }
|
||||
o.AddressCountry = func() string { return m.AddressCountry }
|
||||
o.AddressPostCode = func() string { return m.AddressPostCode }
|
||||
o.AddressPlace = func() string { return m.AddressPlace }
|
||||
o.AddressStreet = func() string { return m.AddressStreet }
|
||||
o.AddressRegion = func() string { return m.AddressRegion }
|
||||
o.Comments = func() string { return m.Comments }
|
||||
o.Created = func() time.Time { return m.Created }
|
||||
o.H3cell = func() null.Val[string] { return m.H3cell }
|
||||
o.HasAdult = func() bool { return m.HasAdult }
|
||||
o.HasLarvae = func() bool { return m.HasLarvae }
|
||||
o.HasPupae = func() bool { return m.HasPupae }
|
||||
o.Location = func() null.Val[string] { return m.Location }
|
||||
o.MapZoom = func() float64 { return m.MapZoom }
|
||||
o.OwnerEmail = func() string { return m.OwnerEmail }
|
||||
o.OwnerName = func() string { return m.OwnerName }
|
||||
o.OwnerPhone = func() string { return m.OwnerPhone }
|
||||
o.PublicID = func() string { return m.PublicID }
|
||||
o.ReporterEmail = func() string { return m.ReporterEmail }
|
||||
o.ReporterName = func() string { return m.ReporterName }
|
||||
o.ReporterPhone = func() string { return m.ReporterPhone }
|
||||
o.Subscribe = func() bool { return m.Subscribe }
|
||||
|
||||
ctx := context.Background()
|
||||
if len(m.R.PoolPhotos) > 0 {
|
||||
PublicreportPoolMods.AddExistingPoolPhotos(m.R.PoolPhotos...).Apply(ctx, o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (f *Factory) NewPublicreportPoolPhoto(mods ...PublicreportPoolPhotoMod) *PublicreportPoolPhotoTemplate {
|
||||
return f.NewPublicreportPoolPhotoWithContext(context.Background(), mods...)
|
||||
}
|
||||
|
||||
func (f *Factory) NewPublicreportPoolPhotoWithContext(ctx context.Context, mods ...PublicreportPoolPhotoMod) *PublicreportPoolPhotoTemplate {
|
||||
o := &PublicreportPoolPhotoTemplate{f: f}
|
||||
|
||||
if f != nil {
|
||||
f.basePublicreportPoolPhotoMods.Apply(ctx, o)
|
||||
}
|
||||
|
||||
PublicreportPoolPhotoModSlice(mods).Apply(ctx, o)
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (f *Factory) FromExistingPublicreportPoolPhoto(m *models.PublicreportPoolPhoto) *PublicreportPoolPhotoTemplate {
|
||||
o := &PublicreportPoolPhotoTemplate{f: f, alreadyPersisted: true}
|
||||
|
||||
o.ID = func() int32 { return m.ID }
|
||||
o.Size = func() int64 { return m.Size }
|
||||
o.Filename = func() string { return m.Filename }
|
||||
o.PoolID = func() int32 { return m.PoolID }
|
||||
o.UUID = func() uuid.UUID { return m.UUID }
|
||||
|
||||
ctx := context.Background()
|
||||
if m.R.Pool != nil {
|
||||
PublicreportPoolPhotoMods.WithExistingPool(m.R.Pool).Apply(ctx, o)
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (f *Factory) NewPublicreportQuick(mods ...PublicreportQuickMod) *PublicreportQuickTemplate {
|
||||
return f.NewPublicreportQuickWithContext(context.Background(), mods...)
|
||||
}
|
||||
|
|
@ -3009,6 +3101,22 @@ func (f *Factory) AddBasePublicreportNuisanceMod(mods ...PublicreportNuisanceMod
|
|||
f.basePublicreportNuisanceMods = append(f.basePublicreportNuisanceMods, mods...)
|
||||
}
|
||||
|
||||
func (f *Factory) ClearBasePublicreportPoolMods() {
|
||||
f.basePublicreportPoolMods = nil
|
||||
}
|
||||
|
||||
func (f *Factory) AddBasePublicreportPoolMod(mods ...PublicreportPoolMod) {
|
||||
f.basePublicreportPoolMods = append(f.basePublicreportPoolMods, mods...)
|
||||
}
|
||||
|
||||
func (f *Factory) ClearBasePublicreportPoolPhotoMods() {
|
||||
f.basePublicreportPoolPhotoMods = nil
|
||||
}
|
||||
|
||||
func (f *Factory) AddBasePublicreportPoolPhotoMod(mods ...PublicreportPoolPhotoMod) {
|
||||
f.basePublicreportPoolPhotoMods = append(f.basePublicreportPoolPhotoMods, mods...)
|
||||
}
|
||||
|
||||
func (f *Factory) ClearBasePublicreportQuickMods() {
|
||||
f.basePublicreportQuickMods = nil
|
||||
}
|
||||
|
|
|
|||
1613
db/factory/publicreport.pool.bob.go
Normal file
1613
db/factory/publicreport.pool.bob.go
Normal file
File diff suppressed because it is too large
Load diff
498
db/factory/publicreport.pool_photo.bob.go
Normal file
498
db/factory/publicreport.pool_photo.bob.go
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package factory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
models "github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jaswdr/faker/v2"
|
||||
"github.com/stephenafamo/bob"
|
||||
)
|
||||
|
||||
type PublicreportPoolPhotoMod interface {
|
||||
Apply(context.Context, *PublicreportPoolPhotoTemplate)
|
||||
}
|
||||
|
||||
type PublicreportPoolPhotoModFunc func(context.Context, *PublicreportPoolPhotoTemplate)
|
||||
|
||||
func (f PublicreportPoolPhotoModFunc) Apply(ctx context.Context, n *PublicreportPoolPhotoTemplate) {
|
||||
f(ctx, n)
|
||||
}
|
||||
|
||||
type PublicreportPoolPhotoModSlice []PublicreportPoolPhotoMod
|
||||
|
||||
func (mods PublicreportPoolPhotoModSlice) Apply(ctx context.Context, n *PublicreportPoolPhotoTemplate) {
|
||||
for _, f := range mods {
|
||||
f.Apply(ctx, n)
|
||||
}
|
||||
}
|
||||
|
||||
// PublicreportPoolPhotoTemplate is an object representing the database table.
|
||||
// all columns are optional and should be set by mods
|
||||
type PublicreportPoolPhotoTemplate struct {
|
||||
ID func() int32
|
||||
Size func() int64
|
||||
Filename func() string
|
||||
PoolID func() int32
|
||||
UUID func() uuid.UUID
|
||||
|
||||
r publicreportPoolPhotoR
|
||||
f *Factory
|
||||
|
||||
alreadyPersisted bool
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoR struct {
|
||||
Pool *publicreportPoolPhotoRPoolR
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoRPoolR struct {
|
||||
o *PublicreportPoolTemplate
|
||||
}
|
||||
|
||||
// Apply mods to the PublicreportPoolPhotoTemplate
|
||||
func (o *PublicreportPoolPhotoTemplate) Apply(ctx context.Context, mods ...PublicreportPoolPhotoMod) {
|
||||
for _, mod := range mods {
|
||||
mod.Apply(ctx, o)
|
||||
}
|
||||
}
|
||||
|
||||
// setModelRels creates and sets the relationships on *models.PublicreportPoolPhoto
|
||||
// according to the relationships in the template. Nothing is inserted into the db
|
||||
func (t PublicreportPoolPhotoTemplate) setModelRels(o *models.PublicreportPoolPhoto) {
|
||||
if t.r.Pool != nil {
|
||||
rel := t.r.Pool.o.Build()
|
||||
rel.R.PoolPhotos = append(rel.R.PoolPhotos, o)
|
||||
o.PoolID = rel.ID // h2
|
||||
o.R.Pool = rel
|
||||
}
|
||||
}
|
||||
|
||||
// BuildSetter returns an *models.PublicreportPoolPhotoSetter
|
||||
// this does nothing with the relationship templates
|
||||
func (o PublicreportPoolPhotoTemplate) BuildSetter() *models.PublicreportPoolPhotoSetter {
|
||||
m := &models.PublicreportPoolPhotoSetter{}
|
||||
|
||||
if o.ID != nil {
|
||||
val := o.ID()
|
||||
m.ID = omit.From(val)
|
||||
}
|
||||
if o.Size != nil {
|
||||
val := o.Size()
|
||||
m.Size = omit.From(val)
|
||||
}
|
||||
if o.Filename != nil {
|
||||
val := o.Filename()
|
||||
m.Filename = omit.From(val)
|
||||
}
|
||||
if o.PoolID != nil {
|
||||
val := o.PoolID()
|
||||
m.PoolID = omit.From(val)
|
||||
}
|
||||
if o.UUID != nil {
|
||||
val := o.UUID()
|
||||
m.UUID = omit.From(val)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// BuildManySetter returns an []*models.PublicreportPoolPhotoSetter
|
||||
// this does nothing with the relationship templates
|
||||
func (o PublicreportPoolPhotoTemplate) BuildManySetter(number int) []*models.PublicreportPoolPhotoSetter {
|
||||
m := make([]*models.PublicreportPoolPhotoSetter, number)
|
||||
|
||||
for i := range m {
|
||||
m[i] = o.BuildSetter()
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Build returns an *models.PublicreportPoolPhoto
|
||||
// Related objects are also created and placed in the .R field
|
||||
// NOTE: Objects are not inserted into the database. Use PublicreportPoolPhotoTemplate.Create
|
||||
func (o PublicreportPoolPhotoTemplate) Build() *models.PublicreportPoolPhoto {
|
||||
m := &models.PublicreportPoolPhoto{}
|
||||
|
||||
if o.ID != nil {
|
||||
m.ID = o.ID()
|
||||
}
|
||||
if o.Size != nil {
|
||||
m.Size = o.Size()
|
||||
}
|
||||
if o.Filename != nil {
|
||||
m.Filename = o.Filename()
|
||||
}
|
||||
if o.PoolID != nil {
|
||||
m.PoolID = o.PoolID()
|
||||
}
|
||||
if o.UUID != nil {
|
||||
m.UUID = o.UUID()
|
||||
}
|
||||
|
||||
o.setModelRels(m)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// BuildMany returns an models.PublicreportPoolPhotoSlice
|
||||
// Related objects are also created and placed in the .R field
|
||||
// NOTE: Objects are not inserted into the database. Use PublicreportPoolPhotoTemplate.CreateMany
|
||||
func (o PublicreportPoolPhotoTemplate) BuildMany(number int) models.PublicreportPoolPhotoSlice {
|
||||
m := make(models.PublicreportPoolPhotoSlice, number)
|
||||
|
||||
for i := range m {
|
||||
m[i] = o.Build()
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func ensureCreatablePublicreportPoolPhoto(m *models.PublicreportPoolPhotoSetter) {
|
||||
if !(m.Size.IsValue()) {
|
||||
val := random_int64(nil)
|
||||
m.Size = omit.From(val)
|
||||
}
|
||||
if !(m.Filename.IsValue()) {
|
||||
val := random_string(nil)
|
||||
m.Filename = omit.From(val)
|
||||
}
|
||||
if !(m.PoolID.IsValue()) {
|
||||
val := random_int32(nil)
|
||||
m.PoolID = omit.From(val)
|
||||
}
|
||||
if !(m.UUID.IsValue()) {
|
||||
val := random_uuid_UUID(nil)
|
||||
m.UUID = omit.From(val)
|
||||
}
|
||||
}
|
||||
|
||||
// insertOptRels creates and inserts any optional the relationships on *models.PublicreportPoolPhoto
|
||||
// according to the relationships in the template.
|
||||
// any required relationship should have already exist on the model
|
||||
func (o *PublicreportPoolPhotoTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.PublicreportPoolPhoto) error {
|
||||
var err error
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Create builds a publicreportPoolPhoto and inserts it into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
func (o *PublicreportPoolPhotoTemplate) Create(ctx context.Context, exec bob.Executor) (*models.PublicreportPoolPhoto, error) {
|
||||
var err error
|
||||
opt := o.BuildSetter()
|
||||
ensureCreatablePublicreportPoolPhoto(opt)
|
||||
|
||||
if o.r.Pool == nil {
|
||||
PublicreportPoolPhotoMods.WithNewPool().Apply(ctx, o)
|
||||
}
|
||||
|
||||
var rel0 *models.PublicreportPool
|
||||
|
||||
if o.r.Pool.o.alreadyPersisted {
|
||||
rel0 = o.r.Pool.o.Build()
|
||||
} else {
|
||||
rel0, err = o.r.Pool.o.Create(ctx, exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
opt.PoolID = omit.From(rel0.ID)
|
||||
|
||||
m, err := models.PublicreportPoolPhotos.Insert(opt).One(ctx, exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.R.Pool = rel0
|
||||
|
||||
if err := o.insertOptRels(ctx, exec, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
// MustCreate builds a publicreportPoolPhoto and inserts it into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
// panics if an error occurs
|
||||
func (o *PublicreportPoolPhotoTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.PublicreportPoolPhoto {
|
||||
m, err := o.Create(ctx, exec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// CreateOrFail builds a publicreportPoolPhoto and inserts it into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs
|
||||
func (o *PublicreportPoolPhotoTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.PublicreportPoolPhoto {
|
||||
tb.Helper()
|
||||
m, err := o.Create(ctx, exec)
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
return nil
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// CreateMany builds multiple publicreportPoolPhotos and inserts them into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
func (o PublicreportPoolPhotoTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.PublicreportPoolPhotoSlice, error) {
|
||||
var err error
|
||||
m := make(models.PublicreportPoolPhotoSlice, number)
|
||||
|
||||
for i := range m {
|
||||
m[i], err = o.Create(ctx, exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MustCreateMany builds multiple publicreportPoolPhotos and inserts them into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
// panics if an error occurs
|
||||
func (o PublicreportPoolPhotoTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.PublicreportPoolPhotoSlice {
|
||||
m, err := o.CreateMany(ctx, exec, number)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// CreateManyOrFail builds multiple publicreportPoolPhotos and inserts them into the database
|
||||
// Relations objects are also inserted and placed in the .R field
|
||||
// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs
|
||||
func (o PublicreportPoolPhotoTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.PublicreportPoolPhotoSlice {
|
||||
tb.Helper()
|
||||
m, err := o.CreateMany(ctx, exec, number)
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
return nil
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// PublicreportPoolPhoto has methods that act as mods for the PublicreportPoolPhotoTemplate
|
||||
var PublicreportPoolPhotoMods publicreportPoolPhotoMods
|
||||
|
||||
type publicreportPoolPhotoMods struct{}
|
||||
|
||||
func (m publicreportPoolPhotoMods) RandomizeAllColumns(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModSlice{
|
||||
PublicreportPoolPhotoMods.RandomID(f),
|
||||
PublicreportPoolPhotoMods.RandomSize(f),
|
||||
PublicreportPoolPhotoMods.RandomFilename(f),
|
||||
PublicreportPoolPhotoMods.RandomPoolID(f),
|
||||
PublicreportPoolPhotoMods.RandomUUID(f),
|
||||
}
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m publicreportPoolPhotoMods) ID(val int32) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.ID = func() int32 { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m publicreportPoolPhotoMods) IDFunc(f func() int32) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.ID = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m publicreportPoolPhotoMods) UnsetID() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.ID = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
func (m publicreportPoolPhotoMods) RandomID(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.ID = func() int32 {
|
||||
return random_int32(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m publicreportPoolPhotoMods) Size(val int64) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Size = func() int64 { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m publicreportPoolPhotoMods) SizeFunc(f func() int64) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Size = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m publicreportPoolPhotoMods) UnsetSize() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Size = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
func (m publicreportPoolPhotoMods) RandomSize(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Size = func() int64 {
|
||||
return random_int64(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m publicreportPoolPhotoMods) Filename(val string) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Filename = func() string { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m publicreportPoolPhotoMods) FilenameFunc(f func() string) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Filename = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m publicreportPoolPhotoMods) UnsetFilename() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Filename = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
func (m publicreportPoolPhotoMods) RandomFilename(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.Filename = func() string {
|
||||
return random_string(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m publicreportPoolPhotoMods) PoolID(val int32) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.PoolID = func() int32 { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m publicreportPoolPhotoMods) PoolIDFunc(f func() int32) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.PoolID = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m publicreportPoolPhotoMods) UnsetPoolID() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.PoolID = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
func (m publicreportPoolPhotoMods) RandomPoolID(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.PoolID = func() int32 {
|
||||
return random_int32(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Set the model columns to this value
|
||||
func (m publicreportPoolPhotoMods) UUID(val uuid.UUID) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.UUID = func() uuid.UUID { return val }
|
||||
})
|
||||
}
|
||||
|
||||
// Set the Column from the function
|
||||
func (m publicreportPoolPhotoMods) UUIDFunc(f func() uuid.UUID) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.UUID = f
|
||||
})
|
||||
}
|
||||
|
||||
// Clear any values for the column
|
||||
func (m publicreportPoolPhotoMods) UnsetUUID() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.UUID = nil
|
||||
})
|
||||
}
|
||||
|
||||
// Generates a random value for the column using the given faker
|
||||
// if faker is nil, a default faker is used
|
||||
func (m publicreportPoolPhotoMods) RandomUUID(f *faker.Faker) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(_ context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.UUID = func() uuid.UUID {
|
||||
return random_uuid_UUID(f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m publicreportPoolPhotoMods) WithParentsCascading() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(ctx context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
if isDone, _ := publicreportPoolPhotoWithParentsCascadingCtx.Value(ctx); isDone {
|
||||
return
|
||||
}
|
||||
ctx = publicreportPoolPhotoWithParentsCascadingCtx.WithValue(ctx, true)
|
||||
{
|
||||
|
||||
related := o.f.NewPublicreportPoolWithContext(ctx, PublicreportPoolMods.WithParentsCascading())
|
||||
m.WithPool(related).Apply(ctx, o)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m publicreportPoolPhotoMods) WithPool(rel *PublicreportPoolTemplate) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(ctx context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.r.Pool = &publicreportPoolPhotoRPoolR{
|
||||
o: rel,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m publicreportPoolPhotoMods) WithNewPool(mods ...PublicreportPoolMod) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(ctx context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
related := o.f.NewPublicreportPoolWithContext(ctx, mods...)
|
||||
|
||||
m.WithPool(related).Apply(ctx, o)
|
||||
})
|
||||
}
|
||||
|
||||
func (m publicreportPoolPhotoMods) WithExistingPool(em *models.PublicreportPool) PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(ctx context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.r.Pool = &publicreportPoolPhotoRPoolR{
|
||||
o: o.f.FromExistingPublicreportPool(em),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m publicreportPoolPhotoMods) WithoutPool() PublicreportPoolPhotoMod {
|
||||
return PublicreportPoolPhotoModFunc(func(ctx context.Context, o *PublicreportPoolPhotoTemplate) {
|
||||
o.r.Pool = nil
|
||||
})
|
||||
}
|
||||
53
db/migrations/00026_publicreport_pool.sql
Normal file
53
db/migrations/00026_publicreport_pool.sql
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
-- +goose Up
|
||||
CREATE TYPE publicreport.PoolSourceDuration AS ENUM (
|
||||
'none',
|
||||
'less-than-week',
|
||||
'1-2-weeks',
|
||||
'2-4-weeks',
|
||||
'1-3-months',
|
||||
'more-than-3-months'
|
||||
);
|
||||
CREATE TABLE publicreport.pool (
|
||||
id SERIAL PRIMARY KEY,
|
||||
access_comments TEXT NOT NULL,
|
||||
access_gate BOOLEAN NOT NULL,
|
||||
access_fence BOOLEAN NOT NULL,
|
||||
access_locked BOOLEAN NOT NULL,
|
||||
access_dog BOOLEAN NOT NULL,
|
||||
access_other BOOLEAN NOT NULL,
|
||||
address TEXT NOT NULL,
|
||||
address_country TEXT NOT NULL,
|
||||
address_post_code TEXT NOT NULL,
|
||||
address_place TEXT NOT NULL,
|
||||
address_street TEXT NOT NULL,
|
||||
address_region TEXT NOT NULL,
|
||||
comments TEXT NOT NULL,
|
||||
created TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
h3cell h3index,
|
||||
has_adult BOOLEAN NOT NULL,
|
||||
has_larvae BOOLEAN NOT NULL,
|
||||
has_pupae BOOLEAN NOT NULL,
|
||||
location GEOGRAPHY,
|
||||
map_zoom FLOAT NOT NULL,
|
||||
owner_email TEXT NOT NULL,
|
||||
owner_name TEXT NOT NULL,
|
||||
owner_phone TEXT NOT NULL,
|
||||
public_id TEXT NOT NULL UNIQUE,
|
||||
reporter_email TEXT NOT NULL,
|
||||
reporter_name TEXT NOT NULL,
|
||||
reporter_phone TEXT NOT NULL,
|
||||
subscribe BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE publicreport.pool_photo (
|
||||
id SERIAL PRIMARY KEY,
|
||||
size BIGINT NOT NULL,
|
||||
filename TEXT NOT NULL,
|
||||
pool_id INT NOT NULL REFERENCES publicreport.pool(id),
|
||||
uuid UUID NOT NULL
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE publicreport.pool_photo;
|
||||
DROP TABLE publicreport.pool;
|
||||
DROP TYPE publicreport.PoolSourceDuration;
|
||||
|
|
@ -70,6 +70,8 @@ type joins[Q dialect.Joinable] struct {
|
|||
Notifications joinSet[notificationJoins[Q]]
|
||||
OauthTokens joinSet[oauthTokenJoins[Q]]
|
||||
Organizations joinSet[organizationJoins[Q]]
|
||||
PublicreportPools joinSet[publicreportPoolJoins[Q]]
|
||||
PublicreportPoolPhotos joinSet[publicreportPoolPhotoJoins[Q]]
|
||||
PublicreportQuicks joinSet[publicreportQuickJoins[Q]]
|
||||
PublicreportQuickPhotos joinSet[publicreportQuickPhotoJoins[Q]]
|
||||
Users joinSet[userJoins[Q]]
|
||||
|
|
@ -123,6 +125,8 @@ func getJoins[Q dialect.Joinable]() joins[Q] {
|
|||
Notifications: buildJoinSet[notificationJoins[Q]](Notifications.Columns, buildNotificationJoins),
|
||||
OauthTokens: buildJoinSet[oauthTokenJoins[Q]](OauthTokens.Columns, buildOauthTokenJoins),
|
||||
Organizations: buildJoinSet[organizationJoins[Q]](Organizations.Columns, buildOrganizationJoins),
|
||||
PublicreportPools: buildJoinSet[publicreportPoolJoins[Q]](PublicreportPools.Columns, buildPublicreportPoolJoins),
|
||||
PublicreportPoolPhotos: buildJoinSet[publicreportPoolPhotoJoins[Q]](PublicreportPoolPhotos.Columns, buildPublicreportPoolPhotoJoins),
|
||||
PublicreportQuicks: buildJoinSet[publicreportQuickJoins[Q]](PublicreportQuicks.Columns, buildPublicreportQuickJoins),
|
||||
PublicreportQuickPhotos: buildJoinSet[publicreportQuickPhotoJoins[Q]](PublicreportQuickPhotos.Columns, buildPublicreportQuickPhotoJoins),
|
||||
Users: buildJoinSet[userJoins[Q]](Users.Columns, buildUserJoins),
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ type preloaders struct {
|
|||
Notification notificationPreloader
|
||||
OauthToken oauthTokenPreloader
|
||||
Organization organizationPreloader
|
||||
PublicreportPool publicreportPoolPreloader
|
||||
PublicreportPoolPhoto publicreportPoolPhotoPreloader
|
||||
PublicreportQuick publicreportQuickPreloader
|
||||
PublicreportQuickPhoto publicreportQuickPhotoPreloader
|
||||
User userPreloader
|
||||
|
|
@ -100,6 +102,8 @@ func getPreloaders() preloaders {
|
|||
Notification: buildNotificationPreloader(),
|
||||
OauthToken: buildOauthTokenPreloader(),
|
||||
Organization: buildOrganizationPreloader(),
|
||||
PublicreportPool: buildPublicreportPoolPreloader(),
|
||||
PublicreportPoolPhoto: buildPublicreportPoolPhotoPreloader(),
|
||||
PublicreportQuick: buildPublicreportQuickPreloader(),
|
||||
PublicreportQuickPhoto: buildPublicreportQuickPhotoPreloader(),
|
||||
User: buildUserPreloader(),
|
||||
|
|
@ -151,6 +155,8 @@ type thenLoaders[Q orm.Loadable] struct {
|
|||
Notification notificationThenLoader[Q]
|
||||
OauthToken oauthTokenThenLoader[Q]
|
||||
Organization organizationThenLoader[Q]
|
||||
PublicreportPool publicreportPoolThenLoader[Q]
|
||||
PublicreportPoolPhoto publicreportPoolPhotoThenLoader[Q]
|
||||
PublicreportQuick publicreportQuickThenLoader[Q]
|
||||
PublicreportQuickPhoto publicreportQuickPhotoThenLoader[Q]
|
||||
User userThenLoader[Q]
|
||||
|
|
@ -196,6 +202,8 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] {
|
|||
Notification: buildNotificationThenLoader[Q](),
|
||||
OauthToken: buildOauthTokenThenLoader[Q](),
|
||||
Organization: buildOrganizationThenLoader[Q](),
|
||||
PublicreportPool: buildPublicreportPoolThenLoader[Q](),
|
||||
PublicreportPoolPhoto: buildPublicreportPoolPhotoThenLoader[Q](),
|
||||
PublicreportQuick: buildPublicreportQuickThenLoader[Q](),
|
||||
PublicreportQuickPhoto: buildPublicreportQuickPhotoThenLoader[Q](),
|
||||
User: buildUserThenLoader[Q](),
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ func Where[Q psql.Filterable]() struct {
|
|||
OauthTokens oauthTokenWhere[Q]
|
||||
Organizations organizationWhere[Q]
|
||||
PublicreportNuisances publicreportNuisanceWhere[Q]
|
||||
PublicreportPools publicreportPoolWhere[Q]
|
||||
PublicreportPoolPhotos publicreportPoolPhotoWhere[Q]
|
||||
PublicreportQuicks publicreportQuickWhere[Q]
|
||||
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
||||
RasterColumns rasterColumnWhere[Q]
|
||||
|
|
@ -110,6 +112,8 @@ func Where[Q psql.Filterable]() struct {
|
|||
OauthTokens oauthTokenWhere[Q]
|
||||
Organizations organizationWhere[Q]
|
||||
PublicreportNuisances publicreportNuisanceWhere[Q]
|
||||
PublicreportPools publicreportPoolWhere[Q]
|
||||
PublicreportPoolPhotos publicreportPoolPhotoWhere[Q]
|
||||
PublicreportQuicks publicreportQuickWhere[Q]
|
||||
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
||||
RasterColumns rasterColumnWhere[Q]
|
||||
|
|
@ -160,6 +164,8 @@ func Where[Q psql.Filterable]() struct {
|
|||
OauthTokens: buildOauthTokenWhere[Q](OauthTokens.Columns),
|
||||
Organizations: buildOrganizationWhere[Q](Organizations.Columns),
|
||||
PublicreportNuisances: buildPublicreportNuisanceWhere[Q](PublicreportNuisances.Columns),
|
||||
PublicreportPools: buildPublicreportPoolWhere[Q](PublicreportPools.Columns),
|
||||
PublicreportPoolPhotos: buildPublicreportPoolPhotoWhere[Q](PublicreportPoolPhotos.Columns),
|
||||
PublicreportQuicks: buildPublicreportQuickWhere[Q](PublicreportQuicks.Columns),
|
||||
PublicreportQuickPhotos: buildPublicreportQuickPhotoWhere[Q](PublicreportQuickPhotos.Columns),
|
||||
RasterColumns: buildRasterColumnWhere[Q](RasterColumns.Columns),
|
||||
|
|
|
|||
1295
db/models/publicreport.pool.bob.go
Normal file
1295
db/models/publicreport.pool.bob.go
Normal file
File diff suppressed because it is too large
Load diff
678
db/models/publicreport.pool_photo.bob.go
Normal file
678
db/models/publicreport.pool_photo.bob.go
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
// Code generated by BobGen psql v0.0.4-0.20260105020634-53e08d840e47+dirty. DO NOT EDIT.
|
||||
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stephenafamo/bob"
|
||||
"github.com/stephenafamo/bob/dialect/psql"
|
||||
"github.com/stephenafamo/bob/dialect/psql/dialect"
|
||||
"github.com/stephenafamo/bob/dialect/psql/dm"
|
||||
"github.com/stephenafamo/bob/dialect/psql/sm"
|
||||
"github.com/stephenafamo/bob/dialect/psql/um"
|
||||
"github.com/stephenafamo/bob/expr"
|
||||
"github.com/stephenafamo/bob/mods"
|
||||
"github.com/stephenafamo/bob/orm"
|
||||
"github.com/stephenafamo/bob/types/pgtypes"
|
||||
)
|
||||
|
||||
// PublicreportPoolPhoto is an object representing the database table.
|
||||
type PublicreportPoolPhoto struct {
|
||||
ID int32 `db:"id,pk" `
|
||||
Size int64 `db:"size" `
|
||||
Filename string `db:"filename" `
|
||||
PoolID int32 `db:"pool_id" `
|
||||
UUID uuid.UUID `db:"uuid" `
|
||||
|
||||
R publicreportPoolPhotoR `db:"-" `
|
||||
}
|
||||
|
||||
// PublicreportPoolPhotoSlice is an alias for a slice of pointers to PublicreportPoolPhoto.
|
||||
// This should almost always be used instead of []*PublicreportPoolPhoto.
|
||||
type PublicreportPoolPhotoSlice []*PublicreportPoolPhoto
|
||||
|
||||
// PublicreportPoolPhotos contains methods to work with the pool_photo table
|
||||
var PublicreportPoolPhotos = psql.NewTablex[*PublicreportPoolPhoto, PublicreportPoolPhotoSlice, *PublicreportPoolPhotoSetter]("publicreport", "pool_photo", buildPublicreportPoolPhotoColumns("publicreport.pool_photo"))
|
||||
|
||||
// PublicreportPoolPhotosQuery is a query on the pool_photo table
|
||||
type PublicreportPoolPhotosQuery = *psql.ViewQuery[*PublicreportPoolPhoto, PublicreportPoolPhotoSlice]
|
||||
|
||||
// publicreportPoolPhotoR is where relationships are stored.
|
||||
type publicreportPoolPhotoR struct {
|
||||
Pool *PublicreportPool // publicreport.pool_photo.pool_photo_pool_id_fkey
|
||||
}
|
||||
|
||||
func buildPublicreportPoolPhotoColumns(alias string) publicreportPoolPhotoColumns {
|
||||
return publicreportPoolPhotoColumns{
|
||||
ColumnsExpr: expr.NewColumnsExpr(
|
||||
"id", "size", "filename", "pool_id", "uuid",
|
||||
).WithParent("publicreport.pool_photo"),
|
||||
tableAlias: alias,
|
||||
ID: psql.Quote(alias, "id"),
|
||||
Size: psql.Quote(alias, "size"),
|
||||
Filename: psql.Quote(alias, "filename"),
|
||||
PoolID: psql.Quote(alias, "pool_id"),
|
||||
UUID: psql.Quote(alias, "uuid"),
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoColumns struct {
|
||||
expr.ColumnsExpr
|
||||
tableAlias string
|
||||
ID psql.Expression
|
||||
Size psql.Expression
|
||||
Filename psql.Expression
|
||||
PoolID psql.Expression
|
||||
UUID psql.Expression
|
||||
}
|
||||
|
||||
func (c publicreportPoolPhotoColumns) Alias() string {
|
||||
return c.tableAlias
|
||||
}
|
||||
|
||||
func (publicreportPoolPhotoColumns) AliasedAs(alias string) publicreportPoolPhotoColumns {
|
||||
return buildPublicreportPoolPhotoColumns(alias)
|
||||
}
|
||||
|
||||
// PublicreportPoolPhotoSetter is used for insert/upsert/update operations
|
||||
// All values are optional, and do not have to be set
|
||||
// Generated columns are not included
|
||||
type PublicreportPoolPhotoSetter struct {
|
||||
ID omit.Val[int32] `db:"id,pk" `
|
||||
Size omit.Val[int64] `db:"size" `
|
||||
Filename omit.Val[string] `db:"filename" `
|
||||
PoolID omit.Val[int32] `db:"pool_id" `
|
||||
UUID omit.Val[uuid.UUID] `db:"uuid" `
|
||||
}
|
||||
|
||||
func (s PublicreportPoolPhotoSetter) SetColumns() []string {
|
||||
vals := make([]string, 0, 5)
|
||||
if s.ID.IsValue() {
|
||||
vals = append(vals, "id")
|
||||
}
|
||||
if s.Size.IsValue() {
|
||||
vals = append(vals, "size")
|
||||
}
|
||||
if s.Filename.IsValue() {
|
||||
vals = append(vals, "filename")
|
||||
}
|
||||
if s.PoolID.IsValue() {
|
||||
vals = append(vals, "pool_id")
|
||||
}
|
||||
if s.UUID.IsValue() {
|
||||
vals = append(vals, "uuid")
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
func (s PublicreportPoolPhotoSetter) Overwrite(t *PublicreportPoolPhoto) {
|
||||
if s.ID.IsValue() {
|
||||
t.ID = s.ID.MustGet()
|
||||
}
|
||||
if s.Size.IsValue() {
|
||||
t.Size = s.Size.MustGet()
|
||||
}
|
||||
if s.Filename.IsValue() {
|
||||
t.Filename = s.Filename.MustGet()
|
||||
}
|
||||
if s.PoolID.IsValue() {
|
||||
t.PoolID = s.PoolID.MustGet()
|
||||
}
|
||||
if s.UUID.IsValue() {
|
||||
t.UUID = s.UUID.MustGet()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PublicreportPoolPhotoSetter) Apply(q *dialect.InsertQuery) {
|
||||
q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {
|
||||
return PublicreportPoolPhotos.BeforeInsertHooks.RunHooks(ctx, exec, s)
|
||||
})
|
||||
|
||||
q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
|
||||
vals := make([]bob.Expression, 5)
|
||||
if s.ID.IsValue() {
|
||||
vals[0] = psql.Arg(s.ID.MustGet())
|
||||
} else {
|
||||
vals[0] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if s.Size.IsValue() {
|
||||
vals[1] = psql.Arg(s.Size.MustGet())
|
||||
} else {
|
||||
vals[1] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if s.Filename.IsValue() {
|
||||
vals[2] = psql.Arg(s.Filename.MustGet())
|
||||
} else {
|
||||
vals[2] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if s.PoolID.IsValue() {
|
||||
vals[3] = psql.Arg(s.PoolID.MustGet())
|
||||
} else {
|
||||
vals[3] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
if s.UUID.IsValue() {
|
||||
vals[4] = psql.Arg(s.UUID.MustGet())
|
||||
} else {
|
||||
vals[4] = psql.Raw("DEFAULT")
|
||||
}
|
||||
|
||||
return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "")
|
||||
}))
|
||||
}
|
||||
|
||||
func (s PublicreportPoolPhotoSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
|
||||
return um.Set(s.Expressions()...)
|
||||
}
|
||||
|
||||
func (s PublicreportPoolPhotoSetter) Expressions(prefix ...string) []bob.Expression {
|
||||
exprs := make([]bob.Expression, 0, 5)
|
||||
|
||||
if s.ID.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "id")...),
|
||||
psql.Arg(s.ID),
|
||||
}})
|
||||
}
|
||||
|
||||
if s.Size.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "size")...),
|
||||
psql.Arg(s.Size),
|
||||
}})
|
||||
}
|
||||
|
||||
if s.Filename.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "filename")...),
|
||||
psql.Arg(s.Filename),
|
||||
}})
|
||||
}
|
||||
|
||||
if s.PoolID.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "pool_id")...),
|
||||
psql.Arg(s.PoolID),
|
||||
}})
|
||||
}
|
||||
|
||||
if s.UUID.IsValue() {
|
||||
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
|
||||
psql.Quote(append(prefix, "uuid")...),
|
||||
psql.Arg(s.UUID),
|
||||
}})
|
||||
}
|
||||
|
||||
return exprs
|
||||
}
|
||||
|
||||
// FindPublicreportPoolPhoto retrieves a single record by primary key
|
||||
// If cols is empty Find will return all columns.
|
||||
func FindPublicreportPoolPhoto(ctx context.Context, exec bob.Executor, IDPK int32, cols ...string) (*PublicreportPoolPhoto, error) {
|
||||
if len(cols) == 0 {
|
||||
return PublicreportPoolPhotos.Query(
|
||||
sm.Where(PublicreportPoolPhotos.Columns.ID.EQ(psql.Arg(IDPK))),
|
||||
).One(ctx, exec)
|
||||
}
|
||||
|
||||
return PublicreportPoolPhotos.Query(
|
||||
sm.Where(PublicreportPoolPhotos.Columns.ID.EQ(psql.Arg(IDPK))),
|
||||
sm.Columns(PublicreportPoolPhotos.Columns.Only(cols...)),
|
||||
).One(ctx, exec)
|
||||
}
|
||||
|
||||
// PublicreportPoolPhotoExists checks the presence of a single record by primary key
|
||||
func PublicreportPoolPhotoExists(ctx context.Context, exec bob.Executor, IDPK int32) (bool, error) {
|
||||
return PublicreportPoolPhotos.Query(
|
||||
sm.Where(PublicreportPoolPhotos.Columns.ID.EQ(psql.Arg(IDPK))),
|
||||
).Exists(ctx, exec)
|
||||
}
|
||||
|
||||
// AfterQueryHook is called after PublicreportPoolPhoto is retrieved from the database
|
||||
func (o *PublicreportPoolPhoto) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error {
|
||||
var err error
|
||||
|
||||
switch queryType {
|
||||
case bob.QueryTypeSelect:
|
||||
ctx, err = PublicreportPoolPhotos.AfterSelectHooks.RunHooks(ctx, exec, PublicreportPoolPhotoSlice{o})
|
||||
case bob.QueryTypeInsert:
|
||||
ctx, err = PublicreportPoolPhotos.AfterInsertHooks.RunHooks(ctx, exec, PublicreportPoolPhotoSlice{o})
|
||||
case bob.QueryTypeUpdate:
|
||||
ctx, err = PublicreportPoolPhotos.AfterUpdateHooks.RunHooks(ctx, exec, PublicreportPoolPhotoSlice{o})
|
||||
case bob.QueryTypeDelete:
|
||||
ctx, err = PublicreportPoolPhotos.AfterDeleteHooks.RunHooks(ctx, exec, PublicreportPoolPhotoSlice{o})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// primaryKeyVals returns the primary key values of the PublicreportPoolPhoto
|
||||
func (o *PublicreportPoolPhoto) primaryKeyVals() bob.Expression {
|
||||
return psql.Arg(o.ID)
|
||||
}
|
||||
|
||||
func (o *PublicreportPoolPhoto) pkEQ() dialect.Expression {
|
||||
return psql.Quote("publicreport.pool_photo", "id").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
|
||||
return o.primaryKeyVals().WriteSQL(ctx, w, d, start)
|
||||
}))
|
||||
}
|
||||
|
||||
// Update uses an executor to update the PublicreportPoolPhoto
|
||||
func (o *PublicreportPoolPhoto) Update(ctx context.Context, exec bob.Executor, s *PublicreportPoolPhotoSetter) error {
|
||||
v, err := PublicreportPoolPhotos.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.R = v.R
|
||||
*o = *v
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes a single PublicreportPoolPhoto record with an executor
|
||||
func (o *PublicreportPoolPhoto) Delete(ctx context.Context, exec bob.Executor) error {
|
||||
_, err := PublicreportPoolPhotos.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec)
|
||||
return err
|
||||
}
|
||||
|
||||
// Reload refreshes the PublicreportPoolPhoto using the executor
|
||||
func (o *PublicreportPoolPhoto) Reload(ctx context.Context, exec bob.Executor) error {
|
||||
o2, err := PublicreportPoolPhotos.Query(
|
||||
sm.Where(PublicreportPoolPhotos.Columns.ID.EQ(psql.Arg(o.ID))),
|
||||
).One(ctx, exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o2.R = o.R
|
||||
*o = *o2
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AfterQueryHook is called after PublicreportPoolPhotoSlice is retrieved from the database
|
||||
func (o PublicreportPoolPhotoSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error {
|
||||
var err error
|
||||
|
||||
switch queryType {
|
||||
case bob.QueryTypeSelect:
|
||||
ctx, err = PublicreportPoolPhotos.AfterSelectHooks.RunHooks(ctx, exec, o)
|
||||
case bob.QueryTypeInsert:
|
||||
ctx, err = PublicreportPoolPhotos.AfterInsertHooks.RunHooks(ctx, exec, o)
|
||||
case bob.QueryTypeUpdate:
|
||||
ctx, err = PublicreportPoolPhotos.AfterUpdateHooks.RunHooks(ctx, exec, o)
|
||||
case bob.QueryTypeDelete:
|
||||
ctx, err = PublicreportPoolPhotos.AfterDeleteHooks.RunHooks(ctx, exec, o)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o PublicreportPoolPhotoSlice) pkIN() dialect.Expression {
|
||||
if len(o) == 0 {
|
||||
return psql.Raw("NULL")
|
||||
}
|
||||
|
||||
return psql.Quote("publicreport.pool_photo", "id").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) {
|
||||
pkPairs := make([]bob.Expression, len(o))
|
||||
for i, row := range o {
|
||||
pkPairs[i] = row.primaryKeyVals()
|
||||
}
|
||||
return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "")
|
||||
}))
|
||||
}
|
||||
|
||||
// copyMatchingRows finds models in the given slice that have the same primary key
|
||||
// then it first copies the existing relationships from the old model to the new model
|
||||
// and then replaces the old model in the slice with the new model
|
||||
func (o PublicreportPoolPhotoSlice) copyMatchingRows(from ...*PublicreportPoolPhoto) {
|
||||
for i, old := range o {
|
||||
for _, new := range from {
|
||||
if new.ID != old.ID {
|
||||
continue
|
||||
}
|
||||
new.R = old.R
|
||||
o[i] = new
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateMod modifies an update query with "WHERE primary_key IN (o...)"
|
||||
func (o PublicreportPoolPhotoSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] {
|
||||
return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) {
|
||||
q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {
|
||||
return PublicreportPoolPhotos.BeforeUpdateHooks.RunHooks(ctx, exec, o)
|
||||
})
|
||||
|
||||
q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error {
|
||||
var err error
|
||||
switch retrieved := retrieved.(type) {
|
||||
case *PublicreportPoolPhoto:
|
||||
o.copyMatchingRows(retrieved)
|
||||
case []*PublicreportPoolPhoto:
|
||||
o.copyMatchingRows(retrieved...)
|
||||
case PublicreportPoolPhotoSlice:
|
||||
o.copyMatchingRows(retrieved...)
|
||||
default:
|
||||
// If the retrieved value is not a PublicreportPoolPhoto or a slice of PublicreportPoolPhoto
|
||||
// then run the AfterUpdateHooks on the slice
|
||||
_, err = PublicreportPoolPhotos.AfterUpdateHooks.RunHooks(ctx, exec, o)
|
||||
}
|
||||
|
||||
return err
|
||||
}))
|
||||
|
||||
q.AppendWhere(o.pkIN())
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)"
|
||||
func (o PublicreportPoolPhotoSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] {
|
||||
return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) {
|
||||
q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) {
|
||||
return PublicreportPoolPhotos.BeforeDeleteHooks.RunHooks(ctx, exec, o)
|
||||
})
|
||||
|
||||
q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error {
|
||||
var err error
|
||||
switch retrieved := retrieved.(type) {
|
||||
case *PublicreportPoolPhoto:
|
||||
o.copyMatchingRows(retrieved)
|
||||
case []*PublicreportPoolPhoto:
|
||||
o.copyMatchingRows(retrieved...)
|
||||
case PublicreportPoolPhotoSlice:
|
||||
o.copyMatchingRows(retrieved...)
|
||||
default:
|
||||
// If the retrieved value is not a PublicreportPoolPhoto or a slice of PublicreportPoolPhoto
|
||||
// then run the AfterDeleteHooks on the slice
|
||||
_, err = PublicreportPoolPhotos.AfterDeleteHooks.RunHooks(ctx, exec, o)
|
||||
}
|
||||
|
||||
return err
|
||||
}))
|
||||
|
||||
q.AppendWhere(o.pkIN())
|
||||
})
|
||||
}
|
||||
|
||||
func (o PublicreportPoolPhotoSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals PublicreportPoolPhotoSetter) error {
|
||||
if len(o) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := PublicreportPoolPhotos.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec)
|
||||
return err
|
||||
}
|
||||
|
||||
func (o PublicreportPoolPhotoSlice) DeleteAll(ctx context.Context, exec bob.Executor) error {
|
||||
if len(o) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err := PublicreportPoolPhotos.Delete(o.DeleteMod()).Exec(ctx, exec)
|
||||
return err
|
||||
}
|
||||
|
||||
func (o PublicreportPoolPhotoSlice) ReloadAll(ctx context.Context, exec bob.Executor) error {
|
||||
if len(o) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
o2, err := PublicreportPoolPhotos.Query(sm.Where(o.pkIN())).All(ctx, exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.copyMatchingRows(o2...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pool starts a query for related objects on publicreport.pool
|
||||
func (o *PublicreportPoolPhoto) Pool(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportPoolsQuery {
|
||||
return PublicreportPools.Query(append(mods,
|
||||
sm.Where(PublicreportPools.Columns.ID.EQ(psql.Arg(o.PoolID))),
|
||||
)...)
|
||||
}
|
||||
|
||||
func (os PublicreportPoolPhotoSlice) Pool(mods ...bob.Mod[*dialect.SelectQuery]) PublicreportPoolsQuery {
|
||||
pkPoolID := make(pgtypes.Array[int32], 0, len(os))
|
||||
for _, o := range os {
|
||||
if o == nil {
|
||||
continue
|
||||
}
|
||||
pkPoolID = append(pkPoolID, o.PoolID)
|
||||
}
|
||||
PKArgExpr := psql.Select(sm.Columns(
|
||||
psql.F("unnest", psql.Cast(psql.Arg(pkPoolID), "integer[]")),
|
||||
))
|
||||
|
||||
return PublicreportPools.Query(append(mods,
|
||||
sm.Where(psql.Group(PublicreportPools.Columns.ID).OP("IN", PKArgExpr)),
|
||||
)...)
|
||||
}
|
||||
|
||||
func attachPublicreportPoolPhotoPool0(ctx context.Context, exec bob.Executor, count int, publicreportPoolPhoto0 *PublicreportPoolPhoto, publicreportPool1 *PublicreportPool) (*PublicreportPoolPhoto, error) {
|
||||
setter := &PublicreportPoolPhotoSetter{
|
||||
PoolID: omit.From(publicreportPool1.ID),
|
||||
}
|
||||
|
||||
err := publicreportPoolPhoto0.Update(ctx, exec, setter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("attachPublicreportPoolPhotoPool0: %w", err)
|
||||
}
|
||||
|
||||
return publicreportPoolPhoto0, nil
|
||||
}
|
||||
|
||||
func (publicreportPoolPhoto0 *PublicreportPoolPhoto) InsertPool(ctx context.Context, exec bob.Executor, related *PublicreportPoolSetter) error {
|
||||
var err error
|
||||
|
||||
publicreportPool1, err := PublicreportPools.Insert(related).One(ctx, exec)
|
||||
if err != nil {
|
||||
return fmt.Errorf("inserting related objects: %w", err)
|
||||
}
|
||||
|
||||
_, err = attachPublicreportPoolPhotoPool0(ctx, exec, 1, publicreportPoolPhoto0, publicreportPool1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicreportPoolPhoto0.R.Pool = publicreportPool1
|
||||
|
||||
publicreportPool1.R.PoolPhotos = append(publicreportPool1.R.PoolPhotos, publicreportPoolPhoto0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (publicreportPoolPhoto0 *PublicreportPoolPhoto) AttachPool(ctx context.Context, exec bob.Executor, publicreportPool1 *PublicreportPool) error {
|
||||
var err error
|
||||
|
||||
_, err = attachPublicreportPoolPhotoPool0(ctx, exec, 1, publicreportPoolPhoto0, publicreportPool1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
publicreportPoolPhoto0.R.Pool = publicreportPool1
|
||||
|
||||
publicreportPool1.R.PoolPhotos = append(publicreportPool1.R.PoolPhotos, publicreportPoolPhoto0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoWhere[Q psql.Filterable] struct {
|
||||
ID psql.WhereMod[Q, int32]
|
||||
Size psql.WhereMod[Q, int64]
|
||||
Filename psql.WhereMod[Q, string]
|
||||
PoolID psql.WhereMod[Q, int32]
|
||||
UUID psql.WhereMod[Q, uuid.UUID]
|
||||
}
|
||||
|
||||
func (publicreportPoolPhotoWhere[Q]) AliasedAs(alias string) publicreportPoolPhotoWhere[Q] {
|
||||
return buildPublicreportPoolPhotoWhere[Q](buildPublicreportPoolPhotoColumns(alias))
|
||||
}
|
||||
|
||||
func buildPublicreportPoolPhotoWhere[Q psql.Filterable](cols publicreportPoolPhotoColumns) publicreportPoolPhotoWhere[Q] {
|
||||
return publicreportPoolPhotoWhere[Q]{
|
||||
ID: psql.Where[Q, int32](cols.ID),
|
||||
Size: psql.Where[Q, int64](cols.Size),
|
||||
Filename: psql.Where[Q, string](cols.Filename),
|
||||
PoolID: psql.Where[Q, int32](cols.PoolID),
|
||||
UUID: psql.Where[Q, uuid.UUID](cols.UUID),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *PublicreportPoolPhoto) Preload(name string, retrieved any) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "Pool":
|
||||
rel, ok := retrieved.(*PublicreportPool)
|
||||
if !ok {
|
||||
return fmt.Errorf("publicreportPoolPhoto cannot load %T as %q", retrieved, name)
|
||||
}
|
||||
|
||||
o.R.Pool = rel
|
||||
|
||||
if rel != nil {
|
||||
rel.R.PoolPhotos = PublicreportPoolPhotoSlice{o}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("publicreportPoolPhoto has no relationship %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoPreloader struct {
|
||||
Pool func(...psql.PreloadOption) psql.Preloader
|
||||
}
|
||||
|
||||
func buildPublicreportPoolPhotoPreloader() publicreportPoolPhotoPreloader {
|
||||
return publicreportPoolPhotoPreloader{
|
||||
Pool: func(opts ...psql.PreloadOption) psql.Preloader {
|
||||
return psql.Preload[*PublicreportPool, PublicreportPoolSlice](psql.PreloadRel{
|
||||
Name: "Pool",
|
||||
Sides: []psql.PreloadSide{
|
||||
{
|
||||
From: PublicreportPoolPhotos,
|
||||
To: PublicreportPools,
|
||||
FromColumns: []string{"pool_id"},
|
||||
ToColumns: []string{"id"},
|
||||
},
|
||||
},
|
||||
}, PublicreportPools.Columns.Names(), opts...)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoThenLoader[Q orm.Loadable] struct {
|
||||
Pool func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q]
|
||||
}
|
||||
|
||||
func buildPublicreportPoolPhotoThenLoader[Q orm.Loadable]() publicreportPoolPhotoThenLoader[Q] {
|
||||
type PoolLoadInterface interface {
|
||||
LoadPool(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error
|
||||
}
|
||||
|
||||
return publicreportPoolPhotoThenLoader[Q]{
|
||||
Pool: thenLoadBuilder[Q](
|
||||
"Pool",
|
||||
func(ctx context.Context, exec bob.Executor, retrieved PoolLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error {
|
||||
return retrieved.LoadPool(ctx, exec, mods...)
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// LoadPool loads the publicreportPoolPhoto's Pool into the .R struct
|
||||
func (o *PublicreportPoolPhoto) LoadPool(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reset the relationship
|
||||
o.R.Pool = nil
|
||||
|
||||
related, err := o.Pool(mods...).One(ctx, exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
related.R.PoolPhotos = PublicreportPoolPhotoSlice{o}
|
||||
|
||||
o.R.Pool = related
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadPool loads the publicreportPoolPhoto's Pool into the .R struct
|
||||
func (os PublicreportPoolPhotoSlice) LoadPool(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error {
|
||||
if len(os) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
publicreportPools, err := os.Pool(mods...).All(ctx, exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, o := range os {
|
||||
if o == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, rel := range publicreportPools {
|
||||
|
||||
if !(o.PoolID == rel.ID) {
|
||||
continue
|
||||
}
|
||||
|
||||
rel.R.PoolPhotos = append(rel.R.PoolPhotos, o)
|
||||
|
||||
o.R.Pool = rel
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type publicreportPoolPhotoJoins[Q dialect.Joinable] struct {
|
||||
typ string
|
||||
Pool modAs[Q, publicreportPoolColumns]
|
||||
}
|
||||
|
||||
func (j publicreportPoolPhotoJoins[Q]) aliasedAs(alias string) publicreportPoolPhotoJoins[Q] {
|
||||
return buildPublicreportPoolPhotoJoins[Q](buildPublicreportPoolPhotoColumns(alias), j.typ)
|
||||
}
|
||||
|
||||
func buildPublicreportPoolPhotoJoins[Q dialect.Joinable](cols publicreportPoolPhotoColumns, typ string) publicreportPoolPhotoJoins[Q] {
|
||||
return publicreportPoolPhotoJoins[Q]{
|
||||
typ: typ,
|
||||
Pool: modAs[Q, publicreportPoolColumns]{
|
||||
c: PublicreportPools.Columns,
|
||||
f: func(to publicreportPoolColumns) bob.Mod[Q] {
|
||||
mods := make(mods.QueryMods[Q], 0, 1)
|
||||
|
||||
{
|
||||
mods = append(mods, dialect.Join[Q](typ, PublicreportPools.Name().As(to.Alias())).On(
|
||||
to.ID.EQ(cols.PoolID),
|
||||
))
|
||||
}
|
||||
|
||||
return mods
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -101,3 +101,44 @@ func CellToPostgisGeometry(c h3.Cell) (string, error) {
|
|||
|
||||
return fmt.Sprintf("POLYGON((%s))", sb.String()), nil
|
||||
}
|
||||
|
||||
// Convert from an accuracy in meters of GPS coordinates to the H3 Resolution that has at least
|
||||
// the same area. In other words, for a GPS coordinate accuracy of 2m you have pi*(2m)^2 or ~12.5m^2
|
||||
// of area which corresponds to resolution 13 (average area of 43.87^2) vs resolution 14 (average area 6.26m^2)
|
||||
// See https://h3geo.org/docs/core-library/restable
|
||||
func MeterAccuracyToH3Resolution(accuracy_in_meters float64) int {
|
||||
area := accuracy_in_meters * accuracy_in_meters * 3.1415
|
||||
if area < 0.895 {
|
||||
return 15
|
||||
} else if area < 6.267 {
|
||||
return 14
|
||||
} else if area < 43.87 {
|
||||
return 13
|
||||
} else if area < 307.092 {
|
||||
return 12
|
||||
} else if area < 2149.643 {
|
||||
return 11
|
||||
} else if area < 15_047.502 {
|
||||
return 10
|
||||
} else if area < 105_332.513 {
|
||||
return 9
|
||||
} else if area < 737_327.598 {
|
||||
return 8
|
||||
} else if area < 5_161_293.360 {
|
||||
return 7
|
||||
} else if area < 36_129_062.164 {
|
||||
return 6
|
||||
} else if area < 252_903_858.182 {
|
||||
return 5
|
||||
} else if area < 1_770_347_654.491 {
|
||||
return 4
|
||||
} else if area < 12_393_434_655.088 {
|
||||
return 3
|
||||
} else if area < 86_801_780_398.997 {
|
||||
return 2
|
||||
} else if area < 609_788_441_794.134 {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,21 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/userfile"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/aarondl/opt/omitnull"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stephenafamo/bob/dialect/psql"
|
||||
"github.com/stephenafamo/bob/dialect/psql/um"
|
||||
)
|
||||
|
||||
func Router() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getRoot)
|
||||
r.Get("/nuisance", getNuisance)
|
||||
r.Post("/nuisance-submit", postNuisance)
|
||||
r.Get("/nuisance-submit-complete", getNuisanceSubmitComplete)
|
||||
r.Get("/pool", getPool)
|
||||
r.Get("/quick", getQuick)
|
||||
r.Post("/quick-submit", postQuick)
|
||||
r.Get("/quick-submit-complete", getQuickSubmitComplete)
|
||||
r.Post("/register-notifications", postRegisterNotifications)
|
||||
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
|
||||
r.Get("/status", getStatus)
|
||||
localFS := http.Dir("./static")
|
||||
htmlpage.FileServer(r, "/static", localFS, EmbeddedStaticFS, "static")
|
||||
return r
|
||||
}
|
||||
|
||||
func getRoot(w http.ResponseWriter, r *http.Request) {
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
|
|
@ -67,32 +41,6 @@ func getNuisanceSubmitComplete(w http.ResponseWriter, r *http.Request) {
|
|||
},
|
||||
)
|
||||
}
|
||||
func getPool(w http.ResponseWriter, r *http.Request) {
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
Pool,
|
||||
ContextPool{
|
||||
MapboxToken: config.MapboxToken,
|
||||
},
|
||||
)
|
||||
}
|
||||
func getQuick(w http.ResponseWriter, r *http.Request) {
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
Quick,
|
||||
ContextQuick{},
|
||||
)
|
||||
}
|
||||
func getQuickSubmitComplete(w http.ResponseWriter, r *http.Request) {
|
||||
report := r.URL.Query().Get("report")
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
QuickSubmitComplete,
|
||||
ContextQuickSubmitComplete{
|
||||
ReportID: report,
|
||||
},
|
||||
)
|
||||
}
|
||||
func getRegisterNotificationsComplete(w http.ResponseWriter, r *http.Request) {
|
||||
report := r.URL.Query().Get("report")
|
||||
htmlpage.RenderOrError(
|
||||
|
|
@ -135,7 +83,6 @@ func postNuisance(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
|
||||
inspection_type_str := postFormValueOrNone(r, "inspection-type")
|
||||
var inspection_type enums.PublicreportNuisanceinspectiontype
|
||||
err = inspection_type.Scan(inspection_type_str)
|
||||
|
|
@ -221,108 +168,6 @@ func postNuisance(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, fmt.Sprintf("/nuisance-submit-complete?report=%s", public_id), http.StatusFound)
|
||||
}
|
||||
|
||||
func postQuick(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
|
||||
if err != nil {
|
||||
respondError(w, "Failed to parse form", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
lat := r.FormValue("latitude")
|
||||
lng := r.FormValue("longitude")
|
||||
comments := r.FormValue("comments")
|
||||
//photos := r.FormValue("photos")
|
||||
|
||||
latitude, err := strconv.ParseFloat(lat, 64)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create parse latitude", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
longitude, err := strconv.ParseFloat(lng, 64)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create parse longitude", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
u, err := GenerateReportID()
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create quick report public ID", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
c, err := h3utils.GetCell(longitude, latitude, 15)
|
||||
setter := models.PublicreportQuickSetter{
|
||||
Created: omit.From(time.Now()),
|
||||
Comments: omit.From(comments),
|
||||
//Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)),
|
||||
H3cell: omitnull.From(c.String()),
|
||||
PublicID: omit.From(u),
|
||||
ReporterEmail: omit.From(""),
|
||||
ReporterPhone: omit.From(""),
|
||||
}
|
||||
quick, err := models.PublicreportQuicks.Insert(&setter).One(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create database record", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = psql.Update(
|
||||
um.Table("publicreport.quick"),
|
||||
um.SetCol("location").To(fmt.Sprintf("ST_GeometryFromText('Point(%f %f)')", longitude, latitude)),
|
||||
um.Where(psql.Quote("id").EQ(psql.Arg(quick.ID))),
|
||||
).Exec(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to insert publicreport", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Info().Float64("latitude", latitude).Float64("longitude", longitude).Msg("Got upload")
|
||||
photoSetters := make([]*models.PublicreportQuickPhotoSetter, 0)
|
||||
for _, fheaders := range r.MultipartForm.File {
|
||||
for _, headers := range fheaders {
|
||||
file, err := headers.Open()
|
||||
|
||||
if err != nil {
|
||||
respondError(w, "Failed to open header", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
buff := make([]byte, 512)
|
||||
file.Read(buff)
|
||||
|
||||
file.Seek(0, 0)
|
||||
contentType := http.DetectContentType(buff)
|
||||
var sizeBuff bytes.Buffer
|
||||
fileSize, err := sizeBuff.ReadFrom(file)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to read file", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
file.Seek(0, 0)
|
||||
contentBuf := bytes.NewBuffer(nil)
|
||||
if _, err := io.Copy(contentBuf, file); err != nil {
|
||||
respondError(w, "Failed to save file", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Info().Int64("size", fileSize).Str("filename", headers.Filename).Str("content-type", contentType).Msg("Got an uploaded file")
|
||||
u, err := uuid.NewUUID()
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create quick report photo uuid", err, http.StatusInternalServerError)
|
||||
continue
|
||||
}
|
||||
err = userfile.PublicImageFileContentWrite(u, file)
|
||||
photoSetters = append(photoSetters, &models.PublicreportQuickPhotoSetter{
|
||||
Size: omit.From(fileSize),
|
||||
Filename: omit.From(headers.Filename),
|
||||
UUID: omit.From(u),
|
||||
})
|
||||
}
|
||||
}
|
||||
err = quick.InsertQuickPhotos(r.Context(), db.PGInstance.BobDB, photoSetters...)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create photo records", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, fmt.Sprintf("/quick-submit-complete?report=%s", u), http.StatusFound)
|
||||
}
|
||||
|
||||
func postRegisterNotifications(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
|
|
|
|||
69
public-report/geospatial.go
Normal file
69
public-report/geospatial.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/uber/h3-go/v4"
|
||||
)
|
||||
|
||||
type GeospatialData struct {
|
||||
Cell h3.Cell
|
||||
GeometryQuery string
|
||||
Populated bool
|
||||
}
|
||||
|
||||
func geospatialFromForm(r *http.Request) (GeospatialData, error) {
|
||||
lat := r.FormValue("latitude")
|
||||
lng := r.FormValue("longitude")
|
||||
accuracy_type := r.FormValue("latlng-accuracy-type")
|
||||
accuracy_value := r.FormValue("latlng-accuracy-value")
|
||||
|
||||
if lat == "" || lng == "" {
|
||||
return GeospatialData{Populated: false}, nil
|
||||
}
|
||||
latitude, err := strconv.ParseFloat(lat, 64)
|
||||
if err != nil {
|
||||
return GeospatialData{Populated: false}, fmt.Errorf("Failed to create parse latitude: %v", err)
|
||||
}
|
||||
longitude, err := strconv.ParseFloat(lng, 64)
|
||||
if err != nil {
|
||||
return GeospatialData{Populated: false}, fmt.Errorf("Failed to create parse longitude: %v", err)
|
||||
}
|
||||
var resolution int
|
||||
switch accuracy_type {
|
||||
// These accuracy_type strings come from the Mapbox Geocoding API definition and
|
||||
// are far from scientific
|
||||
case "rooftop":
|
||||
resolution = 14
|
||||
case "parcel":
|
||||
resolution = 13
|
||||
case "point":
|
||||
resolution = 13
|
||||
case "interpolated":
|
||||
resolution = 12
|
||||
case "approximate":
|
||||
resolution = 11
|
||||
case "intersection":
|
||||
resolution = 10
|
||||
// This is a special indicator that we got our location from the browser measurements
|
||||
case "meters":
|
||||
accuracy_in_meters, err := strconv.ParseFloat(accuracy_value, 64)
|
||||
if err != nil {
|
||||
return GeospatialData{Populated: false}, fmt.Errorf("Failed to parse '%s' as an accuracy in meters: %v", accuracy_value, err)
|
||||
}
|
||||
resolution = h3utils.MeterAccuracyToH3Resolution(accuracy_in_meters)
|
||||
default:
|
||||
log.Warn().Str("accuracy-type", accuracy_type).Msg("unrecognized accuracy type, this indicates either a weird client or misbehaving web page. Defaulting to resolution 13")
|
||||
resolution = 13
|
||||
}
|
||||
cell, err := h3utils.GetCell(longitude, latitude, resolution)
|
||||
return GeospatialData{
|
||||
Cell: cell,
|
||||
GeometryQuery: fmt.Sprintf("ST_GeometryFromText('Point(%f %f)')", longitude, latitude),
|
||||
Populated: true,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -17,13 +17,6 @@ type ContextNuisance struct{}
|
|||
type ContextNuisanceSubmitComplete struct {
|
||||
ReportID string
|
||||
}
|
||||
type ContextPool struct{
|
||||
MapboxToken string
|
||||
}
|
||||
type ContextQuick struct{}
|
||||
type ContextQuickSubmitComplete struct {
|
||||
ReportID string
|
||||
}
|
||||
type ContextRegisterNotificationsComplete struct {
|
||||
ReportID string
|
||||
}
|
||||
|
|
@ -33,15 +26,12 @@ type ContextStatus struct{}
|
|||
var (
|
||||
Nuisance = buildTemplate("nuisance", "base")
|
||||
NuisanceSubmitComplete = buildTemplate("nuisance-submit-complete", "base")
|
||||
Pool = buildTemplate("pool", "base")
|
||||
Quick = buildTemplate("quick", "base")
|
||||
QuickSubmitComplete = buildTemplate("quick-submit-complete", "base")
|
||||
RegisterNotificationsComplete = buildTemplate("register-notifications-complete", "base")
|
||||
Root = buildTemplate("root", "base")
|
||||
Status = buildTemplate("status", "base")
|
||||
)
|
||||
|
||||
var components = [...]string{"footer", "location-geocode", "location-geocode-header", "map", "map-header", "photo-upload", "photo-upload-header"}
|
||||
var components = [...]string{"footer", "location-geocode", "location-geocode-header", "photo-upload", "photo-upload-header"}
|
||||
|
||||
func buildTemplate(files ...string) *htmlpage.BuiltTemplate {
|
||||
subdir := "public-report"
|
||||
|
|
|
|||
64
public-report/photo-upload.go
Normal file
64
public-report/photo-upload.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/userfile"
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type PhotoUpload struct {
|
||||
Filename string
|
||||
Size int64
|
||||
UUID uuid.UUID
|
||||
}
|
||||
|
||||
func extractPhotoUploads(r *http.Request) (uploads []PhotoUpload, err error) {
|
||||
uploads = make([]PhotoUpload, 0)
|
||||
for _, fheaders := range r.MultipartForm.File {
|
||||
for _, headers := range fheaders {
|
||||
file, err := headers.Open()
|
||||
|
||||
if err != nil {
|
||||
return uploads, fmt.Errorf("Failed to open header: %v", err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
buff := make([]byte, 512)
|
||||
file.Read(buff)
|
||||
|
||||
file.Seek(0, 0)
|
||||
contentType := http.DetectContentType(buff)
|
||||
var sizeBuff bytes.Buffer
|
||||
fileSize, err := sizeBuff.ReadFrom(file)
|
||||
if err != nil {
|
||||
return uploads, fmt.Errorf("Failed to read file: %v", err)
|
||||
}
|
||||
file.Seek(0, 0)
|
||||
contentBuf := bytes.NewBuffer(nil)
|
||||
if _, err := io.Copy(contentBuf, file); err != nil {
|
||||
return uploads, fmt.Errorf("Failed to save file: %v", err)
|
||||
}
|
||||
log.Info().Int64("size", fileSize).Str("filename", headers.Filename).Str("content-type", contentType).Msg("Got an uploaded file")
|
||||
u, err := uuid.NewUUID()
|
||||
if err != nil {
|
||||
return uploads, fmt.Errorf("Failed to create quick report photo uuid", err)
|
||||
}
|
||||
err = userfile.PublicImageFileContentWrite(u, file)
|
||||
if err != nil {
|
||||
return uploads, fmt.Errorf("Failed to write image file to disk: %v", err)
|
||||
}
|
||||
uploads = append(uploads, PhotoUpload{
|
||||
Size: fileSize,
|
||||
Filename: headers.Filename,
|
||||
UUID: u,
|
||||
})
|
||||
}
|
||||
}
|
||||
return uploads, nil
|
||||
}
|
||||
165
public-report/pool.go
Normal file
165
public-report/pool.go
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stephenafamo/bob/dialect/psql"
|
||||
"github.com/stephenafamo/bob/dialect/psql/um"
|
||||
)
|
||||
|
||||
type ContextPool struct {
|
||||
MapboxToken string
|
||||
}
|
||||
type ContextPoolSubmitComplete struct {
|
||||
ReportID string
|
||||
}
|
||||
|
||||
var (
|
||||
Pool = buildTemplate("pool", "base")
|
||||
PoolSubmitComplete = buildTemplate("pool-submit-complete", "base")
|
||||
)
|
||||
|
||||
func getPool(w http.ResponseWriter, r *http.Request) {
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
Pool,
|
||||
ContextPool{
|
||||
MapboxToken: config.MapboxToken,
|
||||
},
|
||||
)
|
||||
}
|
||||
func getPoolSubmitComplete(w http.ResponseWriter, r *http.Request) {
|
||||
report := r.URL.Query().Get("report")
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
PoolSubmitComplete,
|
||||
ContextPoolSubmitComplete{
|
||||
ReportID: report,
|
||||
},
|
||||
)
|
||||
}
|
||||
func postPool(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
|
||||
if err != nil {
|
||||
respondError(w, "Failed to parse form", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
access_comments := r.FormValue("access-comments")
|
||||
access_gate := boolFromForm(r, "access-gate")
|
||||
access_fence := boolFromForm(r, "access-fence")
|
||||
access_locked := boolFromForm(r, "access-locked")
|
||||
access_dog := boolFromForm(r, "access-dog")
|
||||
access_other := boolFromForm(r, "access-other")
|
||||
address := r.FormValue("address")
|
||||
address_country := r.FormValue("address-country")
|
||||
address_postcode := r.FormValue("address-postcode")
|
||||
address_place := r.FormValue("address-place")
|
||||
address_region := r.FormValue("address-region")
|
||||
address_street := r.FormValue("address-street")
|
||||
comments := r.FormValue("comments")
|
||||
has_adult := boolFromForm(r, "has-adult")
|
||||
has_larvae := boolFromForm(r, "has-larvae")
|
||||
has_pupae := boolFromForm(r, "has-pupae")
|
||||
map_zoom_str := r.FormValue("map-zoom")
|
||||
owner_email := r.FormValue("owner-email")
|
||||
owner_name := r.FormValue("owner-name")
|
||||
owner_phone := r.FormValue("owner-phone")
|
||||
reporter_email := r.FormValue("reporter-email")
|
||||
reporter_name := r.FormValue("reporter-name")
|
||||
reporter_phone := r.FormValue("reporter-phone")
|
||||
subscribe := boolFromForm(r, "subscribe")
|
||||
|
||||
map_zoom, err := strconv.ParseFloat(map_zoom_str, 32)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to parse zoom level", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
public_id, err := GenerateReportID()
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create pool report public ID", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
setter := models.PublicreportPoolSetter{
|
||||
AccessComments: omit.From(access_comments),
|
||||
AccessGate: omit.From(access_gate),
|
||||
AccessFence: omit.From(access_fence),
|
||||
AccessLocked: omit.From(access_locked),
|
||||
AccessDog: omit.From(access_dog),
|
||||
AccessOther: omit.From(access_other),
|
||||
Address: omit.From(address),
|
||||
AddressCountry: omit.From(address_country),
|
||||
AddressPostCode: omit.From(address_postcode),
|
||||
AddressPlace: omit.From(address_place),
|
||||
AddressStreet: omit.From(address_street),
|
||||
AddressRegion: omit.From(address_region),
|
||||
Comments: omit.From(comments),
|
||||
Created: omit.From(time.Now()),
|
||||
//H3cell: add later
|
||||
HasAdult: omit.From(has_adult),
|
||||
HasLarvae: omit.From(has_larvae),
|
||||
HasPupae: omit.From(has_pupae),
|
||||
//Location: add later
|
||||
MapZoom: omit.From(map_zoom),
|
||||
OwnerEmail: omit.From(owner_email),
|
||||
OwnerName: omit.From(owner_name),
|
||||
OwnerPhone: omit.From(owner_phone),
|
||||
PublicID: omit.From(public_id),
|
||||
ReporterEmail: omit.From(reporter_email),
|
||||
ReporterName: omit.From(reporter_name),
|
||||
ReporterPhone: omit.From(reporter_phone),
|
||||
Subscribe: omit.From(subscribe),
|
||||
}
|
||||
pool, err := models.PublicreportPools.Insert(&setter).One(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create database record", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
geospatial, err := geospatialFromForm(r)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to handle geospatial data", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if geospatial.Populated {
|
||||
_, err = psql.Update(
|
||||
um.Table("publicreport.pool"),
|
||||
um.SetCol("h3cell").ToArg(geospatial.Cell),
|
||||
um.SetCol("location").To(geospatial.GeometryQuery),
|
||||
um.Where(psql.Quote("id").EQ(psql.Arg(pool.ID))),
|
||||
).Exec(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to insert publicreport.pool", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Info().Int32("id", pool.ID).Str("public_id", pool.PublicID).Msg("Created pool report")
|
||||
photoSetters := make([]*models.PublicreportPoolPhotoSetter, 0)
|
||||
uploads, err := extractPhotoUploads(r)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to extract photo uploads", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
for _, u := range uploads {
|
||||
photoSetters = append(photoSetters, &models.PublicreportPoolPhotoSetter{
|
||||
Filename: omit.From(u.Filename),
|
||||
Size: omit.From(u.Size),
|
||||
UUID: omit.From(u.UUID),
|
||||
})
|
||||
}
|
||||
err = pool.InsertPoolPhotos(r.Context(), db.PGInstance.BobDB, photoSetters...)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create photo records", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, fmt.Sprintf("/pool-submit-complete?report=%s", public_id), http.StatusFound)
|
||||
}
|
||||
117
public-report/quick.go
Normal file
117
public-report/quick.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
|
||||
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
|
||||
"github.com/aarondl/opt/omit"
|
||||
"github.com/aarondl/opt/omitnull"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/stephenafamo/bob/dialect/psql"
|
||||
"github.com/stephenafamo/bob/dialect/psql/um"
|
||||
)
|
||||
|
||||
type ContextQuick struct{}
|
||||
type ContextQuickSubmitComplete struct {
|
||||
ReportID string
|
||||
}
|
||||
|
||||
var (
|
||||
Quick = buildTemplate("quick", "base")
|
||||
QuickSubmitComplete = buildTemplate("quick-submit-complete", "base")
|
||||
)
|
||||
|
||||
func getQuick(w http.ResponseWriter, r *http.Request) {
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
Quick,
|
||||
ContextQuick{},
|
||||
)
|
||||
}
|
||||
func getQuickSubmitComplete(w http.ResponseWriter, r *http.Request) {
|
||||
report := r.URL.Query().Get("report")
|
||||
htmlpage.RenderOrError(
|
||||
w,
|
||||
QuickSubmitComplete,
|
||||
ContextQuickSubmitComplete{
|
||||
ReportID: report,
|
||||
},
|
||||
)
|
||||
}
|
||||
func postQuick(w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
|
||||
if err != nil {
|
||||
respondError(w, "Failed to parse form", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
lat := r.FormValue("latitude")
|
||||
lng := r.FormValue("longitude")
|
||||
comments := r.FormValue("comments")
|
||||
//photos := r.FormValue("photos")
|
||||
|
||||
latitude, err := strconv.ParseFloat(lat, 64)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create parse latitude", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
longitude, err := strconv.ParseFloat(lng, 64)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create parse longitude", err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
u, err := GenerateReportID()
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create quick report public ID", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
c, err := h3utils.GetCell(longitude, latitude, 15)
|
||||
setter := models.PublicreportQuickSetter{
|
||||
Created: omit.From(time.Now()),
|
||||
Comments: omit.From(comments),
|
||||
//Location: omitnull.From(fmt.Sprintf("ST_GeometryFromText(Point(%s %s))", longitude, latitude)),
|
||||
H3cell: omitnull.From(c.String()),
|
||||
PublicID: omit.From(u),
|
||||
ReporterEmail: omit.From(""),
|
||||
ReporterPhone: omit.From(""),
|
||||
}
|
||||
quick, err := models.PublicreportQuicks.Insert(&setter).One(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create database record", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = psql.Update(
|
||||
um.Table("publicreport.quick"),
|
||||
um.SetCol("location").To(fmt.Sprintf("ST_GeometryFromText('Point(%f %f)')", longitude, latitude)),
|
||||
um.Where(psql.Quote("id").EQ(psql.Arg(quick.ID))),
|
||||
).Exec(r.Context(), db.PGInstance.BobDB)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to insert publicreport", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Info().Float64("latitude", latitude).Float64("longitude", longitude).Msg("Got upload")
|
||||
photoSetters := make([]*models.PublicreportQuickPhotoSetter, 0)
|
||||
uploads, err := extractPhotoUploads(r)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to extract photo uploads", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
for _, u := range uploads {
|
||||
photoSetters = append(photoSetters, &models.PublicreportQuickPhotoSetter{
|
||||
Filename: omit.From(u.Filename),
|
||||
Size: omit.From(u.Size),
|
||||
UUID: omit.From(u.UUID),
|
||||
})
|
||||
}
|
||||
err = quick.InsertQuickPhotos(r.Context(), db.PGInstance.BobDB, photoSetters...)
|
||||
if err != nil {
|
||||
respondError(w, "Failed to create photo records", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, fmt.Sprintf("/quick-submit-complete?report=%s", u), http.StatusFound)
|
||||
}
|
||||
28
public-report/routes.go
Normal file
28
public-report/routes.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package publicreport
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func Router() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/", getRoot)
|
||||
r.Get("/nuisance", getNuisance)
|
||||
r.Post("/nuisance-submit", postNuisance)
|
||||
r.Get("/nuisance-submit-complete", getNuisanceSubmitComplete)
|
||||
r.Get("/pool", getPool)
|
||||
r.Post("/pool-submit", postPool)
|
||||
r.Get("/pool-submit-complete", getPoolSubmitComplete)
|
||||
r.Get("/quick", getQuick)
|
||||
r.Post("/quick-submit", postQuick)
|
||||
r.Get("/quick-submit-complete", getQuickSubmitComplete)
|
||||
r.Post("/register-notifications", postRegisterNotifications)
|
||||
r.Get("/register-notifications-complete", getRegisterNotificationsComplete)
|
||||
r.Get("/status", getStatus)
|
||||
localFS := http.Dir("./static")
|
||||
htmlpage.FileServer(r, "/static", localFS, EmbeddedStaticFS, "static")
|
||||
return r
|
||||
}
|
||||
|
|
@ -66,12 +66,16 @@ function displaySuggestions(suggestions) {
|
|||
}
|
||||
// Handle click on a suggestion
|
||||
item.addEventListener('click', function() {
|
||||
addressInput.value = suggestion.properties.name || suggestion.properties.full_address;
|
||||
// Hide the suggestions container
|
||||
setLocationInputs(suggestion);
|
||||
suggestionsContainer.classList.add('d-none');
|
||||
|
||||
// Display the selected location details
|
||||
displaySelectedLocation(suggestion);
|
||||
setMapMarker(suggestion.geometry.coordinates);
|
||||
const locationSelected = new CustomEvent("locationselected", {
|
||||
detail: {
|
||||
coordinates: suggestion.geometry.coordinates,
|
||||
},
|
||||
});
|
||||
suggestionsContainer.dispatchEvent(locationSelected);
|
||||
});
|
||||
|
||||
suggestionsContainer.appendChild(item);
|
||||
|
|
@ -155,18 +159,45 @@ function onAddressInput() {
|
|||
}, 300);
|
||||
}
|
||||
|
||||
function setLocationInputs(suggestion) {
|
||||
let address = document.getElementById('address');
|
||||
let country = document.getElementById('address-country');
|
||||
let latitude = document.getElementById('latitude');
|
||||
let longitude = document.getElementById('longitude');
|
||||
let latlngAccuracyType = document.getElementById('latlng-accuracy-type');
|
||||
let postcode = document.getElementById('address-postcode');
|
||||
let place = document.getElementById('address-place');
|
||||
let region = document.getElementById('address-region');
|
||||
let street = document.getElementById('address-street');
|
||||
|
||||
// Extract context data from properties
|
||||
const props = suggestion.properties;
|
||||
const context = props.context || {};
|
||||
|
||||
// Populate structured fields
|
||||
address.value = props.full_address;
|
||||
country.value = context.country.name;
|
||||
latitude.value = props.coordinates.latitude;
|
||||
longitude.value = props.coordinates.longitude;
|
||||
latlngAccuracyType.value = props.coordinates.accuracy;
|
||||
postcode.value = context.postcode.name;
|
||||
place.value = context.place.name;
|
||||
region.value = context.region.name;
|
||||
street.value = context.country.name;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const addressInput = document.getElementById('addressInput');
|
||||
const address = document.getElementById('address');
|
||||
const suggestionsContainer = document.getElementById('suggestions');
|
||||
const locationDetails = document.getElementById('locationDetails');
|
||||
|
||||
|
||||
// Listen for input changes
|
||||
addressInput.addEventListener('input', onAddressInput);
|
||||
address.addEventListener('input', onAddressInput);
|
||||
|
||||
// Close suggestions when clicking outside
|
||||
document.addEventListener('click', function(event) {
|
||||
if (!addressInput.contains(event.target) && !suggestionsContainer.contains(event.target)) {
|
||||
if (!address.contains(event.target) && !suggestionsContainer.contains(event.target)) {
|
||||
suggestionsContainer.classList.add('d-none');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,18 @@
|
|||
{{define "location-geocode"}}
|
||||
<!-- Hidden fields for location data -->
|
||||
<input type="hidden" id="address-country" name="address-country"/>
|
||||
<input type="hidden" id="address-postcode" name="address-postcode"/>
|
||||
<input type="hidden" id="address-place" name="address-place"/>
|
||||
<input type="hidden" id="address-region" name="address-region"/>
|
||||
<input type="hidden" id="address-street" name="address-street"/>
|
||||
<input type="hidden" id="latitude" name="latitude"/>
|
||||
<input type="hidden" id="longitude" name="longitude"/>
|
||||
<input type="hidden" id="latlng-accuracy-type" name="latlng-accuracy-type"/>
|
||||
<input type="hidden" id="latlng-accuracy-value" name="latlng-accuracy-value"/>
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-4">Address Search</h2>
|
||||
<div class="mb-3 position-relative">
|
||||
<label for="addressInput" class="form-label">Enter address</label>
|
||||
<input type="text" class="form-control" id="addressInput"
|
||||
<input type="text" class="form-control" id="address" name="address"
|
||||
placeholder="Start typing an address (min 3 characters)">
|
||||
<div id="suggestions" class="suggestions-container list-group d-none"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,144 +1,2 @@
|
|||
{{define "map-header"}}
|
||||
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
|
||||
<link href='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css' rel='stylesheet' />
|
||||
<script>
|
||||
var map = null;
|
||||
var markers = [];
|
||||
function setMapMarker(coords) {
|
||||
console.log("Setting map marker", coords);
|
||||
map.jumpTo({
|
||||
center: coords,
|
||||
zoom: 14,
|
||||
});
|
||||
markers.forEach((marker) => marker.remove());
|
||||
addMarker(coords);
|
||||
}
|
||||
function addMarker(coords) {
|
||||
const marker = new mapboxgl.Marker({
|
||||
color: "#FF0000",
|
||||
draggable: true
|
||||
}).setLngLat(coords).addTo(map);
|
||||
marker.on('dragend', onMapMarkerDragEnd(marker));
|
||||
markers.push(marker);
|
||||
}
|
||||
function onMapMarkerDragEnd(marker) {
|
||||
return function() {
|
||||
const lngLat = marker.getLngLat();
|
||||
displaySelectedCoordinates(lngLat);
|
||||
reverseGeocode(lngLat);
|
||||
}
|
||||
}
|
||||
function displaySelectedCoordinates(lngLat) {
|
||||
const gpsDisplay = document.getElementById("gps-display");
|
||||
gpsDisplay.classList.remove('d-none');
|
||||
longitude.textContent = lngLat.lng;
|
||||
latitude.textContent = lngLat.lat;
|
||||
}
|
||||
async function reverseGeocode(lngLat) {
|
||||
const MAPBOX_ACCESS_TOKEN = '{{.MapboxToken}}';
|
||||
const url = `https://api.mapbox.com/search/geocode/v6/reverse?longitude=${lngLat.lng}&latitude=${lngLat.lat}&access_token=${MAPBOX_ACCESS_TOKEN}`
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
console.log("reverse geocoded to", data);
|
||||
if (data.features.length == 0) {
|
||||
console.warn("No results for reverse geocode");
|
||||
return;
|
||||
}
|
||||
const match = data.features[0];
|
||||
displaySelectedLocation(match);
|
||||
}
|
||||
function onLoadMap() {
|
||||
const MAPBOX_ACCESS_TOKEN = '{{.MapboxToken}}';
|
||||
console.log("Setting up the map...");
|
||||
mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN;
|
||||
map = new mapboxgl.Map({
|
||||
container: "map",
|
||||
center: {
|
||||
lat: 36.2,
|
||||
lng: -119.2
|
||||
},
|
||||
style: 'mapbox://styles/mapbox/streets-v12', // style URL
|
||||
zoom: 15,
|
||||
});
|
||||
map.addControl(new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true
|
||||
},
|
||||
trackUserLocation: true,
|
||||
showUserHeading: true
|
||||
}));
|
||||
map.on("load", function() {
|
||||
console.log("Map post-load...");
|
||||
updateMapWithLocation(map);
|
||||
console.log("Map post-load done.");
|
||||
});
|
||||
console.log("Map init done.");
|
||||
}
|
||||
function updateMapWithLocation(map) {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
// on success
|
||||
function(position) {
|
||||
console.log("Got location", position);
|
||||
map.jumpTo({
|
||||
center: {
|
||||
lng: position.coords.longitude,
|
||||
lat: position.coords.latitude,
|
||||
},
|
||||
zoom: 14,
|
||||
});
|
||||
addMarker([
|
||||
position.coords.longitude,
|
||||
position.coords.latitude,
|
||||
]);
|
||||
},
|
||||
// on error
|
||||
function(error) {
|
||||
switch (error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
console.log("permission denied");
|
||||
break;
|
||||
case error.POSITION_UNAVAILABLE:
|
||||
console.log("location unavailable");
|
||||
break;
|
||||
case error.TIMEOUT:
|
||||
console.log("request timed out");
|
||||
break;
|
||||
}
|
||||
},
|
||||
// options
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
maximumAge: 0
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log("location is not supported");
|
||||
}
|
||||
}
|
||||
window.addEventListener("load", onLoadMap);
|
||||
</script>
|
||||
<style>
|
||||
.map-container {
|
||||
background-color: #e9ecef;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
||||
height: 500px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
#map {
|
||||
height: 500px;
|
||||
width:100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#map img {
|
||||
max-width: none;
|
||||
min-width: 0px;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{{define "photo-upload"}}
|
||||
<label for="photos" class="form-label fw-bold">Photos (Optional)</label>
|
||||
<div class="photo-upload-area">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-camera mb-2" viewBox="0 0 16 16">
|
||||
<path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/>
|
||||
|
|
|
|||
115
public-report/template/pool-submit-complete.html
Normal file
115
public-report/template/pool-submit-complete.html
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
{{template "base.html" .}}
|
||||
|
||||
{{define "title"}}Nuisance Submission Complete{{end}}
|
||||
{{define "extraheader"}}
|
||||
<style>
|
||||
</style>
|
||||
<script>
|
||||
</script>
|
||||
{{end}}
|
||||
{{define "content"}}
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-7">
|
||||
<!-- Confirmation Card -->
|
||||
<div class="card shadow-sm border-info mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h3 class="my-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="bi bi-bell-fill me-2" viewBox="0 0 16 16">
|
||||
<path d="M8 16a2 2 0 0 0 2-2H6a2 2 0 0 0 2 2zm.995-14.901a1 1 0 1 0-1.99 0A5.002 5.002 0 0 0 3 6c0 1.098-.5 6-2 7h14c-1.5-1-2-5.902-2-7 0-2.42-1.72-4.44-4.005-4.901z"/>
|
||||
</svg>
|
||||
Pool Report Complete
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body p-4 text-center">
|
||||
<div class="mb-4">
|
||||
<div class="display-1 text-info mb-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" fill="currentColor" class="bi bi-check-circle-fill" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h4 class="mb-3">Thank You!</h4>
|
||||
<p class="lead">Your report has been successfully submitted.</p>
|
||||
<div class="alert alert-secondary py-3 mt-3">
|
||||
<strong>Report ID:</strong>
|
||||
<span class="fs-5">{{.ReportID}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<!-- What to Expect Section -->
|
||||
<div class="text-start mb-4">
|
||||
<h5>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-info-circle me-2" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
|
||||
</svg>
|
||||
What to Expect
|
||||
</h5>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item bg-transparent">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope-check me-2 text-success" viewBox="0 0 16 16">
|
||||
<path d="M2 2a2 2 0 0 0-2 2v8.01A2 2 0 0 0 2 14h5.5a.5.5 0 0 0 0-1H2a1 1 0 0 1-.966-.741l5.64-3.471L8 9.583l7-4.2V8.5a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2H2Zm3.708 6.208L1 11.105V5.383l4.708 2.825ZM1 4.217V4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v.217l-7 4.2-7-4.2Z"/>
|
||||
<path d="M16 12.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Zm-1.993-1.679a.5.5 0 0 0-.686.172l-1.17 1.95-.547-.547a.5.5 0 0 0-.708.708l.774.773a.75.75 0 0 0 1.174-.144l1.335-2.226a.5.5 0 0 0-.172-.686Z"/>
|
||||
</svg>
|
||||
A confirmation message has been sent to your contact information.
|
||||
</li>
|
||||
<li class="list-group-item bg-transparent">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check me-2 text-success" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M10.854 7.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708 0z"/>
|
||||
<path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
|
||||
<path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
|
||||
</svg>
|
||||
You will receive updates when:
|
||||
<ul class="mt-2">
|
||||
<li>Your report is assigned to a specialist</li>
|
||||
<li>A site visit is scheduled</li>
|
||||
<li>Treatment or remediation is completed</li>
|
||||
<li>The case is resolved</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="list-group-item bg-transparent">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search me-2 text-success" viewBox="0 0 16 16">
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||
</svg>
|
||||
You can check your report status anytime using your Report ID.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Buttons -->
|
||||
<div class="mt-4">
|
||||
<a href="/check-report-status" class="btn btn-outline-primary me-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search me-1" viewBox="0 0 16 16">
|
||||
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||
</svg>
|
||||
Check Report Status
|
||||
</a>
|
||||
<a href="/" class="btn btn-outline-secondary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-house me-1" viewBox="0 0 16 16">
|
||||
<path d="M8.707 1.5a1 1 0 0 0-1.414 0L.646 8.146a.5.5 0 0 0 .708.708L2 8.207V13.5A1.5 1.5 0 0 0 3.5 15h9a1.5 1.5 0 0 0 1.5-1.5V8.207l.646.647a.5.5 0 0 0 .708-.708L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.707 1.5ZM13 7.207V13.5a.5.5 0 0 1-.5.5h-9a.5.5 0 0 1-.5-.5V7.207l5-5 5 5Z"/>
|
||||
</svg>
|
||||
Return to Home
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Optional: Additional Information Section -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-question-circle me-2" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/>
|
||||
</svg>
|
||||
Need Help?
|
||||
</h5>
|
||||
<p>If you need to update your contact information or have questions about your report, please contact our Mosquito Control Unit at <strong>(123) 456-7890</strong> or <a href="mailto:mosquito@example.gov">mosquito@example.gov</a> and reference your Report ID.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
{{define "title"}}Green Pool{{end}}
|
||||
{{define "extraheader"}}
|
||||
{{template "location-geocode-header" .}}
|
||||
{{template "map-header" .}}
|
||||
<script src='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.js'></script>
|
||||
<link href='https://api.mapbox.com/mapbox-gl-js/v3.17.0-beta.1/mapbox-gl.css' rel='stylesheet' />
|
||||
{{template "photo-upload-header"}}
|
||||
<style>
|
||||
.district-logo {
|
||||
|
|
@ -30,6 +31,48 @@
|
|||
margin-bottom: 1rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.map-container {
|
||||
background-color: #e9ecef;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
||||
height: 500px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
#map {
|
||||
height: 500px;
|
||||
width:100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#map img {
|
||||
max-width: none;
|
||||
min-width: 0px;
|
||||
height: auto;
|
||||
}
|
||||
.photo-upload-area {
|
||||
border: 2px dashed #ccc;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.photo-preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.photo-preview img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.section-heading {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
|
|
@ -53,6 +96,232 @@
|
|||
margin-top: 2rem;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function handlePhotoSelection() {
|
||||
const photoInput = document.getElementById('photos');
|
||||
const photoPreviewContainer = document.getElementById('photoPreviewContainer');
|
||||
|
||||
// Clear previous previews
|
||||
photoPreviewContainer.innerHTML = '';
|
||||
|
||||
// Check if files were selected
|
||||
if (photoInput.files && photoInput.files.length > 0) {
|
||||
// Loop through selected files
|
||||
Array.from(photoInput.files).forEach((file, index) => {
|
||||
console.log("Handling", index, file);
|
||||
if (!file.type.match('image.*')) {
|
||||
console.log("Skipping non-image file", file.type);
|
||||
return; // Skip non-image files
|
||||
}
|
||||
|
||||
// Create preview container
|
||||
const previewContainer = document.createElement('div');
|
||||
previewContainer.className = 'position-relative m-1';
|
||||
|
||||
// Create image preview
|
||||
const img = document.createElement('img');
|
||||
img.className = 'img-thumbnail';
|
||||
img.style.width = '100px';
|
||||
img.style.height = '100px';
|
||||
img.style.objectFit = 'cover';
|
||||
|
||||
// Read file and set preview
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
img.src = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
// Create remove button
|
||||
const removeBtn = document.createElement('button');
|
||||
removeBtn.type = 'button';
|
||||
removeBtn.className = 'btn btn-sm btn-danger position-absolute top-0 end-0';
|
||||
removeBtn.innerHTML = '×';
|
||||
removeBtn.style.fontSize = '10px';
|
||||
removeBtn.style.padding = '0 5px';
|
||||
|
||||
// Handle remove button click
|
||||
removeBtn.addEventListener('click', function() {
|
||||
// Create a new FileList without this file
|
||||
// Since FileList is immutable, we need to reset the input
|
||||
// This is a bit tricky and requires recreating the input
|
||||
previewContainer.remove();
|
||||
|
||||
// If this was the last image, clear the input entirely
|
||||
if (photoPreviewContainer.children.length === 0) {
|
||||
photoInput.value = '';
|
||||
}
|
||||
// Note: Unfortunately, selectively removing files from a FileList isn't straightforward
|
||||
// In a real implementation, we might track selected files in an array and recreate the input
|
||||
});
|
||||
|
||||
// Add elements to the preview container
|
||||
previewContainer.appendChild(img);
|
||||
previewContainer.appendChild(removeBtn);
|
||||
photoPreviewContainer.appendChild(previewContainer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Elements
|
||||
const photoInput = document.getElementById('photos');
|
||||
|
||||
// Handle photo selection
|
||||
photoInput.addEventListener('change', handlePhotoSelection);
|
||||
|
||||
// Handle drag and drop
|
||||
const photoDropArea = document.getElementById('photoDropArea');
|
||||
|
||||
photoDropArea.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
photoDropArea.style.backgroundColor = '#e9ecef';
|
||||
});
|
||||
|
||||
photoDropArea.addEventListener('dragleave', function() {
|
||||
photoDropArea.style.backgroundColor = '#f8f9fa';
|
||||
});
|
||||
|
||||
photoDropArea.addEventListener('drop', function(e) {
|
||||
e.preventDefault();
|
||||
photoDropArea.style.backgroundColor = '#f8f9fa';
|
||||
|
||||
if (e.dataTransfer.files.length) {
|
||||
handleFiles(e.dataTransfer.files);
|
||||
}
|
||||
});
|
||||
onLoadMap();
|
||||
const suggestionsContainer = document.getElementById('suggestions');
|
||||
suggestionsContainer.addEventListener("locationselected", (e) => {
|
||||
setMapMarker(e.detail.coordinates);
|
||||
});
|
||||
});
|
||||
var map = null;
|
||||
var markers = [];
|
||||
function setMapMarker(coords) {
|
||||
console.log("Setting map marker", coords);
|
||||
map.jumpTo({
|
||||
center: coords,
|
||||
zoom: 14,
|
||||
});
|
||||
markers.forEach((marker) => marker.remove());
|
||||
addMarker(coords);
|
||||
}
|
||||
function addMarker(coords) {
|
||||
const marker = new mapboxgl.Marker({
|
||||
color: "#FF0000",
|
||||
draggable: true
|
||||
}).setLngLat(coords).addTo(map);
|
||||
marker.on('dragend', onMapMarkerDragEnd(marker));
|
||||
markers.push(marker);
|
||||
}
|
||||
function onMapMarkerDragEnd(marker) {
|
||||
return function() {
|
||||
const lngLat = marker.getLngLat();
|
||||
//displaySelectedCoordinates(lngLat);
|
||||
reverseGeocode(lngLat);
|
||||
}
|
||||
}
|
||||
function displaySelectedCoordinates(lngLat) {
|
||||
const gpsDisplay = document.getElementById("gps-display");
|
||||
gpsDisplay.classList.remove('d-none');
|
||||
longitude.textContent = lngLat.lng;
|
||||
latitude.textContent = lngLat.lat;
|
||||
}
|
||||
async function reverseGeocode(lngLat) {
|
||||
const MAPBOX_ACCESS_TOKEN = '{{.MapboxToken}}';
|
||||
const url = `https://api.mapbox.com/search/geocode/v6/reverse?longitude=${lngLat.lng}&latitude=${lngLat.lat}&access_token=${MAPBOX_ACCESS_TOKEN}`
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
console.log("reverse geocoded to", data);
|
||||
if (data.features.length == 0) {
|
||||
console.warn("No results for reverse geocode");
|
||||
return;
|
||||
}
|
||||
const match = data.features[0];
|
||||
displaySelectedLocation(match);
|
||||
setLocationInputs(match);
|
||||
}
|
||||
function onLoadMap() {
|
||||
const MAPBOX_ACCESS_TOKEN = '{{.MapboxToken}}';
|
||||
let mapZoom = document.getElementById('map-zoom');
|
||||
console.log("Setting up the map...");
|
||||
mapboxgl.accessToken = MAPBOX_ACCESS_TOKEN;
|
||||
map = new mapboxgl.Map({
|
||||
container: "map",
|
||||
center: {
|
||||
lat: 36.2,
|
||||
lng: -119.2
|
||||
},
|
||||
style: 'mapbox://styles/mapbox/streets-v12', // style URL
|
||||
zoom: 15,
|
||||
});
|
||||
map.addControl(new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true
|
||||
},
|
||||
trackUserLocation: true,
|
||||
showUserHeading: true
|
||||
}));
|
||||
map.addControl(new mapboxgl.NavigationControl());
|
||||
map.on("load", function() {
|
||||
console.log("Map post-load...");
|
||||
updateMapWithLocation(map);
|
||||
console.log("Map post-load done.");
|
||||
});
|
||||
map.on("zoomend", function(e) {
|
||||
mapZoom.value = e.target.getZoom();
|
||||
});
|
||||
console.log("Map init done.");
|
||||
}
|
||||
function updateMapWithLocation(map) {
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
// on success
|
||||
function(position) {
|
||||
console.log("Got location", position);
|
||||
map.jumpTo({
|
||||
center: {
|
||||
lng: position.coords.longitude,
|
||||
lat: position.coords.latitude,
|
||||
},
|
||||
zoom: 14,
|
||||
});
|
||||
addMarker([
|
||||
position.coords.longitude,
|
||||
position.coords.latitude,
|
||||
]);
|
||||
reverseGeocode({
|
||||
lat: position.coords.latitude,
|
||||
lng: position.coords.longitude,
|
||||
});
|
||||
},
|
||||
// on error
|
||||
function(error) {
|
||||
switch (error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
console.log("permission denied");
|
||||
break;
|
||||
case error.POSITION_UNAVAILABLE:
|
||||
console.log("location unavailable");
|
||||
break;
|
||||
case error.TIMEOUT:
|
||||
console.log("request timed out");
|
||||
break;
|
||||
}
|
||||
},
|
||||
// options
|
||||
{
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
maximumAge: 0
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log("location is not supported");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{define "content"}}
|
||||
<!-- Main Content -->
|
||||
|
|
@ -77,7 +346,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Report Form -->
|
||||
<form id="greenPoolForm">
|
||||
<form id="greenPoolForm" action="/pool-submit" method="POST" enctype="multipart/form-data">
|
||||
<!-- Photo Upload Section -->
|
||||
<div class="form-section">
|
||||
<div class="section-heading">
|
||||
|
|
@ -86,9 +355,10 @@
|
|||
<span class="optional-label">optional</span>
|
||||
</div>
|
||||
<p class="mb-3">Photos help us identify the severity of the issue and may contain location data that can help us find the source.</p>
|
||||
|
||||
<div class="mb-4">
|
||||
{{template "photo-upload"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Location Section -->
|
||||
<div class="form-section">
|
||||
|
|
@ -119,6 +389,7 @@
|
|||
<div class="map-container">
|
||||
<div id="map"></div>
|
||||
</div>
|
||||
<input type="hidden" id="map-zoom" name="map-zoom"/>
|
||||
</div>
|
||||
|
||||
<!-- Source Details Section -->
|
||||
|
|
@ -132,8 +403,8 @@
|
|||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="duration" class="form-label">How long has this source been present?</label>
|
||||
<select class="form-select" id="duration">
|
||||
<option value="">I don't know</option>
|
||||
<select class="form-select" id="duration" name="source-duration">
|
||||
<option value="none">I don't know</option>
|
||||
<option value="less-than-week">Less than a week</option>
|
||||
<option value="1-2-weeks">1-2 weeks</option>
|
||||
<option value="2-4-weeks">2-4 weeks</option>
|
||||
|
|
@ -145,20 +416,20 @@
|
|||
<div class="col-md-6">
|
||||
<label class="form-label d-block">Have you observed any of the following? <a href="#" data-bs-toggle="modal" data-bs-target="#larvaeInfoModal"><i class="bi bi-question-circle small ms-1"></i></a></label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="larvae">
|
||||
<input class="form-check-input" type="checkbox" id="larvae" name="has-larvae">
|
||||
<label class="form-check-label" for="larvae">
|
||||
Larvae (wigglers) in water
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="pupae">
|
||||
<input class="form-check-input" type="checkbox" id="pupae" name="has-pupae">
|
||||
<label class="form-check-label" for="pupae">
|
||||
Pupae (tumblers) in water
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="adultMosquitoes">
|
||||
<label class="form-check-label" for="adultMosquitoes">
|
||||
<input class="form-check-input" type="checkbox" id="adult" name="has-adult">
|
||||
<label class="form-check-label" for="adult">
|
||||
Adult mosquitoes near the source
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -177,8 +448,8 @@
|
|||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-12">
|
||||
<label for="accessInfo" class="form-label">How can the source be accessed?</label>
|
||||
<textarea class="form-control" id="accessInfo" rows="3" placeholder="Example: The pool is in the backyard, which can be accessed through a side gate on the right side of the house."></textarea>
|
||||
<label for="access-comments" class="form-label">How can the source be accessed?</label>
|
||||
<textarea class="form-control" id="access-comments" name="access-comments" rows="3" placeholder="Example: The pool is in the backyard, which can be accessed through a side gate on the right side of the house."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -188,28 +459,28 @@
|
|||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="gate">
|
||||
<input class="form-check-input" type="checkbox" id="gate" name="access-gate">
|
||||
<label class="form-check-label" for="gate">Gate</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="fence">
|
||||
<input class="form-check-input" type="checkbox" id="fence" name="access-fence">
|
||||
<label class="form-check-label" for="fence">Fence</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="lockedEntrance">
|
||||
<label class="form-check-label" for="lockedEntrance">Locked entrance</label>
|
||||
<input class="form-check-input" type="checkbox" id="locked" name="access-locked">
|
||||
<label class="form-check-label" for="locked">Locked entrance</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="dogs">
|
||||
<input class="form-check-input" type="checkbox" id="dogs" name="access-dog">
|
||||
<label class="form-check-label" for="dogs">Dogs/pets</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="otherObstacle">
|
||||
<label class="form-check-label" for="otherObstacle">Other obstacle</label>
|
||||
<input class="form-check-input" type="checkbox" id="access-other" name="access-other">
|
||||
<label class="form-check-label" for="access-other">Other obstacle</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -229,16 +500,16 @@
|
|||
<h5 class="mb-3">Property Owner Information (if known)</h5>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="ownerName" class="form-label">Owner Name</label>
|
||||
<input type="text" class="form-control" id="ownerName">
|
||||
<label for="owner-name" class="form-label">Owner Name</label>
|
||||
<input type="text" class="form-control" id="owner-name" name="owner-name">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="ownerPhone" class="form-label">Owner Phone</label>
|
||||
<input type="tel" class="form-control" id="ownerPhone">
|
||||
<label for="owner-phone" class="form-label">Owner Phone</label>
|
||||
<input type="tel" class="form-control" id="owner-phone" name="owner-phone">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label for="ownerEmail" class="form-label">Owner Email</label>
|
||||
<input type="email" class="form-control" id="ownerEmail">
|
||||
<label for="owner-email" class="form-label">Owner Email</label>
|
||||
<input type="email" class="form-control" id="owner-email" name="owner-email">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -246,21 +517,21 @@
|
|||
<h5 class="mb-3">Your Contact Information (for updates)</h5>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="reporterName" class="form-label">Your Name</label>
|
||||
<input type="text" class="form-control" id="reporterName">
|
||||
<label for="reporter-name" class="form-label">Your Name</label>
|
||||
<input type="text" class="form-control" id="reporter-name" name="reporter-name">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="reporterPhone" class="form-label">Your Phone</label>
|
||||
<input type="tel" class="form-control" id="reporterPhone">
|
||||
<label for="reporter-phone" class="form-label">Your Phone</label>
|
||||
<input type="tel" class="form-control" id="reporter-phone" name="reporter-phone">
|
||||
</div>
|
||||
<div class="col-md-12 mb-3">
|
||||
<label for="reporterEmail" class="form-label">Your Email</label>
|
||||
<input type="email" class="form-control" id="reporterEmail">
|
||||
<label for="reporter-email" class="form-label">Your Email</label>
|
||||
<input type="email" class="form-control" id="reporter-email" name="reporter-email">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="receiveUpdates" checked>
|
||||
<label class="form-check-label" for="receiveUpdates">
|
||||
<input class="form-check-input" type="checkbox" id="subscribe" name="subscribe" checked>
|
||||
<label class="form-check-label" for="subscribe">
|
||||
I would like to receive updates on this report
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -279,8 +550,8 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label for="additionalInfo" class="form-label">Additional Details</label>
|
||||
<textarea class="form-control" id="additionalInfo" rows="4" placeholder="Example: The house appears to be vacant. There is algae growth in the pool. I've noticed increased mosquito activity in the evenings."></textarea>
|
||||
<label for="comments" class="form-label">Additional Details</label>
|
||||
<textarea class="form-control" id="comments" name="comments" rows="4" placeholder="Example: The house appears to be vacant. There is algae growth in the pool. I've noticed increased mosquito activity in the evenings."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue