/* * Amsterdam Web Communities System * Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ // The database package contains database management and storage logic. package database import ( "context" "database/sql" "errors" "sync" "git.erbosoft.com/amy/amsterdam/util" ) // Globals contains the global data. type Globals struct { Mutex sync.Mutex PostsPerPage int32 `db:"posts_per_page"` OldPostsAtTop int32 `db:"old_posts_at_top"` MaxSearchPage int32 `db:"max_search_page"` MaxCommunityMemberPage int32 `db:"max_comm_mbr_page"` MaxConferenceMemberPage int32 `db:"max_conf_mbr_page"` FrontPagePosts int32 `db:"fp_posts"` NumAuditPage int32 `db:"num_audit_page"` CommunityCreateLevel int32 `db:"comm_create_lvl"` flags *util.OptionSet } // GlobalProperties contains global property entries. type GlobalProperties struct { Index int32 `db:"ndx"` Data string `db:"data"` } // Global property indexes defined. const ( GlobalPropFlags = int32(0) ) // Global flag indexes defined. const ( GlobalFlagPicturesInPosts = uint(0) GlobalFlagNoCategories = uint(1) ) // theGlobals contains the singleton instance of Globals. var theGlobals *Globals = nil // globalsMutex controls access to theGlobals. var globalsMutex sync.Mutex // globalProps is the global properties store. var globalProps map[int32]string = make(map[int32]string) // globalPropMutex controls access to globalProps. var globalPropMutex sync.Mutex // Flags returns the global flags. func (g *Globals) Flags(ctx context.Context) (*util.OptionSet, error) { g.Mutex.Lock() defer g.Mutex.Unlock() if g.flags == nil { s, err := AmGetGlobalProperty(ctx, GlobalPropFlags) if err != nil { return nil, err } g.flags = util.OptionSetFromString(s) } return g.flags, nil } // SaveFlags saves off the global flags. func (g *Globals) SaveFlags(ctx context.Context, f *util.OptionSet) error { s := f.AsString() g.Mutex.Lock() defer g.Mutex.Unlock() err := AmSetGlobalProperty(ctx, GlobalPropFlags, s) if err == nil { g.flags = f } return err } // AmGlobals returns trhe pointer to the singleton Globals instance. func AmGlobals(ctx context.Context) (*Globals, error) { globalsMutex.Lock() defer globalsMutex.Unlock() if theGlobals == nil { var dbdata []Globals err := amdb.SelectContext(ctx, &dbdata, "SELECT * FROM globals") if err != nil { return nil, err } if len(dbdata) > 1 { return nil, errors.New("should only be one globals record") } theGlobals = &(dbdata[0]) } return theGlobals, nil } /* AmGetGlobalProperty returns the value of a global property. * Parameters: * ctx - Standard Go context value. * index - The index of the property to retrieve. * Returns: * Value of the property, or empty string. * Standard Go error status. */ func AmGetGlobalProperty(ctx context.Context, index int32) (string, error) { globalPropMutex.Lock() defer globalPropMutex.Unlock() var err error = nil rc, ok := globalProps[index] if !ok { row := amdb.QueryRowContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index) err = row.Scan(&rc) switch err { case nil: globalProps[index] = rc case sql.ErrNoRows: rc = "" err = nil } } return rc, err } /* AmSetGlobalProperty sets the value of a global property. * Parameters: * ctx - Standard Go context value. * index - The index of the property to set. * value - The value of the property to set. * Returns: * Standard Go error status. */ func AmSetGlobalProperty(ctx context.Context, index int32, value string) error { globalPropMutex.Lock() defer globalPropMutex.Unlock() _, updateMode := globalProps[index] if !updateMode { row := amdb.QueryRowContext(ctx, "SELECT data FROM propglobal WHERE ndx = ?", index) var tmpdata string err := row.Scan(&tmpdata) switch err { case nil: updateMode = true case sql.ErrNoRows: updateMode = false default: return err } } var err error = nil if updateMode { _, err = amdb.ExecContext(ctx, "UPDATE propglobal SET data = ? WHERE ndx = ?", value, index) } else { _, err = amdb.ExecContext(ctx, "INSERT INTO propglobal (ndx, data) VALUES (?, ?)", index, value) } if err == nil { globalProps[index] = value } return err }