package controllers import ( "net/http" "git.golem15.com/golem15/sm-user-plugin/models" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/bouncer" "git.golem15.com/golem15/summercms/modules/wire" "gorm.io/gorm" ) // OAuthIdentitiesOptions configures host-mounted list/unlink handlers. // Providers defaults to google, facebook, github when nil or empty. // WriteNotFound is injected by the host so 404 bodies match that app. type OAuthIdentitiesOptions struct { Providers []string WriteNotFound func(http.ResponseWriter, *http.Request) } // OAuthIdentitiesIndex lists the caller's linked OAuth providers. func OAuthIdentitiesIndex(app *backpack.App) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { db, user, ok := oauthIdentityDeps(w, r, app) if !ok { return } var rows []models.OAuthIdentity if err := db.WithContext(r.Context()). Where("user_id = ?", user.ID). Order("provider"). Find(&rows).Error; err != nil { writeOpaque500(w) return } data := make([]map[string]any, 0, len(rows)) for i := range rows { item := map[string]any{ "provider": rows[i].Provider, "linked_at": nil, } if rows[i].LinkedAt != nil { item["linked_at"] = &wire.Time{Time: rows[i].LinkedAt.UTC()} } data = append(data, item) } writeJSON(w, http.StatusOK, map[string]any{"data": wire.Slice(data)}) } } func oauthIdentityDeps(w http.ResponseWriter, r *http.Request, app *backpack.App) (*gorm.DB, *bouncer.Principal, bool) { if app == nil { writeOpaque500(w) return nil, nil, false } db, ok := app.Lookup[*gorm.DB]() if !ok || db == nil { writeOpaque500(w) return nil, nil, false } user, ok := bouncer.User(r.Context()) if !ok || user == nil || user.ID == 0 { writeUnauthorized(w) return nil, nil, false } return db, user, true }