Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
package main

import (
	"encoding/json"
	"strings"

	"github.com/pocketbase/dbx"
	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/types"
)

func registerHookPreApprovedEmails(app *pocketbase.PocketBase) {
	app.OnRecordAfterCreateSuccess("users").BindFunc(func(e *core.RecordEvent) error {
		userEmail := strings.ToLower(e.Record.GetString("email"))
		userId := e.Record.Id

		// Find all organizations
		orgs, err := app.FindAllRecords("organizations")
		if err != nil {
			app.Logger().Error("Failed to fetch organizations for pre-approved email check", "error", err)
			return e.Next()
		}

		var firstMatchingOrgId string
		profilesCollection, err := app.FindCollectionByNameOrId("profiles")
		if err != nil {
			app.Logger().Error("Failed to find profiles collection", "error", err)
			return e.Next()
		}

		for _, org := range orgs {
			orgId := org.Id
			variablesRaw := org.Get("variables")
			if variablesRaw == nil {
				continue
			}

			// Parse variables - handle both string and types.JSONRaw
			var variablesBytes []byte
			switch v := variablesRaw.(type) {
			case string:
				variablesBytes = []byte(v)
			case types.JSONRaw:
				variablesBytes = []byte(v)
			default:
				continue
			}

			var variables map[string]interface{}
			if err := json.Unmarshal(variablesBytes, &variables); err != nil {
				continue
			}

			// Check for preApprovedEmails array
			preApprovedRaw, exists := variables["preApprovedEmails"]
			if !exists {
				continue
			}

			preApprovedList, ok := preApprovedRaw.([]interface{})
			if !ok {
				continue
			}

			// Check if user's email is in the pre-approved list (case-insensitive)
			matchIndex := -1
			for i, emailRaw := range preApprovedList {
				email, ok := emailRaw.(string)
				if !ok {
					continue
				}
				if strings.ToLower(email) == userEmail {
					matchIndex = i
					break
				}
			}

			if matchIndex == -1 {
				continue
			}

			// Found a match - find the "tech" role for this org
			techRole, err := app.FindFirstRecordByFilter(
				"roles",
				"org = {:org} && name = {:name}",
				dbx.Params{"org": orgId, "name": "tech"},
			)
			if err != nil {
				app.Logger().Error("Failed to find tech role for org", "orgId", orgId, "error", err)
				continue
			}

			// Create a profile linking user to org with tech role
			profile := core.NewRecord(profilesCollection)
			profile.Set("org", orgId)
			profile.Set("user", userId)
			profile.Set("roles", []string{techRole.Id})

			if err := app.Save(profile); err != nil {
				app.Logger().Error("Failed to create profile for pre-approved user", "userId", userId, "orgId", orgId, "error", err)
				continue
			}

			// Track first matching org for activeOrg
			if firstMatchingOrgId == "" {
				firstMatchingOrgId = orgId
			}

			// Remove email from preApprovedEmails list
			newPreApprovedList := append(preApprovedList[:matchIndex], preApprovedList[matchIndex+1:]...)
			variables["preApprovedEmails"] = newPreApprovedList

			// Save updated variables back to org
			updatedVariablesJson, err := json.Marshal(variables)
			if err != nil {
				app.Logger().Error("Failed to marshal updated variables", "orgId", orgId, "error", err)
				continue
			}

			org.Set("variables", string(updatedVariablesJson))
			if err := app.Save(org); err != nil {
				app.Logger().Error("Failed to save org with updated preApprovedEmails", "orgId", orgId, "error", err)
				continue
			}

			app.Logger().Info("Auto-enrolled pre-approved user", "userId", userId, "email", userEmail, "orgId", orgId)
		}

		// Set user's activeOrg to first matching org
		if firstMatchingOrgId != "" {
			user, err := app.FindRecordById("users", userId)
			if err != nil {
				app.Logger().Error("Failed to find user to set activeOrg", "userId", userId, "error", err)
				return e.Next()
			}

			user.Set("activeOrg", firstMatchingOrgId)
			if err := app.Save(user); err != nil {
				app.Logger().Error("Failed to set activeOrg for user", "userId", userId, "error", err)
			}
		}

		return e.Next()
	})
}