2026-03-12 23:49:16 +00:00
|
|
|
package platform
|
2025-11-13 16:46:30 +00:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2025-12-02 00:30:46 +00:00
|
|
|
"strings"
|
2025-11-13 16:46:30 +00:00
|
|
|
"time"
|
|
|
|
|
|
2026-02-12 21:06:08 +00:00
|
|
|
"github.com/Gleipnir-Technology/bob/dialect/psql"
|
|
|
|
|
"github.com/Gleipnir-Technology/bob/dialect/psql/im"
|
2025-11-24 18:08:24 +00:00
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/db"
|
|
|
|
|
enums "github.com/Gleipnir-Technology/nidus-sync/db/enums"
|
|
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/db/models"
|
2026-01-06 14:46:31 +00:00
|
|
|
"github.com/Gleipnir-Technology/nidus-sync/debug"
|
2026-02-12 21:06:08 +00:00
|
|
|
//"github.com/aarondl/opt/omit"
|
2025-11-13 16:46:30 +00:00
|
|
|
"github.com/aarondl/opt/omitnull"
|
2025-12-02 00:30:46 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
2025-11-13 16:46:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
NotificationPathOauthReset string = "/oauth/refresh"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Notification struct {
|
|
|
|
|
Link string
|
|
|
|
|
Message string
|
|
|
|
|
Time time.Time
|
|
|
|
|
Type string
|
|
|
|
|
}
|
2026-04-02 01:07:55 +00:00
|
|
|
type notificationCounts struct {
|
|
|
|
|
Communications uint
|
|
|
|
|
Home uint
|
|
|
|
|
Review uint
|
2026-03-13 21:22:34 +00:00
|
|
|
}
|
2025-11-13 16:46:30 +00:00
|
|
|
|
|
|
|
|
// Clear all notifications for a given user with the given path
|
2026-01-07 16:07:51 +00:00
|
|
|
func ClearOauth(ctx context.Context, user *models.User) {
|
2025-11-13 16:46:30 +00:00
|
|
|
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(),
|
|
|
|
|
)
|
2025-11-24 18:08:24 +00:00
|
|
|
updater.Exec(ctx, db.PGInstance.BobDB)
|
2025-11-13 16:46:30 +00:00
|
|
|
//user.UserNotifications(
|
|
|
|
|
//models.SelectWhere.Notifications.Link.EQ(NotificationPathOauthReset),
|
|
|
|
|
//).UpdateAll()
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 16:07:51 +00:00
|
|
|
func NotifyOauthInvalid(ctx context.Context, user *models.User) {
|
2025-12-02 00:30:46 +00:00
|
|
|
msg := "Oauth token invalidated"
|
2026-02-12 21:06:08 +00:00
|
|
|
_, err := psql.Insert(
|
|
|
|
|
im.Into("notification", "created", "id", "link", "message", "resolved_at", "type", "user_id"),
|
|
|
|
|
im.Values(
|
|
|
|
|
psql.Arg(time.Now()),
|
|
|
|
|
psql.Raw("DEFAULT"),
|
|
|
|
|
psql.Arg(NotificationPathOauthReset),
|
|
|
|
|
psql.Arg(msg),
|
|
|
|
|
psql.Raw("NULL"),
|
|
|
|
|
psql.Arg(enums.NotificationtypeOauthTokenInvalidated),
|
|
|
|
|
psql.Arg(user.ID),
|
|
|
|
|
),
|
|
|
|
|
//im.OnConflict("user_id", "link").DoNothing(),
|
|
|
|
|
//im.OnConflictOnConstraint("unique_user_link_not_resolved").DoNothing(),
|
|
|
|
|
im.OnConflict("user_id", "link").Where("resolved_at IS NULL").DoNothing(),
|
|
|
|
|
).Exec(ctx, db.PGInstance.BobDB)
|
|
|
|
|
/*
|
|
|
|
|
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, ¬ificationSetter)
|
|
|
|
|
*/
|
2025-11-13 16:46:30 +00:00
|
|
|
if err != nil {
|
2026-02-12 21:06:08 +00:00
|
|
|
if strings.Contains(err.Error(), "ERROR: duplicate key value violates unique constraint") {
|
2025-12-02 00:30:46 +00:00
|
|
|
log.Info().Str("msg", msg).Int("user_id", int(user.ID)).Msg("Refusing to add another notification with the same type")
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-01-06 14:46:31 +00:00
|
|
|
debug.LogErrorTypeInfo(err)
|
2025-12-02 00:30:46 +00:00
|
|
|
log.Error().Err(err).Msg("Failed to insert new notification. This is a programmer bug.")
|
2025-11-13 16:46:30 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-12 23:49:16 +00:00
|
|
|
func NotificationsForUser(ctx context.Context, u User) ([]Notification, error) {
|
2025-11-13 16:46:30 +00:00
|
|
|
results := make([]Notification, 0)
|
2026-03-12 23:49:16 +00:00
|
|
|
notifications, err := u.model.UserNotifications(
|
2025-11-13 16:46:30 +00:00
|
|
|
models.SelectWhere.Notifications.ResolvedAt.IsNull(),
|
2025-11-24 18:08:24 +00:00
|
|
|
).All(ctx, db.PGInstance.BobDB)
|
2025-11-13 16:46:30 +00:00
|
|
|
if err != nil {
|
2025-11-13 20:53:20 +00:00
|
|
|
return results, fmt.Errorf("Failed to get notifications: %w", err)
|
2025-11-13 16:46:30 +00:00
|
|
|
}
|
|
|
|
|
for _, n := range notifications {
|
|
|
|
|
results = append(results, Notification{
|
|
|
|
|
Link: n.Link,
|
|
|
|
|
Message: n.Message,
|
|
|
|
|
Time: n.Created,
|
|
|
|
|
Type: notificationTypeName(n.Type),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return results, nil
|
|
|
|
|
}
|
2026-04-02 01:07:55 +00:00
|
|
|
func NotificationCountsForUser(ctx context.Context, u User) (*notificationCounts, error) {
|
2026-03-13 21:22:34 +00:00
|
|
|
count_home, err := u.model.UserNotifications(
|
|
|
|
|
models.SelectWhere.Notifications.ResolvedAt.IsNull(),
|
|
|
|
|
).Count(ctx, db.PGInstance.BobDB)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("Failed to get home notification count: %w", err)
|
|
|
|
|
}
|
2026-03-18 15:36:20 +00:00
|
|
|
count_reports, err := u.Organization.model.Reports(
|
|
|
|
|
models.SelectWhere.PublicreportReports.Reviewed.IsNull(),
|
2026-03-14 16:58:25 +00:00
|
|
|
).Count(ctx, db.PGInstance.BobDB)
|
2026-03-13 21:22:34 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("Failed to get nuisance notification count: %w", err)
|
|
|
|
|
}
|
2026-03-19 16:01:44 +00:00
|
|
|
count_review, err := u.Organization.model.ReviewTasks(
|
|
|
|
|
models.SelectWhere.ReviewTasks.Reviewed.IsNull(),
|
|
|
|
|
).Count(ctx, db.PGInstance.BobDB)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("Failed to get review notification count: %w", err)
|
|
|
|
|
}
|
2026-03-20 16:38:01 +00:00
|
|
|
//log.Debug().Int64("reports", count_reports).Int64("home", count_home).Int64("review", count_review).Int("user", u.ID).Msg("calculated notification counts")
|
2026-04-02 01:07:55 +00:00
|
|
|
return ¬ificationCounts{
|
2026-03-18 15:36:20 +00:00
|
|
|
Communications: uint(count_reports),
|
2026-03-13 21:22:34 +00:00
|
|
|
Home: uint(count_home),
|
2026-03-19 16:01:44 +00:00
|
|
|
Review: uint(count_review),
|
2026-03-13 21:22:34 +00:00
|
|
|
}, nil
|
|
|
|
|
}
|
2025-11-13 16:46:30 +00:00
|
|
|
|
|
|
|
|
func notificationTypeName(t enums.Notificationtype) string {
|
|
|
|
|
switch t {
|
|
|
|
|
case enums.NotificationtypeOauthTokenInvalidated:
|
2026-02-10 16:24:37 +00:00
|
|
|
return "oauth-token-invalid"
|
2025-11-13 16:46:30 +00:00
|
|
|
default:
|
|
|
|
|
return "unknown-type"
|
|
|
|
|
}
|
|
|
|
|
}
|