Rip apart several new packages for inter-dependence

This will help make it clear what depends on what for rendering html
pages
This commit is contained in:
Eli Ribble 2026-01-07 16:07:51 +00:00
parent 4c23eba5d7
commit 572b8a9de9
11 changed files with 277 additions and 263 deletions

View file

@ -1,103 +0,0 @@
package htmlpage
import (
"fmt"
"strings"
"github.com/Gleipnir-Technology/go-geojson2h3/v2"
"github.com/tidwall/geojson"
"github.com/uber/h3-go/v4"
)
/*
func h3ToBoundsGeoJSON(c h3.Cell) (string, error) {
b, err := h3.CellToBoundary(c)
if err != nil {
respondError(w, "Failed to get cell boundary", err, http.StatusInternalServerError)
return
}
features, err := geojson2h3.ToFeatureCollection(b)
if err != nil {
return "", fmt.Errorf("Failed to convert boundary to
}
*/
func toH3Cell(s string) (h3.Cell, error) {
c := h3.CellFromString(s)
if !c.IsValid() {
return c, fmt.Errorf("Invalid cell definition '%s'", s)
}
return c, nil
}
func h3ToGeoJSON(indexes []h3.Cell) (interface{}, error) {
featureCollection, err := geojson2h3.ToFeatureCollection(indexes)
if err != nil {
return "", fmt.Errorf("Failed to get feature collection: %w", err)
}
return featureCollection.JSON(), nil
}
func main2() {
resolution := 9
object, err := geojson.Parse(`{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"shape":"Polygon","name":"Unnamed Layer","category":"default"},"geometry":{"type":"Polygon","coordinates":[[[-73.901303,40.756892],[-73.893924,40.743755],[-73.871476,40.756278],[-73.863378,40.764175],[-73.871444,40.768467],[-73.879852,40.760014],[-73.885515,40.764045],[-73.891522,40.761054],[-73.901303,40.756892]]]},"id":"a6ca1b7e-9ddf-4425-ad07-8a895f7d6ccf"}]}`, nil)
if err != nil {
panic(err)
}
indexes, err := geojson2h3.ToH3(resolution, object)
if err != nil {
panic(err)
}
for _, index := range indexes {
fmt.Printf("h3index: %s\n", index.String())
}
featureCollection, err := geojson2h3.ToFeatureCollection(indexes)
if err != nil {
panic(err)
}
fmt.Println("Polyfill:")
fmt.Println(featureCollection.JSON())
}
// Given a cell at a smaller resolution remap it to the larger resolution
func scaleCell(cell h3.Cell, resolution int) (h3.Cell, error) {
r := cell.Resolution()
if r == resolution {
return cell, nil
}
latLong, err := cell.LatLng()
if err != nil {
return 0, fmt.Errorf("Failed to get latlng: %w", err)
}
scaled, err := h3.LatLngToCell(latLong, resolution)
if err != nil {
return 0, fmt.Errorf("Failed to create latlng: %w", err)
}
return scaled, nil
}
func getCell(x, y float64, resolution int) (h3.Cell, error) {
latLng := h3.NewLatLng(y, x)
return h3.LatLngToCell(latLng, resolution)
}
func cellToPostgisGeometry(c h3.Cell) (string, error) {
boundary, err := h3.CellToBoundary(c)
if err != nil {
return "", fmt.Errorf("Failed to get cell boundary: %w", err)
}
var sb strings.Builder
for i, p := range boundary {
if i > 0 {
sb.WriteString(",")
}
fmt.Fprintf(&sb, "%g %g", p.Lng, p.Lat)
}
// add the first point on to the end to close the polygon
sb.WriteString(",")
fmt.Fprintf(&sb, "%g %g", boundary[0].Lng, boundary[0].Lat)
return fmt.Sprintf("POLYGON((%s))", sb.String()), nil
}

View file

@ -15,9 +15,13 @@ import (
"strings"
"time"
"github.com/Gleipnir-Technology/nidus-sync/background"
"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/db/sql"
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
"github.com/Gleipnir-Technology/nidus-sync/notification"
"github.com/aarondl/opt/null"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
@ -30,8 +34,6 @@ import (
//go:embed templates/*
var embeddedFiles embed.FS
var MapboxToken string
// Authenticated pages
var (
cell = newBuiltTemplate("cell", "authenticated")
@ -190,7 +192,7 @@ type ServiceRequestSummary struct {
type User struct {
DisplayName string
Initials string
Notifications []Notification
Notifications []notification.Notification
Username string
}
@ -228,7 +230,7 @@ func bigNumber(n int) string {
}
func contentForUser(ctx context.Context, user *models.User) (User, error) {
notifications, err := notificationsForUser(ctx, user)
notifications, err := notification.ForUser(ctx, user)
if err != nil {
return User{}, err
}
@ -279,7 +281,7 @@ func Cell(ctx context.Context, w http.ResponseWriter, user *models.User, c int64
respondError(w, "Failed to get inspections by cell", err, http.StatusInternalServerError)
return
}
geojson, err := h3ToGeoJSON([]h3.Cell{h3.Cell(c)})
geojson, err := h3utils.H3ToGeoJSON([]h3.Cell{h3.Cell(c)})
if err != nil {
respondError(w, "Failed to get boundaries", err, http.StatusInternalServerError)
return
@ -305,7 +307,7 @@ func Cell(ctx context.Context, w http.ResponseWriter, user *models.User, c int64
Lng: center.Lng,
},
GeoJSON: geojson,
MapboxToken: MapboxToken,
MapboxToken: config.MapboxToken,
Zoom: resolution + 5,
},
Treatments: treatments,
@ -330,7 +332,7 @@ func Dashboard(ctx context.Context, w http.ResponseWriter, user *models.User) {
} else {
lastSync = &sync.Created
}
is_syncing := isSyncOngoing(org.ID)
is_syncing := background.IsSyncOngoing(org.ID)
inspectionCount, err := org.Mosquitoinspections().Count(ctx, db.PGInstance.BobDB)
if err != nil {
respondError(w, "Failed to get inspection count", err, http.StatusInternalServerError)
@ -372,7 +374,7 @@ func Dashboard(ctx context.Context, w http.ResponseWriter, user *models.User) {
IsSyncOngoing: is_syncing,
LastSync: lastSync,
MapData: ComponentMap{
MapboxToken: MapboxToken,
MapboxToken: config.MapboxToken,
},
Org: org.Name.MustGet(),
RecentRequests: requests,
@ -490,7 +492,7 @@ func Source(w http.ResponseWriter, r *http.Request, user *models.User, id uuid.U
MapData: ComponentMap{
Center: latlng,
//GeoJSON:
MapboxToken: MapboxToken,
MapboxToken: config.MapboxToken,
Markers: []MapMarker{
MapMarker{
LatLng: latlng,

View file

@ -7,6 +7,7 @@ import (
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/db/sql"
"github.com/Gleipnir-Technology/nidus-sync/h3utils"
"github.com/aarondl/opt/null"
"github.com/google/uuid"
"github.com/rs/zerolog/log"
@ -210,7 +211,7 @@ func toTemplateTrapData(trap_data models.FieldseekerTrapdatumSlice) ([]TrapData,
if r.H3cell.IsNull() {
continue
}
cell, err := toH3Cell(r.H3cell.MustGet())
cell, err := h3utils.ToCell(r.H3cell.MustGet())
if err != nil {
log.Error().Err(err).Msg("Failed to get location for trap data")
continue
@ -333,7 +334,7 @@ func toTemplateBreedingSource(source *models.FieldseekerPointlocation) *Breeding
log.Error().Msg("h3 cell is null")
return nil
}
cell, err := toH3Cell(source.H3cell.MustGet())
cell, err := h3utils.ToCell(source.H3cell.MustGet())
if err != nil {
log.Error().Err(err).Msg("Failed to get h3 cell from point location")
return nil

View file

@ -1,92 +0,0 @@
package htmlpage
import (
"context"
"fmt"
"strings"
"time"
"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/debug"
"github.com/aarondl/opt/omit"
"github.com/aarondl/opt/omitnull"
"github.com/rs/zerolog/log"
)
var (
NotificationPathOauthReset string = "/oauth/refresh"
)
type Notification struct {
Link string
Message string
Time time.Time
Type string
}
// Clear all notifications for a given user with the given path
func clearNotificationsOauth(ctx context.Context, user *models.User) {
setter := models.NotificationSetter{
ResolvedAt: omitnull.From(time.Now()),
}
updater := models.Notifications.Update(
//models.SelectWhere.Notifications.Link.EQ(NotificationPathOauthReset),
models.UpdateWhere.Notifications.Link.EQ(NotificationPathOauthReset),
models.UpdateWhere.Notifications.UserID.EQ(user.ID),
setter.UpdateMod(),
)
updater.Exec(ctx, db.PGInstance.BobDB)
//user.UserNotifications(
//models.SelectWhere.Notifications.Link.EQ(NotificationPathOauthReset),
//).UpdateAll()
}
func notifyOauthInvalid(ctx context.Context, user *models.User) {
msg := "Oauth token invalidated"
notificationSetter := models.NotificationSetter{
Created: omit.From(time.Now()),
Message: omit.From(msg),
Link: omit.From(NotificationPathOauthReset),
Type: omit.From(enums.NotificationtypeOauthTokenInvalidated),
}
err := user.InsertUserNotifications(ctx, db.PGInstance.BobDB, &notificationSetter)
if err != nil {
if strings.HasPrefix(err.Error(), "ERROR: duplicate key value violates unique constraint") {
log.Info().Str("msg", msg).Int("user_id", int(user.ID)).Msg("Refusing to add another notification with the same type")
return
}
debug.LogErrorTypeInfo(err)
log.Error().Err(err).Msg("Failed to insert new notification. This is a programmer bug.")
return
}
}
func notificationsForUser(ctx context.Context, u *models.User) ([]Notification, error) {
results := make([]Notification, 0)
notifications, err := u.UserNotifications(
models.SelectWhere.Notifications.ResolvedAt.IsNull(),
).All(ctx, db.PGInstance.BobDB)
if err != nil {
return results, fmt.Errorf("Failed to get notifications: %w", err)
}
for _, n := range notifications {
results = append(results, Notification{
Link: n.Link,
Message: n.Message,
Time: n.Created,
Type: notificationTypeName(n.Type),
})
}
return results, nil
}
func notificationTypeName(t enums.Notificationtype) string {
switch t {
case enums.NotificationtypeOauthTokenInvalidated:
return "alert"
default:
return "unknown-type"
}
}