package main import ( "log" "strings" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/types" ) // isGroupMember checks if a user is a member of a group func isGroupMember(app *pocketbase.PocketBase, groupId string, userId string) (bool, error) { group, err := app.Dao().FindRecordById("groups", groupId) if err != nil { return false, err } members := group.GetStringSlice("members") for _, member := range members { if member == userId { return true, nil } } return false, nil } // isGroupOwner checks if a user is the owner of a group func isGroupOwner(app *pocketbase.PocketBase, groupId string, userId string) (bool, error) { group, err := app.Dao().FindRecordById("groups", groupId) if err != nil { return false, err } return group.GetString("owner") == userId, nil } func main() { app := pocketbase.New() // Groups API Rules app.OnRecordBeforeCreateRequest("groups").Add(func(e *core.RecordCreateEvent) next func() { // Set the owner to the current user e.Record.Set("owner", e.HttpContext.Request().Context().Value("user_id")) // Initialize members array with the owner e.Record.Set("members", []string{e.Record.GetString("owner")}) return next }) app.OnRecordBeforeUpdateRequest("groups").Add(func(e *core.RecordUpdateEvent) next func() { userId := e.HttpContext.Request().Context().Value("user_id").(string) // Only owner can update the group isOwner, err := isGroupOwner(app, e.Record.Id, userId) if err != nil || !isOwner { e.HttpContext.Response().WriteHeader(403) return nil } return next }) app.OnRecordBeforeDeleteRequest("groups").Add(func(e *core.RecordDeleteEvent) next func() { userId := e.HttpContext.Request().Context().Value("user_id").(string) // Only owner can delete the group isOwner, err := isGroupOwner(app, e.Record.Id, userId) if err != nil || !isOwner { e.HttpContext.Response().WriteHeader(403) return nil } return next }) // Team Sessions API Rules app.OnRecordBeforeCreateRequest("team_sessions").Add(func(e *core.RecordCreateEvent) next func() { userId := e.HttpContext.Request().Context().Value("user_id").(string) groupId := e.Record.GetString("group") // Check if user is a member of the group isMember, err := isGroupMember(app, groupId, userId) if err != nil || !isMember { e.HttpContext.Response().WriteHeader(403) return nil } return next }) // Invitations API Rules app.OnRecordBeforeCreateRequest("invitations").Add(func(e *core.RecordCreateEvent) next func() { userId := e.HttpContext.Request().Context().Value("user_id").(string) groupId := e.Record.GetString("group") // Only group owner can create invitations isOwner, err := isGroupOwner(app, groupId, userId) if err != nil || !isOwner { e.HttpContext.Response().WriteHeader(403) return nil } // Set status to pending e.Record.Set("status", "pending") return next }) app.OnRecordAfterCreateRequest("invitations").Add(func(e *core.RecordCreateEvent) next func() { // Send real-time notification to the invited user message := map[string]interface{}{ "action": "invitation", "data": map[string]interface{}{ "id": e.Record.Id, "group": e.Record.GetString("group"), "invited_by": e.Record.GetString("invited_by"), "status": e.Record.GetString("status"), "created": e.Record.Created.Time(), }, } // Broadcast to the invited user's channel if err := app.Realtime().Broadcast("invitations", message); err != nil { log.Printf("Error broadcasting invitation: %v", err) } return next }) // Real-time subscription rules app.OnRecordAfterAuthWithTokenRequest().Add(func(e *core.RecordAuthEvent) next func() { // Subscribe to invitations channel e.HttpContext.Request().Context().Set("realtime_subscriptions", []string{ "invitations", "groups:" + e.Record.Id, "team_sessions", }) return next }) // Custom API endpoint for accepting invitations app.OnServe().Bind(&ServeEvent{ App: app, }) } type ServeEvent struct { App *pocketbase.PocketBase }