Make organization.name not-nullable, consolidate org in dash context

This commit is contained in:
Eli Ribble 2026-01-14 21:49:12 +00:00
parent 4f0b73c769
commit a4c0e367a8
No known key found for this signature in database
13 changed files with 118 additions and 50 deletions

View file

@ -131,7 +131,7 @@ func SignupUser(ctx context.Context, username string, name string, password stri
return nil, fmt.Errorf("Cannot signup user, failed to create hashed password: %w", err)
}
o_setter := models.OrganizationSetter{
Name: omitnull.From(fmt.Sprintf("%s's organization", username)),
Name: omit.From(fmt.Sprintf("%s's organization", username)),
ArcgisID: omitnull.From(""),
ArcgisName: omitnull.From(""),
FieldseekerURL: omitnull.From(""),

View file

@ -213,6 +213,15 @@ var Districts = Table[
Generated: false,
AutoIncr: false,
},
Geom4326: column{
Name: "geom_4326",
DBType: "geometry",
Default: "GENERATED",
Comment: "",
Nullable: true,
Generated: true,
AutoIncr: false,
},
},
Indexes: districtIndexes{
DistrictPkey: index{
@ -282,11 +291,12 @@ type districtColumns struct {
ShapeLe1 column
ShapeArea column
Geom column
Geom4326 column
}
func (c districtColumns) AsSlice() []column {
return []column{
c.Gid, c.ID, c.Website, c.Contact, c.Address, c.Regionid, c.PostalCod, c.Phone1, c.Fax1, c.Agency, c.Code1, c.City1, c.ShapeLeng, c.Address2, c.GeneralMG, c.City2, c.PostalC1, c.Fax2, c.Phone2, c.ShapeLe1, c.ShapeArea, c.Geom,
c.Gid, c.ID, c.Website, c.Contact, c.Address, c.Regionid, c.PostalCod, c.Phone1, c.Fax1, c.Agency, c.Code1, c.City1, c.ShapeLeng, c.Address2, c.GeneralMG, c.City2, c.PostalC1, c.Fax2, c.Phone2, c.ShapeLe1, c.ShapeArea, c.Geom, c.Geom4326,
}
}

View file

@ -27,9 +27,9 @@ var Organizations = Table[
Name: column{
Name: "name",
DBType: "text",
Default: "NULL",
Default: "",
Comment: "",
Nullable: true,
Nullable: false,
Generated: false,
AutoIncr: false,
},

View file

@ -118,6 +118,7 @@ func (f *Factory) FromExistingDistrict(m *models.District) *DistrictTemplate {
o.ShapeLe1 = func() null.Val[decimal.Decimal] { return m.ShapeLe1 }
o.ShapeArea = func() null.Val[decimal.Decimal] { return m.ShapeArea }
o.Geom = func() null.Val[string] { return m.Geom }
o.Geom4326 = func() null.Val[string] { return m.Geom4326 }
return o
}
@ -2317,7 +2318,7 @@ func (f *Factory) FromExistingOrganization(m *models.Organization) *Organization
o := &OrganizationTemplate{f: f, alreadyPersisted: true}
o.ID = func() int32 { return m.ID }
o.Name = func() null.Val[string] { return m.Name }
o.Name = func() string { return m.Name }
o.ArcgisID = func() null.Val[string] { return m.ArcgisID }
o.ArcgisName = func() null.Val[string] { return m.ArcgisName }
o.FieldseekerURL = func() null.Val[string] { return m.FieldseekerURL }

View file

@ -59,6 +59,7 @@ type DistrictTemplate struct {
ShapeLe1 func() null.Val[decimal.Decimal]
ShapeArea func() null.Val[decimal.Decimal]
Geom func() null.Val[string]
Geom4326 func() null.Val[string]
f *Factory
@ -257,6 +258,9 @@ func (o DistrictTemplate) Build() *models.District {
if o.Geom != nil {
m.Geom = o.Geom()
}
if o.Geom4326 != nil {
m.Geom4326 = o.Geom4326()
}
o.setModelRels(m)
@ -399,6 +403,7 @@ func (m districtMods) RandomizeAllColumns(f *faker.Faker) DistrictMod {
DistrictMods.RandomShapeLe1(f),
DistrictMods.RandomShapeArea(f),
DistrictMods.RandomGeom(f),
DistrictMods.RandomGeom4326(f),
}
}
@ -1546,6 +1551,59 @@ func (m districtMods) RandomGeomNotNull(f *faker.Faker) DistrictMod {
})
}
// Set the model columns to this value
func (m districtMods) Geom4326(val null.Val[string]) DistrictMod {
return DistrictModFunc(func(_ context.Context, o *DistrictTemplate) {
o.Geom4326 = func() null.Val[string] { return val }
})
}
// Set the Column from the function
func (m districtMods) Geom4326Func(f func() null.Val[string]) DistrictMod {
return DistrictModFunc(func(_ context.Context, o *DistrictTemplate) {
o.Geom4326 = f
})
}
// Clear any values for the column
func (m districtMods) UnsetGeom4326() DistrictMod {
return DistrictModFunc(func(_ context.Context, o *DistrictTemplate) {
o.Geom4326 = nil
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m districtMods) RandomGeom4326(f *faker.Faker) DistrictMod {
return DistrictModFunc(func(_ context.Context, o *DistrictTemplate) {
o.Geom4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m districtMods) RandomGeom4326NotNull(f *faker.Faker) DistrictMod {
return DistrictModFunc(func(_ context.Context, o *DistrictTemplate) {
o.Geom4326 = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
func (m districtMods) WithParentsCascading() DistrictMod {
return DistrictModFunc(func(ctx context.Context, o *DistrictTemplate) {
if isDone, _ := districtWithParentsCascadingCtx.Value(ctx); isDone {

View file

@ -37,7 +37,7 @@ func (mods OrganizationModSlice) Apply(ctx context.Context, n *OrganizationTempl
// all columns are optional and should be set by mods
type OrganizationTemplate struct {
ID func() int32
Name func() null.Val[string]
Name func() string
ArcgisID func() null.Val[string]
ArcgisName func() null.Val[string]
FieldseekerURL func() null.Val[string]
@ -650,7 +650,7 @@ func (o OrganizationTemplate) BuildSetter() *models.OrganizationSetter {
}
if o.Name != nil {
val := o.Name()
m.Name = omitnull.FromNull(val)
m.Name = omit.From(val)
}
if o.ArcgisID != nil {
val := o.ArcgisID()
@ -721,6 +721,10 @@ func (o OrganizationTemplate) BuildMany(number int) models.OrganizationSlice {
}
func ensureCreatableOrganization(m *models.OrganizationSetter) {
if !(m.Name.IsValue()) {
val := random_string(nil)
m.Name = omit.From(val)
}
}
// insertOptRels creates and inserts any optional the relationships on *models.Organization
@ -1501,14 +1505,14 @@ func (m organizationMods) RandomID(f *faker.Faker) OrganizationMod {
}
// Set the model columns to this value
func (m organizationMods) Name(val null.Val[string]) OrganizationMod {
func (m organizationMods) Name(val string) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.Name = func() null.Val[string] { return val }
o.Name = func() string { return val }
})
}
// Set the Column from the function
func (m organizationMods) NameFunc(f func() null.Val[string]) OrganizationMod {
func (m organizationMods) NameFunc(f func() string) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.Name = f
})
@ -1523,32 +1527,10 @@ func (m organizationMods) UnsetName() OrganizationMod {
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is sometimes null
func (m organizationMods) RandomName(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.Name = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
}
})
}
// Generates a random value for the column using the given faker
// if faker is nil, a default faker is used
// The generated value is never null
func (m organizationMods) RandomNameNotNull(f *faker.Faker) OrganizationMod {
return OrganizationModFunc(func(_ context.Context, o *OrganizationTemplate) {
o.Name = func() null.Val[string] {
if f == nil {
f = &defaultFaker
}
val := random_string(f)
return null.From(val)
o.Name = func() string {
return random_string(f)
}
})
}

View file

@ -0,0 +1,5 @@
-- +goose Up
ALTER TABLE organization ALTER COLUMN name SET NOT NULL;
-- +goose Down
ALTER TABLE organization ALTER COLUMN name DROP NOT NULL;

View file

@ -44,6 +44,7 @@ type District struct {
ShapeLe1 null.Val[decimal.Decimal] `db:"shape_le_1" `
ShapeArea null.Val[decimal.Decimal] `db:"shape_area" `
Geom null.Val[string] `db:"geom" `
Geom4326 null.Val[string] `db:"geom_4326,generated" `
}
// DistrictSlice is an alias for a slice of pointers to District.
@ -59,7 +60,7 @@ type DistrictsQuery = *psql.ViewQuery[*District, DistrictSlice]
func buildDistrictColumns(alias string) districtColumns {
return districtColumns{
ColumnsExpr: expr.NewColumnsExpr(
"gid", "id", "website", "contact", "address", "regionid", "postal_cod", "phone1", "fax1", "agency", "code1", "city1", "shape_leng", "address2", "general_mg", "city2", "postal_c_1", "fax2", "phone2", "shape_le_1", "shape_area", "geom",
"gid", "id", "website", "contact", "address", "regionid", "postal_cod", "phone1", "fax1", "agency", "code1", "city1", "shape_leng", "address2", "general_mg", "city2", "postal_c_1", "fax2", "phone2", "shape_le_1", "shape_area", "geom", "geom_4326",
).WithParent("district"),
tableAlias: alias,
Gid: psql.Quote(alias, "gid"),
@ -84,6 +85,7 @@ func buildDistrictColumns(alias string) districtColumns {
ShapeLe1: psql.Quote(alias, "shape_le_1"),
ShapeArea: psql.Quote(alias, "shape_area"),
Geom: psql.Quote(alias, "geom"),
Geom4326: psql.Quote(alias, "geom_4326"),
}
}
@ -112,6 +114,7 @@ type districtColumns struct {
ShapeLe1 psql.Expression
ShapeArea psql.Expression
Geom psql.Expression
Geom4326 psql.Expression
}
func (c districtColumns) Alias() string {
@ -842,6 +845,7 @@ type districtWhere[Q psql.Filterable] struct {
ShapeLe1 psql.WhereNullMod[Q, decimal.Decimal]
ShapeArea psql.WhereNullMod[Q, decimal.Decimal]
Geom psql.WhereNullMod[Q, string]
Geom4326 psql.WhereNullMod[Q, string]
}
func (districtWhere[Q]) AliasedAs(alias string) districtWhere[Q] {
@ -872,5 +876,6 @@ func buildDistrictWhere[Q psql.Filterable](cols districtColumns) districtWhere[Q
ShapeLe1: psql.WhereNull[Q, decimal.Decimal](cols.ShapeLe1),
ShapeArea: psql.WhereNull[Q, decimal.Decimal](cols.ShapeArea),
Geom: psql.WhereNull[Q, string](cols.Geom),
Geom4326: psql.WhereNull[Q, string](cols.Geom4326),
}
}

View file

@ -26,7 +26,7 @@ import (
// Organization is an object representing the database table.
type Organization struct {
ID int32 `db:"id,pk" `
Name null.Val[string] `db:"name" `
Name string `db:"name" `
ArcgisID null.Val[string] `db:"arcgis_id" `
ArcgisName null.Val[string] `db:"arcgis_name" `
FieldseekerURL null.Val[string] `db:"fieldseeker_url" `
@ -117,7 +117,7 @@ func (organizationColumns) AliasedAs(alias string) organizationColumns {
// Generated columns are not included
type OrganizationSetter struct {
ID omit.Val[int32] `db:"id,pk" `
Name omitnull.Val[string] `db:"name" `
Name omit.Val[string] `db:"name" `
ArcgisID omitnull.Val[string] `db:"arcgis_id" `
ArcgisName omitnull.Val[string] `db:"arcgis_name" `
FieldseekerURL omitnull.Val[string] `db:"fieldseeker_url" `
@ -128,7 +128,7 @@ func (s OrganizationSetter) SetColumns() []string {
if s.ID.IsValue() {
vals = append(vals, "id")
}
if !s.Name.IsUnset() {
if s.Name.IsValue() {
vals = append(vals, "name")
}
if !s.ArcgisID.IsUnset() {
@ -147,8 +147,8 @@ func (s OrganizationSetter) Overwrite(t *Organization) {
if s.ID.IsValue() {
t.ID = s.ID.MustGet()
}
if !s.Name.IsUnset() {
t.Name = s.Name.MustGetNull()
if s.Name.IsValue() {
t.Name = s.Name.MustGet()
}
if !s.ArcgisID.IsUnset() {
t.ArcgisID = s.ArcgisID.MustGetNull()
@ -174,8 +174,8 @@ func (s *OrganizationSetter) Apply(q *dialect.InsertQuery) {
vals[0] = psql.Raw("DEFAULT")
}
if !s.Name.IsUnset() {
vals[1] = psql.Arg(s.Name.MustGetNull())
if s.Name.IsValue() {
vals[1] = psql.Arg(s.Name.MustGet())
} else {
vals[1] = psql.Raw("DEFAULT")
}
@ -216,7 +216,7 @@ func (s OrganizationSetter) Expressions(prefix ...string) []bob.Expression {
}})
}
if !s.Name.IsUnset() {
if s.Name.IsValue() {
exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{
psql.Quote(append(prefix, "name")...),
psql.Arg(s.Name),
@ -3416,7 +3416,7 @@ func (organization0 *Organization) AttachUser(ctx context.Context, exec bob.Exec
type organizationWhere[Q psql.Filterable] struct {
ID psql.WhereMod[Q, int32]
Name psql.WhereNullMod[Q, string]
Name psql.WhereMod[Q, string]
ArcgisID psql.WhereNullMod[Q, string]
ArcgisName psql.WhereNullMod[Q, string]
FieldseekerURL psql.WhereNullMod[Q, string]
@ -3429,7 +3429,7 @@ func (organizationWhere[Q]) AliasedAs(alias string) organizationWhere[Q] {
func buildOrganizationWhere[Q psql.Filterable](cols organizationColumns) organizationWhere[Q] {
return organizationWhere[Q]{
ID: psql.Where[Q, int32](cols.ID),
Name: psql.WhereNull[Q, string](cols.Name),
Name: psql.Where[Q, string](cols.Name),
ArcgisID: psql.WhereNull[Q, string](cols.ArcgisID),
ArcgisName: psql.WhereNull[Q, string](cols.ArcgisName),
FieldseekerURL: psql.WhereNull[Q, string](cols.FieldseekerURL),

View file

@ -42,7 +42,6 @@ type ContextDashboard struct {
IsSyncOngoing bool
LastSync *time.Time
MapData ComponentMap
Org string
RecentRequests []ServiceRequestSummary
User User
}
@ -249,7 +248,6 @@ func dashboard(ctx context.Context, w http.ResponseWriter, user *models.User) {
MapData: ComponentMap{
MapboxToken: config.MapboxToken,
},
Org: org.Name.MustGet(),
RecentRequests: requests,
User: userContent,
}

View file

@ -28,7 +28,7 @@ function onLoad() {
map.addSource('tegola-nidus', {
'type': 'vector',
'tiles': [
'https://{{.Config.URLTegola}}/maps/nidus/{z}/{x}/{y}?organization_id={{.User.OrganizationID}}'
'https://{{.Config.URLTegola}}/maps/nidus/{z}/{x}/{y}?organization_id={{.User.Organization.ID}}'
]
//'minzoom': 6,
//'maxzoom': 14
@ -172,7 +172,7 @@ body {
<!-- Dashboard Header -->
<div class="row mb-4">
<div class="col-md-6">
<h1>{{ .Org }} Dashboard</h1>
<h1>{{ .User.Organization.Name }} Dashboard</h1>
<p class="text-muted">Overview of mosquito control activities in your district</p>
</div>
<div class="col-md-6 text-md-end d-flex align-items-center justify-content-md-end">

View file

@ -94,6 +94,10 @@ type Link struct {
Href string
Title string
}
type Organization struct {
ID int
Name string
}
type ServiceRequestSummary struct {
Date time.Time
Location string
@ -103,6 +107,6 @@ type User struct {
DisplayName string
Initials string
Notifications []notification.Notification
OrganizationID int
Organization Organization
Username string
}

View file

@ -95,10 +95,15 @@ func contentForUser(ctx context.Context, user *models.User) (User, error) {
if err != nil {
return User{}, err
}
org := user.R.Organization
return User{
DisplayName: user.DisplayName,
Initials: extractInitials(user.DisplayName),
Notifications: notifications,
Organization: Organization {
ID: int(org.ID),
Name: org.Name,
},
Username: user.Username,
}, nil