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
|
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
|
// Relationship Contexts for publicreport.nuisance
|
||||||
publicreportNuisanceWithParentsCascadingCtx = newContextual[bool]("publicreportNuisanceWithParentsCascading")
|
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
|
// Relationship Contexts for publicreport.quick
|
||||||
publicreportQuickWithParentsCascadingCtx = newContextual[bool]("publicreportQuickWithParentsCascading")
|
publicreportQuickWithParentsCascadingCtx = newContextual[bool]("publicreportQuickWithParentsCascading")
|
||||||
publicreportQuickRelQuickPhotosCtx = newContextual[bool]("publicreport.quick.publicreport.quick_photo.publicreport.quick_photo.quick_photo_quick_id_fkey")
|
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
|
baseOauthTokenMods OauthTokenModSlice
|
||||||
baseOrganizationMods OrganizationModSlice
|
baseOrganizationMods OrganizationModSlice
|
||||||
basePublicreportNuisanceMods PublicreportNuisanceModSlice
|
basePublicreportNuisanceMods PublicreportNuisanceModSlice
|
||||||
|
basePublicreportPoolMods PublicreportPoolModSlice
|
||||||
|
basePublicreportPoolPhotoMods PublicreportPoolPhotoModSlice
|
||||||
basePublicreportQuickMods PublicreportQuickModSlice
|
basePublicreportQuickMods PublicreportQuickModSlice
|
||||||
basePublicreportQuickPhotoMods PublicreportQuickPhotoModSlice
|
basePublicreportQuickPhotoMods PublicreportQuickPhotoModSlice
|
||||||
baseRasterColumnMods RasterColumnModSlice
|
baseRasterColumnMods RasterColumnModSlice
|
||||||
|
|
@ -2420,6 +2422,96 @@ func (f *Factory) FromExistingPublicreportNuisance(m *models.PublicreportNuisanc
|
||||||
return o
|
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 {
|
func (f *Factory) NewPublicreportQuick(mods ...PublicreportQuickMod) *PublicreportQuickTemplate {
|
||||||
return f.NewPublicreportQuickWithContext(context.Background(), mods...)
|
return f.NewPublicreportQuickWithContext(context.Background(), mods...)
|
||||||
}
|
}
|
||||||
|
|
@ -3009,6 +3101,22 @@ func (f *Factory) AddBasePublicreportNuisanceMod(mods ...PublicreportNuisanceMod
|
||||||
f.basePublicreportNuisanceMods = append(f.basePublicreportNuisanceMods, mods...)
|
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() {
|
func (f *Factory) ClearBasePublicreportQuickMods() {
|
||||||
f.basePublicreportQuickMods = nil
|
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]]
|
Notifications joinSet[notificationJoins[Q]]
|
||||||
OauthTokens joinSet[oauthTokenJoins[Q]]
|
OauthTokens joinSet[oauthTokenJoins[Q]]
|
||||||
Organizations joinSet[organizationJoins[Q]]
|
Organizations joinSet[organizationJoins[Q]]
|
||||||
|
PublicreportPools joinSet[publicreportPoolJoins[Q]]
|
||||||
|
PublicreportPoolPhotos joinSet[publicreportPoolPhotoJoins[Q]]
|
||||||
PublicreportQuicks joinSet[publicreportQuickJoins[Q]]
|
PublicreportQuicks joinSet[publicreportQuickJoins[Q]]
|
||||||
PublicreportQuickPhotos joinSet[publicreportQuickPhotoJoins[Q]]
|
PublicreportQuickPhotos joinSet[publicreportQuickPhotoJoins[Q]]
|
||||||
Users joinSet[userJoins[Q]]
|
Users joinSet[userJoins[Q]]
|
||||||
|
|
@ -123,6 +125,8 @@ func getJoins[Q dialect.Joinable]() joins[Q] {
|
||||||
Notifications: buildJoinSet[notificationJoins[Q]](Notifications.Columns, buildNotificationJoins),
|
Notifications: buildJoinSet[notificationJoins[Q]](Notifications.Columns, buildNotificationJoins),
|
||||||
OauthTokens: buildJoinSet[oauthTokenJoins[Q]](OauthTokens.Columns, buildOauthTokenJoins),
|
OauthTokens: buildJoinSet[oauthTokenJoins[Q]](OauthTokens.Columns, buildOauthTokenJoins),
|
||||||
Organizations: buildJoinSet[organizationJoins[Q]](Organizations.Columns, buildOrganizationJoins),
|
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),
|
PublicreportQuicks: buildJoinSet[publicreportQuickJoins[Q]](PublicreportQuicks.Columns, buildPublicreportQuickJoins),
|
||||||
PublicreportQuickPhotos: buildJoinSet[publicreportQuickPhotoJoins[Q]](PublicreportQuickPhotos.Columns, buildPublicreportQuickPhotoJoins),
|
PublicreportQuickPhotos: buildJoinSet[publicreportQuickPhotoJoins[Q]](PublicreportQuickPhotos.Columns, buildPublicreportQuickPhotoJoins),
|
||||||
Users: buildJoinSet[userJoins[Q]](Users.Columns, buildUserJoins),
|
Users: buildJoinSet[userJoins[Q]](Users.Columns, buildUserJoins),
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ type preloaders struct {
|
||||||
Notification notificationPreloader
|
Notification notificationPreloader
|
||||||
OauthToken oauthTokenPreloader
|
OauthToken oauthTokenPreloader
|
||||||
Organization organizationPreloader
|
Organization organizationPreloader
|
||||||
|
PublicreportPool publicreportPoolPreloader
|
||||||
|
PublicreportPoolPhoto publicreportPoolPhotoPreloader
|
||||||
PublicreportQuick publicreportQuickPreloader
|
PublicreportQuick publicreportQuickPreloader
|
||||||
PublicreportQuickPhoto publicreportQuickPhotoPreloader
|
PublicreportQuickPhoto publicreportQuickPhotoPreloader
|
||||||
User userPreloader
|
User userPreloader
|
||||||
|
|
@ -100,6 +102,8 @@ func getPreloaders() preloaders {
|
||||||
Notification: buildNotificationPreloader(),
|
Notification: buildNotificationPreloader(),
|
||||||
OauthToken: buildOauthTokenPreloader(),
|
OauthToken: buildOauthTokenPreloader(),
|
||||||
Organization: buildOrganizationPreloader(),
|
Organization: buildOrganizationPreloader(),
|
||||||
|
PublicreportPool: buildPublicreportPoolPreloader(),
|
||||||
|
PublicreportPoolPhoto: buildPublicreportPoolPhotoPreloader(),
|
||||||
PublicreportQuick: buildPublicreportQuickPreloader(),
|
PublicreportQuick: buildPublicreportQuickPreloader(),
|
||||||
PublicreportQuickPhoto: buildPublicreportQuickPhotoPreloader(),
|
PublicreportQuickPhoto: buildPublicreportQuickPhotoPreloader(),
|
||||||
User: buildUserPreloader(),
|
User: buildUserPreloader(),
|
||||||
|
|
@ -151,6 +155,8 @@ type thenLoaders[Q orm.Loadable] struct {
|
||||||
Notification notificationThenLoader[Q]
|
Notification notificationThenLoader[Q]
|
||||||
OauthToken oauthTokenThenLoader[Q]
|
OauthToken oauthTokenThenLoader[Q]
|
||||||
Organization organizationThenLoader[Q]
|
Organization organizationThenLoader[Q]
|
||||||
|
PublicreportPool publicreportPoolThenLoader[Q]
|
||||||
|
PublicreportPoolPhoto publicreportPoolPhotoThenLoader[Q]
|
||||||
PublicreportQuick publicreportQuickThenLoader[Q]
|
PublicreportQuick publicreportQuickThenLoader[Q]
|
||||||
PublicreportQuickPhoto publicreportQuickPhotoThenLoader[Q]
|
PublicreportQuickPhoto publicreportQuickPhotoThenLoader[Q]
|
||||||
User userThenLoader[Q]
|
User userThenLoader[Q]
|
||||||
|
|
@ -196,6 +202,8 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] {
|
||||||
Notification: buildNotificationThenLoader[Q](),
|
Notification: buildNotificationThenLoader[Q](),
|
||||||
OauthToken: buildOauthTokenThenLoader[Q](),
|
OauthToken: buildOauthTokenThenLoader[Q](),
|
||||||
Organization: buildOrganizationThenLoader[Q](),
|
Organization: buildOrganizationThenLoader[Q](),
|
||||||
|
PublicreportPool: buildPublicreportPoolThenLoader[Q](),
|
||||||
|
PublicreportPoolPhoto: buildPublicreportPoolPhotoThenLoader[Q](),
|
||||||
PublicreportQuick: buildPublicreportQuickThenLoader[Q](),
|
PublicreportQuick: buildPublicreportQuickThenLoader[Q](),
|
||||||
PublicreportQuickPhoto: buildPublicreportQuickPhotoThenLoader[Q](),
|
PublicreportQuickPhoto: buildPublicreportQuickPhotoThenLoader[Q](),
|
||||||
User: buildUserThenLoader[Q](),
|
User: buildUserThenLoader[Q](),
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ func Where[Q psql.Filterable]() struct {
|
||||||
OauthTokens oauthTokenWhere[Q]
|
OauthTokens oauthTokenWhere[Q]
|
||||||
Organizations organizationWhere[Q]
|
Organizations organizationWhere[Q]
|
||||||
PublicreportNuisances publicreportNuisanceWhere[Q]
|
PublicreportNuisances publicreportNuisanceWhere[Q]
|
||||||
|
PublicreportPools publicreportPoolWhere[Q]
|
||||||
|
PublicreportPoolPhotos publicreportPoolPhotoWhere[Q]
|
||||||
PublicreportQuicks publicreportQuickWhere[Q]
|
PublicreportQuicks publicreportQuickWhere[Q]
|
||||||
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
||||||
RasterColumns rasterColumnWhere[Q]
|
RasterColumns rasterColumnWhere[Q]
|
||||||
|
|
@ -110,6 +112,8 @@ func Where[Q psql.Filterable]() struct {
|
||||||
OauthTokens oauthTokenWhere[Q]
|
OauthTokens oauthTokenWhere[Q]
|
||||||
Organizations organizationWhere[Q]
|
Organizations organizationWhere[Q]
|
||||||
PublicreportNuisances publicreportNuisanceWhere[Q]
|
PublicreportNuisances publicreportNuisanceWhere[Q]
|
||||||
|
PublicreportPools publicreportPoolWhere[Q]
|
||||||
|
PublicreportPoolPhotos publicreportPoolPhotoWhere[Q]
|
||||||
PublicreportQuicks publicreportQuickWhere[Q]
|
PublicreportQuicks publicreportQuickWhere[Q]
|
||||||
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
PublicreportQuickPhotos publicreportQuickPhotoWhere[Q]
|
||||||
RasterColumns rasterColumnWhere[Q]
|
RasterColumns rasterColumnWhere[Q]
|
||||||
|
|
@ -160,6 +164,8 @@ func Where[Q psql.Filterable]() struct {
|
||||||
OauthTokens: buildOauthTokenWhere[Q](OauthTokens.Columns),
|
OauthTokens: buildOauthTokenWhere[Q](OauthTokens.Columns),
|
||||||
Organizations: buildOrganizationWhere[Q](Organizations.Columns),
|
Organizations: buildOrganizationWhere[Q](Organizations.Columns),
|
||||||
PublicreportNuisances: buildPublicreportNuisanceWhere[Q](PublicreportNuisances.Columns),
|
PublicreportNuisances: buildPublicreportNuisanceWhere[Q](PublicreportNuisances.Columns),
|
||||||
|
PublicreportPools: buildPublicreportPoolWhere[Q](PublicreportPools.Columns),
|
||||||
|
PublicreportPoolPhotos: buildPublicreportPoolPhotoWhere[Q](PublicreportPoolPhotos.Columns),
|
||||||
PublicreportQuicks: buildPublicreportQuickWhere[Q](PublicreportQuicks.Columns),
|
PublicreportQuicks: buildPublicreportQuickWhere[Q](PublicreportQuicks.Columns),
|
||||||
PublicreportQuickPhotos: buildPublicreportQuickPhotoWhere[Q](PublicreportQuickPhotos.Columns),
|
PublicreportQuickPhotos: buildPublicreportQuickPhotoWhere[Q](PublicreportQuickPhotos.Columns),
|
||||||
RasterColumns: buildRasterColumnWhere[Q](RasterColumns.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
|
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
|
package publicreport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/config"
|
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db"
|
"github.com/Gleipnir-Technology/nidus-sync/db"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
"github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
"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/htmlpage"
|
||||||
"github.com/Gleipnir-Technology/nidus-sync/userfile"
|
|
||||||
"github.com/aarondl/opt/omit"
|
"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/rs/zerolog/log"
|
||||||
"github.com/stephenafamo/bob/dialect/psql"
|
"github.com/stephenafamo/bob/dialect/psql"
|
||||||
"github.com/stephenafamo/bob/dialect/psql/um"
|
"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) {
|
func getRoot(w http.ResponseWriter, r *http.Request) {
|
||||||
htmlpage.RenderOrError(
|
htmlpage.RenderOrError(
|
||||||
w,
|
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) {
|
func getRegisterNotificationsComplete(w http.ResponseWriter, r *http.Request) {
|
||||||
report := r.URL.Query().Get("report")
|
report := r.URL.Query().Get("report")
|
||||||
htmlpage.RenderOrError(
|
htmlpage.RenderOrError(
|
||||||
|
|
@ -135,7 +83,6 @@ func postNuisance(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inspection_type_str := postFormValueOrNone(r, "inspection-type")
|
inspection_type_str := postFormValueOrNone(r, "inspection-type")
|
||||||
var inspection_type enums.PublicreportNuisanceinspectiontype
|
var inspection_type enums.PublicreportNuisanceinspectiontype
|
||||||
err = inspection_type.Scan(inspection_type_str)
|
err = inspection_type.Scan(inspection_type_str)
|
||||||
|
|
@ -188,29 +135,29 @@ func postNuisance(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
log.Info().Str("address", address).Str("name", name).Msg("Got report")
|
log.Info().Str("address", address).Str("name", name).Msg("Got report")
|
||||||
setter := models.PublicreportNuisanceSetter{
|
setter := models.PublicreportNuisanceSetter{
|
||||||
AdditionalInfo: omit.From(additional_info),
|
AdditionalInfo: omit.From(additional_info),
|
||||||
Created: omit.From(time.Now()),
|
Created: omit.From(time.Now()),
|
||||||
Duration: omit.From(duration),
|
Duration: omit.From(duration),
|
||||||
Email: omit.From(email),
|
Email: omit.From(email),
|
||||||
InspectionType: omit.From(inspection_type),
|
InspectionType: omit.From(inspection_type),
|
||||||
Location: omit.From(location),
|
Location: omit.From(location),
|
||||||
PreferredDateRange: omit.From(preferred_date_range),
|
PreferredDateRange: omit.From(preferred_date_range),
|
||||||
PreferredTime: omit.From(preferred_time),
|
PreferredTime: omit.From(preferred_time),
|
||||||
PublicID: omit.From(public_id),
|
PublicID: omit.From(public_id),
|
||||||
RequestCall: omit.From(request_call),
|
RequestCall: omit.From(request_call),
|
||||||
Severity: omit.From(int16(severity)),
|
Severity: omit.From(int16(severity)),
|
||||||
SourceContainer: omit.From(source_container),
|
SourceContainer: omit.From(source_container),
|
||||||
SourceDescription: omit.From(source_description),
|
SourceDescription: omit.From(source_description),
|
||||||
SourceRoof: omit.From(source_roof),
|
SourceRoof: omit.From(source_roof),
|
||||||
SourceStagnant: omit.From(source_stagnant),
|
SourceStagnant: omit.From(source_stagnant),
|
||||||
TimeOfDayDay: omit.From(tod_day),
|
TimeOfDayDay: omit.From(tod_day),
|
||||||
TimeOfDayEarly: omit.From(tod_early),
|
TimeOfDayEarly: omit.From(tod_early),
|
||||||
TimeOfDayEvening: omit.From(tod_evening),
|
TimeOfDayEvening: omit.From(tod_evening),
|
||||||
TimeOfDayNight: omit.From(tod_night),
|
TimeOfDayNight: omit.From(tod_night),
|
||||||
ReporterAddress: omit.From(address),
|
ReporterAddress: omit.From(address),
|
||||||
ReporterEmail: omit.From(email),
|
ReporterEmail: omit.From(email),
|
||||||
ReporterName: omit.From(name),
|
ReporterName: omit.From(name),
|
||||||
ReporterPhone: omit.From(phone),
|
ReporterPhone: omit.From(phone),
|
||||||
}
|
}
|
||||||
nuisance, err := models.PublicreportNuisances.Insert(&setter).One(r.Context(), db.PGInstance.BobDB)
|
nuisance, err := models.PublicreportNuisances.Insert(&setter).One(r.Context(), db.PGInstance.BobDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -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)
|
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) {
|
func postRegisterNotifications(w http.ResponseWriter, r *http.Request) {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
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 {
|
type ContextNuisanceSubmitComplete struct {
|
||||||
ReportID string
|
ReportID string
|
||||||
}
|
}
|
||||||
type ContextPool struct{
|
|
||||||
MapboxToken string
|
|
||||||
}
|
|
||||||
type ContextQuick struct{}
|
|
||||||
type ContextQuickSubmitComplete struct {
|
|
||||||
ReportID string
|
|
||||||
}
|
|
||||||
type ContextRegisterNotificationsComplete struct {
|
type ContextRegisterNotificationsComplete struct {
|
||||||
ReportID string
|
ReportID string
|
||||||
}
|
}
|
||||||
|
|
@ -33,15 +26,12 @@ type ContextStatus struct{}
|
||||||
var (
|
var (
|
||||||
Nuisance = buildTemplate("nuisance", "base")
|
Nuisance = buildTemplate("nuisance", "base")
|
||||||
NuisanceSubmitComplete = buildTemplate("nuisance-submit-complete", "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")
|
RegisterNotificationsComplete = buildTemplate("register-notifications-complete", "base")
|
||||||
Root = buildTemplate("root", "base")
|
Root = buildTemplate("root", "base")
|
||||||
Status = buildTemplate("status", "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 {
|
func buildTemplate(files ...string) *htmlpage.BuiltTemplate {
|
||||||
subdir := "public-report"
|
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
|
// Handle click on a suggestion
|
||||||
item.addEventListener('click', function() {
|
item.addEventListener('click', function() {
|
||||||
addressInput.value = suggestion.properties.name || suggestion.properties.full_address;
|
// Hide the suggestions container
|
||||||
|
setLocationInputs(suggestion);
|
||||||
suggestionsContainer.classList.add('d-none');
|
suggestionsContainer.classList.add('d-none');
|
||||||
|
|
||||||
// Display the selected location details
|
|
||||||
displaySelectedLocation(suggestion);
|
displaySelectedLocation(suggestion);
|
||||||
setMapMarker(suggestion.geometry.coordinates);
|
const locationSelected = new CustomEvent("locationselected", {
|
||||||
|
detail: {
|
||||||
|
coordinates: suggestion.geometry.coordinates,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
suggestionsContainer.dispatchEvent(locationSelected);
|
||||||
});
|
});
|
||||||
|
|
||||||
suggestionsContainer.appendChild(item);
|
suggestionsContainer.appendChild(item);
|
||||||
|
|
@ -155,18 +159,45 @@ function onAddressInput() {
|
||||||
}, 300);
|
}, 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() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
const addressInput = document.getElementById('addressInput');
|
const address = document.getElementById('address');
|
||||||
const suggestionsContainer = document.getElementById('suggestions');
|
const suggestionsContainer = document.getElementById('suggestions');
|
||||||
const locationDetails = document.getElementById('locationDetails');
|
const locationDetails = document.getElementById('locationDetails');
|
||||||
|
|
||||||
|
|
||||||
// Listen for input changes
|
// Listen for input changes
|
||||||
addressInput.addEventListener('input', onAddressInput);
|
address.addEventListener('input', onAddressInput);
|
||||||
|
|
||||||
// Close suggestions when clicking outside
|
// Close suggestions when clicking outside
|
||||||
document.addEventListener('click', function(event) {
|
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');
|
suggestionsContainer.classList.add('d-none');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
{{define "location-geocode"}}
|
{{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">
|
<div class="col-md-6">
|
||||||
<h2 class="mb-4">Address Search</h2>
|
|
||||||
<div class="mb-3 position-relative">
|
<div class="mb-3 position-relative">
|
||||||
<label for="addressInput" class="form-label">Enter address</label>
|
<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)">
|
placeholder="Start typing an address (min 3 characters)">
|
||||||
<div id="suggestions" class="suggestions-container list-group d-none"></div>
|
<div id="suggestions" class="suggestions-container list-group d-none"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,144 +1,2 @@
|
||||||
{{define "map-header"}}
|
{{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}}
|
{{end}}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
{{define "photo-upload"}}
|
{{define "photo-upload"}}
|
||||||
<label for="photos" class="form-label fw-bold">Photos (Optional)</label>
|
|
||||||
<div class="photo-upload-area">
|
<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">
|
<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"/>
|
<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 "title"}}Green Pool{{end}}
|
||||||
{{define "extraheader"}}
|
{{define "extraheader"}}
|
||||||
{{template "location-geocode-header" .}}
|
{{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"}}
|
{{template "photo-upload-header"}}
|
||||||
<style>
|
<style>
|
||||||
.district-logo {
|
.district-logo {
|
||||||
|
|
@ -30,6 +31,48 @@
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
padding-bottom: 0;
|
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 {
|
.section-heading {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -53,6 +96,232 @@
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
</style>
|
</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}}
|
{{end}}
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
|
|
@ -77,7 +346,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Report Form -->
|
<!-- Report Form -->
|
||||||
<form id="greenPoolForm">
|
<form id="greenPoolForm" action="/pool-submit" method="POST" enctype="multipart/form-data">
|
||||||
<!-- Photo Upload Section -->
|
<!-- Photo Upload Section -->
|
||||||
<div class="form-section">
|
<div class="form-section">
|
||||||
<div class="section-heading">
|
<div class="section-heading">
|
||||||
|
|
@ -86,8 +355,9 @@
|
||||||
<span class="optional-label">optional</span>
|
<span class="optional-label">optional</span>
|
||||||
</div>
|
</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>
|
<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"}}
|
{{template "photo-upload"}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Location Section -->
|
<!-- Location Section -->
|
||||||
|
|
@ -119,6 +389,7 @@
|
||||||
<div class="map-container">
|
<div class="map-container">
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<input type="hidden" id="map-zoom" name="map-zoom"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Source Details Section -->
|
<!-- Source Details Section -->
|
||||||
|
|
@ -132,8 +403,8 @@
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="duration" class="form-label">How long has this source been present?</label>
|
<label for="duration" class="form-label">How long has this source been present?</label>
|
||||||
<select class="form-select" id="duration">
|
<select class="form-select" id="duration" name="source-duration">
|
||||||
<option value="">I don't know</option>
|
<option value="none">I don't know</option>
|
||||||
<option value="less-than-week">Less than a week</option>
|
<option value="less-than-week">Less than a week</option>
|
||||||
<option value="1-2-weeks">1-2 weeks</option>
|
<option value="1-2-weeks">1-2 weeks</option>
|
||||||
<option value="2-4-weeks">2-4 weeks</option>
|
<option value="2-4-weeks">2-4 weeks</option>
|
||||||
|
|
@ -145,20 +416,20 @@
|
||||||
<div class="col-md-6">
|
<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>
|
<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">
|
<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">
|
<label class="form-check-label" for="larvae">
|
||||||
Larvae (wigglers) in water
|
Larvae (wigglers) in water
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<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">
|
<label class="form-check-label" for="pupae">
|
||||||
Pupae (tumblers) in water
|
Pupae (tumblers) in water
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="adultMosquitoes">
|
<input class="form-check-input" type="checkbox" id="adult" name="has-adult">
|
||||||
<label class="form-check-label" for="adultMosquitoes">
|
<label class="form-check-label" for="adult">
|
||||||
Adult mosquitoes near the source
|
Adult mosquitoes near the source
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -177,8 +448,8 @@
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<label for="accessInfo" class="form-label">How can the source be accessed?</label>
|
<label for="access-comments" 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>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -188,28 +459,28 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="form-check">
|
<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>
|
<label class="form-check-label" for="gate">Gate</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<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>
|
<label class="form-check-label" for="fence">Fence</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="lockedEntrance">
|
<input class="form-check-input" type="checkbox" id="locked" name="access-locked">
|
||||||
<label class="form-check-label" for="lockedEntrance">Locked entrance</label>
|
<label class="form-check-label" for="locked">Locked entrance</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<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>
|
<label class="form-check-label" for="dogs">Dogs/pets</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="otherObstacle">
|
<input class="form-check-input" type="checkbox" id="access-other" name="access-other">
|
||||||
<label class="form-check-label" for="otherObstacle">Other obstacle</label>
|
<label class="form-check-label" for="access-other">Other obstacle</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -229,16 +500,16 @@
|
||||||
<h5 class="mb-3">Property Owner Information (if known)</h5>
|
<h5 class="mb-3">Property Owner Information (if known)</h5>
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="ownerName" class="form-label">Owner Name</label>
|
<label for="owner-name" class="form-label">Owner Name</label>
|
||||||
<input type="text" class="form-control" id="ownerName">
|
<input type="text" class="form-control" id="owner-name" name="owner-name">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="ownerPhone" class="form-label">Owner Phone</label>
|
<label for="owner-phone" class="form-label">Owner Phone</label>
|
||||||
<input type="tel" class="form-control" id="ownerPhone">
|
<input type="tel" class="form-control" id="owner-phone" name="owner-phone">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<label for="ownerEmail" class="form-label">Owner Email</label>
|
<label for="owner-email" class="form-label">Owner Email</label>
|
||||||
<input type="email" class="form-control" id="ownerEmail">
|
<input type="email" class="form-control" id="owner-email" name="owner-email">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -246,21 +517,21 @@
|
||||||
<h5 class="mb-3">Your Contact Information (for updates)</h5>
|
<h5 class="mb-3">Your Contact Information (for updates)</h5>
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="reporterName" class="form-label">Your Name</label>
|
<label for="reporter-name" class="form-label">Your Name</label>
|
||||||
<input type="text" class="form-control" id="reporterName">
|
<input type="text" class="form-control" id="reporter-name" name="reporter-name">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="reporterPhone" class="form-label">Your Phone</label>
|
<label for="reporter-phone" class="form-label">Your Phone</label>
|
||||||
<input type="tel" class="form-control" id="reporterPhone">
|
<input type="tel" class="form-control" id="reporter-phone" name="reporter-phone">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12 mb-3">
|
<div class="col-md-12 mb-3">
|
||||||
<label for="reporterEmail" class="form-label">Your Email</label>
|
<label for="reporter-email" class="form-label">Your Email</label>
|
||||||
<input type="email" class="form-control" id="reporterEmail">
|
<input type="email" class="form-control" id="reporter-email" name="reporter-email">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="receiveUpdates" checked>
|
<input class="form-check-input" type="checkbox" id="subscribe" name="subscribe" checked>
|
||||||
<label class="form-check-label" for="receiveUpdates">
|
<label class="form-check-label" for="subscribe">
|
||||||
I would like to receive updates on this report
|
I would like to receive updates on this report
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -279,8 +550,8 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<label for="additionalInfo" class="form-label">Additional Details</label>
|
<label for="comments" 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>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue